|
| 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 | +/* |
| 10 | + * Instead of the generic __SYSCALL_DEFINEx() definition, this macro takes |
| 11 | + * struct pt_regs *regs as the only argument of the syscall stub named |
| 12 | + * sys_*(). It decodes just the registers it needs and passes them on to |
| 13 | + * the SyS_*() wrapper and then to the SYSC_*() function doing the actual job. |
| 14 | + * These wrappers and functions are inlined, meaning that the assembly looks |
| 15 | + * as follows (slightly re-ordered): |
| 16 | + * |
| 17 | + * <sys_recv>: <-- syscall with 4 parameters |
| 18 | + * callq <__fentry__> |
| 19 | + * |
| 20 | + * mov 0x70(%rdi),%rdi <-- decode regs->di |
| 21 | + * mov 0x68(%rdi),%rsi <-- decode regs->si |
| 22 | + * mov 0x60(%rdi),%rdx <-- decode regs->dx |
| 23 | + * mov 0x38(%rdi),%rcx <-- decode regs->r10 |
| 24 | + * |
| 25 | + * xor %r9d,%r9d <-- clear %r9 |
| 26 | + * xor %r8d,%r8d <-- clear %r8 |
| 27 | + * |
| 28 | + * callq __sys_recvfrom <-- do the actual work in __sys_recvfrom() |
| 29 | + * which takes 6 arguments |
| 30 | + * |
| 31 | + * cltq <-- extend return value to 64-bit |
| 32 | + * retq <-- return |
| 33 | + * |
| 34 | + * This approach avoids leaking random user-provided register content down |
| 35 | + * the call chain. |
| 36 | + * |
| 37 | + * As the generic SYSCALL_DEFINE0() macro does not decode any parameters for |
| 38 | + * obvious reasons, and passing struct pt_regs *regs to it in %rdi does not |
| 39 | + * hurt, there is no need to override it. |
| 40 | + */ |
| 41 | +#define __SYSCALL_DEFINEx(x, name, ...) \ |
| 42 | + asmlinkage long sys##name(const struct pt_regs *regs); \ |
| 43 | + ALLOW_ERROR_INJECTION(sys##name, ERRNO); \ |
| 44 | + static long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \ |
| 45 | + static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__)); \ |
| 46 | + asmlinkage long sys##name(const struct pt_regs *regs) \ |
| 47 | + { \ |
| 48 | + return SyS##name(__MAP(x,__SC_ARGS \ |
| 49 | + ,,regs->di,,regs->si,,regs->dx \ |
| 50 | + ,,regs->r10,,regs->r8,,regs->r9)); \ |
| 51 | + } \ |
| 52 | + static long SyS##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \ |
| 53 | + { \ |
| 54 | + long ret = SYSC##name(__MAP(x,__SC_CAST,__VA_ARGS__)); \ |
| 55 | + __MAP(x,__SC_TEST,__VA_ARGS__); \ |
| 56 | + __PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__)); \ |
| 57 | + return ret; \ |
| 58 | + } \ |
| 59 | + static inline long SYSC##name(__MAP(x,__SC_DECL,__VA_ARGS__)) |
| 60 | + |
| 61 | +/* |
| 62 | + * For VSYSCALLS, we need to declare these three syscalls with the new |
| 63 | + * pt_regs-based calling convention for in-kernel use. |
| 64 | + */ |
| 65 | +struct pt_regs; |
| 66 | +asmlinkage long sys_getcpu(const struct pt_regs *regs); /* di,si,dx */ |
| 67 | +asmlinkage long sys_gettimeofday(const struct pt_regs *regs); /* di,si */ |
| 68 | +asmlinkage long sys_time(const struct pt_regs *regs); /* di */ |
| 69 | + |
| 70 | +#endif /* _ASM_X86_SYSCALL_WRAPPER_H */ |
0 commit comments