On Thu, Jan 03, 2019 at 06:13:58PM +0000, Will Deacon wrote: > The ARM Linux kernel handles the EABI syscall numbers as follows: > > 0 - NR_SYSCALLS-1 : Invoke syscall via syscall table > NR_SYSCALLS - 0xeffff : -ENOSYS (to be allocated in future) > 0xf0000 - 0xf07ff : Private syscall or -ENOSYS if not allocated > > 0xf07ff : SIGILL > > Our compat code gets this wrong and ends up sending SIGILL in response > to all syscalls greater than NR_SYSCALLS which have a value greater > than 0x7ff in the bottom 16 bits. > > Fix this by defining the end of the ARM private syscall region and > checking the syscall number against that directly. Update the comment > while we're at it. > > Cc: <stable@xxxxxxxxxxxxxxx> > Cc: Dave Martin <Dave.Martin@xxxxxxx> > Reported-by: Pi-Hsun Shih <pihsun@xxxxxxxxxxxx> > Signed-off-by: Will Deacon <will.deacon@xxxxxxx> > --- > arch/arm64/include/asm/unistd.h | 5 +++-- > arch/arm64/kernel/sys_compat.c | 4 ++-- > 2 files changed, 5 insertions(+), 4 deletions(-) > > diff --git a/arch/arm64/include/asm/unistd.h b/arch/arm64/include/asm/unistd.h > index b13ca091f833..be66a54ee3a1 100644 > --- a/arch/arm64/include/asm/unistd.h > +++ b/arch/arm64/include/asm/unistd.h > @@ -40,8 +40,9 @@ > * The following SVCs are ARM private. > */ > #define __ARM_NR_COMPAT_BASE 0x0f0000 > -#define __ARM_NR_compat_cacheflush (__ARM_NR_COMPAT_BASE+2) > -#define __ARM_NR_compat_set_tls (__ARM_NR_COMPAT_BASE+5) > +#define __ARM_NR_compat_cacheflush (__ARM_NR_COMPAT_BASE + 2) > +#define __ARM_NR_compat_set_tls (__ARM_NR_COMPAT_BASE + 5) > +#define __ARM_NR_compat_syscall_end (__ARM_NR_COMPAT_BASE + 0x800) Nit: there is no compat_syscall_end(). Can we make this #define upper case, like __ARM_NR_COMPAT_BASE, since a symbolic bound, not a syscall number? It would be nice to have this for arch/arm too rather than the current magic numbers. > #define __NR_compat_syscalls 399 > #endif > diff --git a/arch/arm64/kernel/sys_compat.c b/arch/arm64/kernel/sys_compat.c > index 32653d156747..5972b7533fa0 100644 > --- a/arch/arm64/kernel/sys_compat.c > +++ b/arch/arm64/kernel/sys_compat.c > @@ -102,12 +102,12 @@ long compat_arm_syscall(struct pt_regs *regs) > > default: > /* > - * Calls 9f00xx..9f07ff are defined to return -ENOSYS > + * Calls 0xf0xxx..0xf07ff are defined to return -ENOSYS > * if not implemented, rather than raising SIGILL. This > * way the calling program can gracefully determine whether > * a feature is supported. > */ > - if ((no & 0xffff) <= 0x7ff) > + if (no < __ARM_NR_compat_syscall_end) arm_syscall() in arch/arm is not responsible for handling syscalls less __ARM_NR_BASE; the code in entry-common.S redirects those directly to sys_ni_syscall() instead. Given how fiddly this is I think it's preferable if we keep to the arch/arm code structure as much as possible, and call this function only when no >= __ARM_NR_COMPAT_BASE? Regular (possibly unallocated) Linux syscalls can be more naturally handled in do_ni_syscall() instead IMHO, mirroring the entry-common.S code that it replaces. Cheers ---Dave