x86/entry: Use int everywhere for system call numbers
authorH. Peter Anvin (Intel) <hpa@zytor.com>
Tue, 18 May 2021 19:13:03 +0000 (12:13 -0700)
committerThomas Gleixner <tglx@linutronix.de>
Tue, 25 May 2021 08:07:00 +0000 (10:07 +0200)
System call numbers are defined as int, so use int everywhere for system
call numbers. This is strictly a cleanup; it should not change anything
user visible; all ABI changes have been done in the preceeding patches.

[ tglx: Replaced the unsigned long cast ]

Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://lore.kernel.org/r/20210518191303.4135296-7-hpa@zytor.com
arch/x86/entry/common.c
arch/x86/include/asm/syscall.h

index f51bc17..ee95fe3 100644 (file)
 #include <asm/irq_stack.h>
 
 #ifdef CONFIG_X86_64
-__visible noinstr void do_syscall_64(struct pt_regs *regs, unsigned long nr)
+
+static __always_inline bool do_syscall_x64(struct pt_regs *regs, int nr)
+{
+       /*
+        * Convert negative numbers to very high and thus out of range
+        * numbers for comparisons.
+        */
+       unsigned int unr = nr;
+
+       if (likely(unr < NR_syscalls)) {
+               unr = array_index_nospec(unr, NR_syscalls);
+               regs->ax = sys_call_table[unr](regs);
+               return true;
+       }
+       return false;
+}
+
+static __always_inline bool do_syscall_x32(struct pt_regs *regs, int nr)
+{
+       /*
+        * Adjust the starting offset of the table, and convert numbers
+        * < __X32_SYSCALL_BIT to very high and thus out of range
+        * numbers for comparisons.
+        */
+       unsigned int xnr = nr - __X32_SYSCALL_BIT;
+
+       if (IS_ENABLED(CONFIG_X86_X32_ABI) && likely(xnr < X32_NR_syscalls)) {
+               xnr = array_index_nospec(xnr, X32_NR_syscalls);
+               regs->ax = x32_sys_call_table[xnr](regs);
+               return true;
+       }
+       return false;
+}
+
+__visible noinstr void do_syscall_64(struct pt_regs *regs, int nr)
 {
        add_random_kstack_offset();
        nr = syscall_enter_from_user_mode(regs, nr);
 
        instrumentation_begin();
-       if (likely(nr < NR_syscalls)) {
-               nr = array_index_nospec(nr, NR_syscalls);
-               regs->ax = sys_call_table[nr](regs);
-#ifdef CONFIG_X86_X32_ABI
-       } else if (likely((nr & __X32_SYSCALL_BIT) &&
-                         (nr & ~__X32_SYSCALL_BIT) < X32_NR_syscalls)) {
-               nr = array_index_nospec(nr & ~__X32_SYSCALL_BIT,
-                                       X32_NR_syscalls);
-               regs->ax = x32_sys_call_table[nr](regs);
-#endif
-       } else if (unlikely((int)nr != -1)) {
+
+       if (!do_syscall_x64(regs, nr) && !do_syscall_x32(regs, nr) && nr != -1) {
+               /* Invalid system call, but still a system call. */
                regs->ax = __x64_sys_ni_syscall(regs);
        }
+
        instrumentation_end();
        syscall_exit_to_user_mode(regs);
 }
 #endif
 
 #if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION)
-static __always_inline unsigned int syscall_32_enter(struct pt_regs *regs)
+static __always_inline int syscall_32_enter(struct pt_regs *regs)
 {
        if (IS_ENABLED(CONFIG_IA32_EMULATION))
                current_thread_info()->status |= TS_COMPAT;
 
-       return (unsigned int)regs->orig_ax;
+       return (int)regs->orig_ax;
 }
 
 /*
  * Invoke a 32-bit syscall.  Called with IRQs on in CONTEXT_KERNEL.
  */
-static __always_inline void do_syscall_32_irqs_on(struct pt_regs *regs,
-                                                 unsigned int nr)
+static __always_inline void do_syscall_32_irqs_on(struct pt_regs *regs, int nr)
 {
-       if (likely(nr < IA32_NR_syscalls)) {
-               nr = array_index_nospec(nr, IA32_NR_syscalls);
-               regs->ax = ia32_sys_call_table[nr](regs);
-       } else if (unlikely((int)nr != -1)) {
+       /*
+        * Convert negative numbers to very high and thus out of range
+        * numbers for comparisons.
+        */
+       unsigned int unr = nr;
+
+       if (likely(unr < IA32_NR_syscalls)) {
+               unr = array_index_nospec(unr, IA32_NR_syscalls);
+               regs->ax = ia32_sys_call_table[unr](regs);
+       } else if (nr != -1) {
                regs->ax = __ia32_sys_ni_syscall(regs);
        }
 }
@@ -86,15 +118,15 @@ static __always_inline void do_syscall_32_irqs_on(struct pt_regs *regs,
 /* Handles int $0x80 */
 __visible noinstr void do_int80_syscall_32(struct pt_regs *regs)
 {
-       unsigned int nr = syscall_32_enter(regs);
+       int nr = syscall_32_enter(regs);
 
        add_random_kstack_offset();
        /*
-        * Subtlety here: if ptrace pokes something larger than 2^32-1 into
-        * orig_ax, the unsigned int return value truncates it.  This may
-        * or may not be necessary, but it matches the old asm behavior.
+        * Subtlety here: if ptrace pokes something larger than 2^31-1 into
+        * orig_ax, the int return value truncates it. This matches
+        * the semantics of syscall_get_nr().
         */
-       nr = (unsigned int)syscall_enter_from_user_mode(regs, nr);
+       nr = syscall_enter_from_user_mode(regs, nr);
        instrumentation_begin();
 
        do_syscall_32_irqs_on(regs, nr);
@@ -105,7 +137,7 @@ __visible noinstr void do_int80_syscall_32(struct pt_regs *regs)
 
 static noinstr bool __do_fast_syscall_32(struct pt_regs *regs)
 {
-       unsigned int nr = syscall_32_enter(regs);
+       int nr = syscall_32_enter(regs);
        int res;
 
        add_random_kstack_offset();
@@ -140,8 +172,7 @@ static noinstr bool __do_fast_syscall_32(struct pt_regs *regs)
                return false;
        }
 
-       /* The case truncates any ptrace induced syscall nr > 2^32 -1 */
-       nr = (unsigned int)syscall_enter_from_user_mode_work(regs, nr);
+       nr = syscall_enter_from_user_mode_work(regs, nr);
 
        /* Now this is just like a normal syscall. */
        do_syscall_32_irqs_on(regs, nr);
index f6593ca..f7e2d82 100644 (file)
@@ -159,7 +159,7 @@ static inline int syscall_get_arch(struct task_struct *task)
                ? AUDIT_ARCH_I386 : AUDIT_ARCH_X86_64;
 }
 
-void do_syscall_64(struct pt_regs *regs, unsigned long nr);
+void do_syscall_64(struct pt_regs *regs, int nr);
 void do_int80_syscall_32(struct pt_regs *regs);
 long do_fast_syscall_32(struct pt_regs *regs);