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