36
36
#include <asm/irq_stack.h>
37
37
38
38
#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 )
40
74
{
41
75
add_random_kstack_offset ();
42
76
nr = syscall_enter_from_user_mode (regs , nr );
43
77
44
78
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. */
56
82
regs -> ax = __x64_sys_ni_syscall (regs );
57
83
}
84
+
58
85
instrumentation_end ();
59
86
syscall_exit_to_user_mode (regs );
60
87
}
61
88
#endif
62
89
63
90
#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 )
65
92
{
66
93
if (IS_ENABLED (CONFIG_IA32_EMULATION ))
67
94
current_thread_info ()-> status |= TS_COMPAT ;
68
95
69
- return (unsigned int )regs -> orig_ax ;
96
+ return (int )regs -> orig_ax ;
70
97
}
71
98
72
99
/*
73
100
* Invoke a 32-bit syscall. Called with IRQs on in CONTEXT_KERNEL.
74
101
*/
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 )
77
103
{
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 ) {
82
114
regs -> ax = __ia32_sys_ni_syscall (regs );
83
115
}
84
116
}
85
117
86
118
/* Handles int $0x80 */
87
119
__visible noinstr void do_int80_syscall_32 (struct pt_regs * regs )
88
120
{
89
- unsigned int nr = syscall_32_enter (regs );
121
+ int nr = syscall_32_enter (regs );
90
122
91
123
add_random_kstack_offset ();
92
124
/*
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() .
96
128
*/
97
- nr = ( unsigned int ) syscall_enter_from_user_mode (regs , nr );
129
+ nr = syscall_enter_from_user_mode (regs , nr );
98
130
instrumentation_begin ();
99
131
100
132
do_syscall_32_irqs_on (regs , nr );
@@ -105,7 +137,7 @@ __visible noinstr void do_int80_syscall_32(struct pt_regs *regs)
105
137
106
138
static noinstr bool __do_fast_syscall_32 (struct pt_regs * regs )
107
139
{
108
- unsigned int nr = syscall_32_enter (regs );
140
+ int nr = syscall_32_enter (regs );
109
141
int res ;
110
142
111
143
add_random_kstack_offset ();
@@ -140,8 +172,7 @@ static noinstr bool __do_fast_syscall_32(struct pt_regs *regs)
140
172
return false;
141
173
}
142
174
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 );
145
176
146
177
/* Now this is just like a normal syscall. */
147
178
do_syscall_32_irqs_on (regs , nr );
0 commit comments