Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 | /* SPDX-License-Identifier: GPL-2.0 */ /* * syscall_wrapper.h - x86 specific wrappers to syscall definitions */ #ifndef _ASM_X86_SYSCALL_WRAPPER_H #define _ASM_X86_SYSCALL_WRAPPER_H struct pt_regs; /* Mapping of registers to parameters for syscalls on x86-64 and x32 */ #define SC_X86_64_REGS_TO_ARGS(x, ...) \ __MAP(x,__SC_ARGS \ ,,regs->di,,regs->si,,regs->dx \ ,,regs->r10,,regs->r8,,regs->r9) \ /* Mapping of registers to parameters for syscalls on i386 */ #define SC_IA32_REGS_TO_ARGS(x, ...) \ __MAP(x,__SC_ARGS \ ,,(unsigned int)regs->bx,,(unsigned int)regs->cx \ ,,(unsigned int)regs->dx,,(unsigned int)regs->si \ ,,(unsigned int)regs->di,,(unsigned int)regs->bp) #ifdef CONFIG_IA32_EMULATION /* * For IA32 emulation, we need to handle "compat" syscalls *and* create * additional wrappers (aptly named __ia32_sys_xyzzy) which decode the * ia32 regs in the proper order for shared or "common" syscalls. As some * syscalls may not be implemented, we need to expand COND_SYSCALL in * kernel/sys_ni.c and SYS_NI in kernel/time/posix-stubs.c to cover this * case as well. */ #define __IA32_COMPAT_SYS_STUB0(x, name) \ asmlinkage long __ia32_compat_sys_##name(const struct pt_regs *regs);\ ALLOW_ERROR_INJECTION(__ia32_compat_sys_##name, ERRNO); \ asmlinkage long __ia32_compat_sys_##name(const struct pt_regs *regs)\ { \ return __se_compat_sys_##name(); \ } #define __IA32_COMPAT_SYS_STUBx(x, name, ...) \ asmlinkage long __ia32_compat_sys##name(const struct pt_regs *regs);\ ALLOW_ERROR_INJECTION(__ia32_compat_sys##name, ERRNO); \ asmlinkage long __ia32_compat_sys##name(const struct pt_regs *regs)\ { \ return __se_compat_sys##name(SC_IA32_REGS_TO_ARGS(x,__VA_ARGS__));\ } #define __IA32_SYS_STUBx(x, name, ...) \ asmlinkage long __ia32_sys##name(const struct pt_regs *regs); \ ALLOW_ERROR_INJECTION(__ia32_sys##name, ERRNO); \ asmlinkage long __ia32_sys##name(const struct pt_regs *regs) \ { \ return __se_sys##name(SC_IA32_REGS_TO_ARGS(x,__VA_ARGS__));\ } /* * To keep the naming coherent, re-define SYSCALL_DEFINE0 to create an alias * named __ia32_sys_*() */ #define SYSCALL_DEFINE0(sname) \ SYSCALL_METADATA(_##sname, 0); \ asmlinkage long __x64_sys_##sname(const struct pt_regs *__unused);\ ALLOW_ERROR_INJECTION(__x64_sys_##sname, ERRNO); \ SYSCALL_ALIAS(__ia32_sys_##sname, __x64_sys_##sname); \ asmlinkage long __x64_sys_##sname(const struct pt_regs *__unused) #define COND_SYSCALL(name) \ asmlinkage __weak long __x64_sys_##name(const struct pt_regs *__unused) \ { \ return sys_ni_syscall(); \ } \ asmlinkage __weak long __ia32_sys_##name(const struct pt_regs *__unused)\ { \ return sys_ni_syscall(); \ } #define SYS_NI(name) \ SYSCALL_ALIAS(__x64_sys_##name, sys_ni_posix_timers); \ SYSCALL_ALIAS(__ia32_sys_##name, sys_ni_posix_timers) #else /* CONFIG_IA32_EMULATION */ #define __IA32_COMPAT_SYS_STUBx(x, name, ...) #define __IA32_SYS_STUBx(x, fullname, name, ...) #endif /* CONFIG_IA32_EMULATION */ #ifdef CONFIG_X86_X32 /* * For the x32 ABI, we need to create a stub for compat_sys_*() which is aware * of the x86-64-style parameter ordering of x32 syscalls. The syscalls common * with x86_64 obviously do not need such care. */ #define __X32_COMPAT_SYS_STUB0(x, name, ...) \ asmlinkage long __x32_compat_sys_##name(const struct pt_regs *regs);\ ALLOW_ERROR_INJECTION(__x32_compat_sys_##name, ERRNO); \ asmlinkage long __x32_compat_sys_##name(const struct pt_regs *regs)\ { \ return __se_compat_sys_##name();\ } #define __X32_COMPAT_SYS_STUBx(x, name, ...) \ asmlinkage long __x32_compat_sys##name(const struct pt_regs *regs);\ ALLOW_ERROR_INJECTION(__x32_compat_sys##name, ERRNO); \ asmlinkage long __x32_compat_sys##name(const struct pt_regs *regs)\ { \ return __se_compat_sys##name(SC_X86_64_REGS_TO_ARGS(x,__VA_ARGS__));\ } #else /* CONFIG_X86_X32 */ #define __X32_COMPAT_SYS_STUB0(x, name) #define __X32_COMPAT_SYS_STUBx(x, name, ...) #endif /* CONFIG_X86_X32 */ #ifdef CONFIG_COMPAT /* * Compat means IA32_EMULATION and/or X86_X32. As they use a different * mapping of registers to parameters, we need to generate stubs for each * of them. */ #define COMPAT_SYSCALL_DEFINE0(name) \ static long __se_compat_sys_##name(void); \ static inline long __do_compat_sys_##name(void); \ __IA32_COMPAT_SYS_STUB0(x, name) \ __X32_COMPAT_SYS_STUB0(x, name) \ static long __se_compat_sys_##name(void) \ { \ return __do_compat_sys_##name(); \ } \ static inline long __do_compat_sys_##name(void) #define COMPAT_SYSCALL_DEFINEx(x, name, ...) \ static long __se_compat_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \ static inline long __do_compat_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));\ __IA32_COMPAT_SYS_STUBx(x, name, __VA_ARGS__) \ __X32_COMPAT_SYS_STUBx(x, name, __VA_ARGS__) \ static long __se_compat_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \ { \ return __do_compat_sys##name(__MAP(x,__SC_DELOUSE,__VA_ARGS__));\ } \ static inline long __do_compat_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) /* * As some compat syscalls may not be implemented, we need to expand * COND_SYSCALL_COMPAT in kernel/sys_ni.c and COMPAT_SYS_NI in * kernel/time/posix-stubs.c to cover this case as well. */ #define COND_SYSCALL_COMPAT(name) \ cond_syscall(__ia32_compat_sys_##name); \ cond_syscall(__x32_compat_sys_##name) #define COMPAT_SYS_NI(name) \ SYSCALL_ALIAS(__ia32_compat_sys_##name, sys_ni_posix_timers); \ SYSCALL_ALIAS(__x32_compat_sys_##name, sys_ni_posix_timers) #endif /* CONFIG_COMPAT */ /* * Instead of the generic __SYSCALL_DEFINEx() definition, this macro takes * struct pt_regs *regs as the only argument of the syscall stub named * __x64_sys_*(). It decodes just the registers it needs and passes them on to * the __se_sys_*() wrapper performing sign extension and then to the * __do_sys_*() function doing the actual job. These wrappers and functions * are inlined (at least in very most cases), meaning that the assembly looks * as follows (slightly re-ordered for better readability): * * <__x64_sys_recv>: <-- syscall with 4 parameters * callq <__fentry__> * * mov 0x70(%rdi),%rdi <-- decode regs->di * mov 0x68(%rdi),%rsi <-- decode regs->si * mov 0x60(%rdi),%rdx <-- decode regs->dx * mov 0x38(%rdi),%rcx <-- decode regs->r10 * * xor %r9d,%r9d <-- clear %r9 * xor %r8d,%r8d <-- clear %r8 * * callq __sys_recvfrom <-- do the actual work in __sys_recvfrom() * which takes 6 arguments * * cltq <-- extend return value to 64-bit * retq <-- return * * This approach avoids leaking random user-provided register content down * the call chain. * * If IA32_EMULATION is enabled, this macro generates an additional wrapper * named __ia32_sys_*() which decodes the struct pt_regs *regs according * to the i386 calling convention (bx, cx, dx, si, di, bp). */ #define __SYSCALL_DEFINEx(x, name, ...) \ asmlinkage long __x64_sys##name(const struct pt_regs *regs); \ ALLOW_ERROR_INJECTION(__x64_sys##name, ERRNO); \ static long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \ static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));\ asmlinkage long __x64_sys##name(const struct pt_regs *regs) \ { \ return __se_sys##name(SC_X86_64_REGS_TO_ARGS(x,__VA_ARGS__));\ } \ __IA32_SYS_STUBx(x, name, __VA_ARGS__) \ static long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \ { \ long ret = __do_sys##name(__MAP(x,__SC_CAST,__VA_ARGS__));\ __MAP(x,__SC_TEST,__VA_ARGS__); \ __PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__)); \ return ret; \ } \ static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) /* * As the generic SYSCALL_DEFINE0() macro does not decode any parameters for * obvious reasons, and passing struct pt_regs *regs to it in %rdi does not * hurt, we only need to re-define it here to keep the naming congruent to * SYSCALL_DEFINEx() -- which is essential for the COND_SYSCALL() and SYS_NI() * macros to work correctly. */ #ifndef SYSCALL_DEFINE0 #define SYSCALL_DEFINE0(sname) \ SYSCALL_METADATA(_##sname, 0); \ asmlinkage long __x64_sys_##sname(const struct pt_regs *__unused);\ ALLOW_ERROR_INJECTION(__x64_sys_##sname, ERRNO); \ asmlinkage long __x64_sys_##sname(const struct pt_regs *__unused) #endif #ifndef COND_SYSCALL #define COND_SYSCALL(name) \ asmlinkage __weak long __x64_sys_##name(const struct pt_regs *__unused) \ { \ return sys_ni_syscall(); \ } #endif #ifndef SYS_NI #define SYS_NI(name) SYSCALL_ALIAS(__x64_sys_##name, sys_ni_posix_timers); #endif /* * For VSYSCALLS, we need to declare these three syscalls with the new * pt_regs-based calling convention for in-kernel use. */ asmlinkage long __x64_sys_getcpu(const struct pt_regs *regs); asmlinkage long __x64_sys_gettimeofday(const struct pt_regs *regs); asmlinkage long __x64_sys_time(const struct pt_regs *regs); #endif /* _ASM_X86_SYSCALL_WRAPPER_H */ |