3636#include <asm/irq_stack.h>
3737
3838#ifdef CONFIG_X86_64
39- __visible noinstr void do_syscall_64 (struct pt_regs * regs , unsigned long nr )
39+
40+ static __always_inline bool do_syscall_x64 (struct pt_regs * regs , int nr )
41+ {
42+ /*
43+ * Convert negative numbers to very high and thus out of range
44+ * numbers for comparisons.
45+ */
46+ unsigned int unr = nr ;
47+
48+ if (likely (unr < NR_syscalls )) {
49+ unr = array_index_nospec (unr , NR_syscalls );
50+ regs -> ax = sys_call_table [unr ](regs );
51+ return true;
52+ }
53+ return false;
54+ }
55+
56+ static __always_inline bool do_syscall_x32 (struct pt_regs * regs , int nr )
57+ {
58+ /*
59+ * Adjust the starting offset of the table, and convert numbers
60+ * < __X32_SYSCALL_BIT to very high and thus out of range
61+ * numbers for comparisons.
62+ */
63+ unsigned int xnr = nr - __X32_SYSCALL_BIT ;
64+
65+ if (IS_ENABLED (CONFIG_X86_X32_ABI ) && likely (xnr < X32_NR_syscalls )) {
66+ xnr = array_index_nospec (xnr , X32_NR_syscalls );
67+ regs -> ax = x32_sys_call_table [xnr ](regs );
68+ return true;
69+ }
70+ return false;
71+ }
72+
73+ __visible noinstr void do_syscall_64 (struct pt_regs * regs , int nr )
4074{
4175 add_random_kstack_offset ();
4276 nr = syscall_enter_from_user_mode (regs , nr );
4377
4478 instrumentation_begin ();
45- if (likely (nr < NR_syscalls )) {
46- nr = array_index_nospec (nr , NR_syscalls );
47- regs -> ax = sys_call_table [nr ](regs );
48- #ifdef CONFIG_X86_X32_ABI
49- } else if (likely ((nr & __X32_SYSCALL_BIT ) &&
50- (nr & ~__X32_SYSCALL_BIT ) < X32_NR_syscalls )) {
51- nr = array_index_nospec (nr & ~__X32_SYSCALL_BIT ,
52- X32_NR_syscalls );
53- regs -> ax = x32_sys_call_table [nr ](regs );
54- #endif
55- } else if (unlikely ((int )nr != -1 )) {
79+
80+ if (!do_syscall_x64 (regs , nr ) && !do_syscall_x32 (regs , nr ) && nr != -1 ) {
81+ /* Invalid system call, but still a system call. */
5682 regs -> ax = __x64_sys_ni_syscall (regs );
5783 }
84+
5885 instrumentation_end ();
5986 syscall_exit_to_user_mode (regs );
6087}
6188#endif
6289
6390#if defined(CONFIG_X86_32 ) || defined(CONFIG_IA32_EMULATION )
64- static __always_inline unsigned int syscall_32_enter (struct pt_regs * regs )
91+ static __always_inline int syscall_32_enter (struct pt_regs * regs )
6592{
6693 if (IS_ENABLED (CONFIG_IA32_EMULATION ))
6794 current_thread_info ()-> status |= TS_COMPAT ;
6895
69- return (unsigned int )regs -> orig_ax ;
96+ return (int )regs -> orig_ax ;
7097}
7198
7299/*
73100 * Invoke a 32-bit syscall. Called with IRQs on in CONTEXT_KERNEL.
74101 */
75- static __always_inline void do_syscall_32_irqs_on (struct pt_regs * regs ,
76- unsigned int nr )
102+ static __always_inline void do_syscall_32_irqs_on (struct pt_regs * regs , int nr )
77103{
78- if (likely (nr < IA32_NR_syscalls )) {
79- nr = array_index_nospec (nr , IA32_NR_syscalls );
80- regs -> ax = ia32_sys_call_table [nr ](regs );
81- } else if (unlikely ((int )nr != -1 )) {
104+ /*
105+ * Convert negative numbers to very high and thus out of range
106+ * numbers for comparisons.
107+ */
108+ unsigned int unr = nr ;
109+
110+ if (likely (unr < IA32_NR_syscalls )) {
111+ unr = array_index_nospec (unr , IA32_NR_syscalls );
112+ regs -> ax = ia32_sys_call_table [unr ](regs );
113+ } else if (nr != -1 ) {
82114 regs -> ax = __ia32_sys_ni_syscall (regs );
83115 }
84116}
85117
86118/* Handles int $0x80 */
87119__visible noinstr void do_int80_syscall_32 (struct pt_regs * regs )
88120{
89- unsigned int nr = syscall_32_enter (regs );
121+ int nr = syscall_32_enter (regs );
90122
91123 add_random_kstack_offset ();
92124 /*
93- * Subtlety here: if ptrace pokes something larger than 2^32 -1 into
94- * orig_ax, the unsigned int return value truncates it. This may
95- * or may not be necessary, but it matches the old asm behavior .
125+ * Subtlety here: if ptrace pokes something larger than 2^31 -1 into
126+ * orig_ax, the int return value truncates it. This matches
127+ * the semantics of syscall_get_nr() .
96128 */
97- nr = ( unsigned int ) syscall_enter_from_user_mode (regs , nr );
129+ nr = syscall_enter_from_user_mode (regs , nr );
98130 instrumentation_begin ();
99131
100132 do_syscall_32_irqs_on (regs , nr );
@@ -105,7 +137,7 @@ __visible noinstr void do_int80_syscall_32(struct pt_regs *regs)
105137
106138static noinstr bool __do_fast_syscall_32 (struct pt_regs * regs )
107139{
108- unsigned int nr = syscall_32_enter (regs );
140+ int nr = syscall_32_enter (regs );
109141 int res ;
110142
111143 add_random_kstack_offset ();
@@ -140,8 +172,7 @@ static noinstr bool __do_fast_syscall_32(struct pt_regs *regs)
140172 return false;
141173 }
142174
143- /* The case truncates any ptrace induced syscall nr > 2^32 -1 */
144- nr = (unsigned int )syscall_enter_from_user_mode_work (regs , nr );
175+ nr = syscall_enter_from_user_mode_work (regs , nr );
145176
146177 /* Now this is just like a normal syscall. */
147178 do_syscall_32_irqs_on (regs , nr );
0 commit comments