cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

syscall_wrapper.h (9348B)


      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
      9struct pt_regs;
     10
     11extern long __x64_sys_ni_syscall(const struct pt_regs *regs);
     12extern long __ia32_sys_ni_syscall(const struct pt_regs *regs);
     13
     14/*
     15 * Instead of the generic __SYSCALL_DEFINEx() definition, the x86 version takes
     16 * struct pt_regs *regs as the only argument of the syscall stub(s) named as:
     17 * __x64_sys_*()         - 64-bit native syscall
     18 * __ia32_sys_*()        - 32-bit native syscall or common compat syscall
     19 * __ia32_compat_sys_*() - 32-bit compat syscall
     20 * __x64_compat_sys_*()  - 64-bit X32 compat syscall
     21 *
     22 * The registers are decoded according to the ABI:
     23 * 64-bit: RDI, RSI, RDX, R10, R8, R9
     24 * 32-bit: EBX, ECX, EDX, ESI, EDI, EBP
     25 *
     26 * The stub then passes the decoded arguments to the __se_sys_*() wrapper to
     27 * perform sign-extension (omitted for zero-argument syscalls).  Finally the
     28 * arguments are passed to the __do_sys_*() function which is the actual
     29 * syscall.  These wrappers are marked as inline so the compiler can optimize
     30 * the functions where appropriate.
     31 *
     32 * Example assembly (slightly re-ordered for better readability):
     33 *
     34 * <__x64_sys_recv>:		<-- syscall with 4 parameters
     35 *	callq	<__fentry__>
     36 *
     37 *	mov	0x70(%rdi),%rdi	<-- decode regs->di
     38 *	mov	0x68(%rdi),%rsi	<-- decode regs->si
     39 *	mov	0x60(%rdi),%rdx	<-- decode regs->dx
     40 *	mov	0x38(%rdi),%rcx	<-- decode regs->r10
     41 *
     42 *	xor	%r9d,%r9d	<-- clear %r9
     43 *	xor	%r8d,%r8d	<-- clear %r8
     44 *
     45 *	callq	__sys_recvfrom	<-- do the actual work in __sys_recvfrom()
     46 *				    which takes 6 arguments
     47 *
     48 *	cltq			<-- extend return value to 64-bit
     49 *	retq			<-- return
     50 *
     51 * This approach avoids leaking random user-provided register content down
     52 * the call chain.
     53 */
     54
     55/* Mapping of registers to parameters for syscalls on x86-64 and x32 */
     56#define SC_X86_64_REGS_TO_ARGS(x, ...)					\
     57	__MAP(x,__SC_ARGS						\
     58		,,regs->di,,regs->si,,regs->dx				\
     59		,,regs->r10,,regs->r8,,regs->r9)			\
     60
     61/* Mapping of registers to parameters for syscalls on i386 */
     62#define SC_IA32_REGS_TO_ARGS(x, ...)					\
     63	__MAP(x,__SC_ARGS						\
     64	      ,,(unsigned int)regs->bx,,(unsigned int)regs->cx		\
     65	      ,,(unsigned int)regs->dx,,(unsigned int)regs->si		\
     66	      ,,(unsigned int)regs->di,,(unsigned int)regs->bp)
     67
     68#define __SYS_STUB0(abi, name)						\
     69	long __##abi##_##name(const struct pt_regs *regs);		\
     70	ALLOW_ERROR_INJECTION(__##abi##_##name, ERRNO);			\
     71	long __##abi##_##name(const struct pt_regs *regs)		\
     72		__alias(__do_##name);
     73
     74#define __SYS_STUBx(abi, name, ...)					\
     75	long __##abi##_##name(const struct pt_regs *regs);		\
     76	ALLOW_ERROR_INJECTION(__##abi##_##name, ERRNO);			\
     77	long __##abi##_##name(const struct pt_regs *regs)		\
     78	{								\
     79		return __se_##name(__VA_ARGS__);			\
     80	}
     81
     82#define __COND_SYSCALL(abi, name)					\
     83	__weak long __##abi##_##name(const struct pt_regs *__unused);	\
     84	__weak long __##abi##_##name(const struct pt_regs *__unused)	\
     85	{								\
     86		return sys_ni_syscall();				\
     87	}
     88
     89#define __SYS_NI(abi, name)						\
     90	SYSCALL_ALIAS(__##abi##_##name, sys_ni_posix_timers);
     91
     92#ifdef CONFIG_X86_64
     93#define __X64_SYS_STUB0(name)						\
     94	__SYS_STUB0(x64, sys_##name)
     95
     96#define __X64_SYS_STUBx(x, name, ...)					\
     97	__SYS_STUBx(x64, sys##name,					\
     98		    SC_X86_64_REGS_TO_ARGS(x, __VA_ARGS__))
     99
    100#define __X64_COND_SYSCALL(name)					\
    101	__COND_SYSCALL(x64, sys_##name)
    102
    103#define __X64_SYS_NI(name)						\
    104	__SYS_NI(x64, sys_##name)
    105#else /* CONFIG_X86_64 */
    106#define __X64_SYS_STUB0(name)
    107#define __X64_SYS_STUBx(x, name, ...)
    108#define __X64_COND_SYSCALL(name)
    109#define __X64_SYS_NI(name)
    110#endif /* CONFIG_X86_64 */
    111
    112#if defined(CONFIG_X86_32) || defined(CONFIG_IA32_EMULATION)
    113#define __IA32_SYS_STUB0(name)						\
    114	__SYS_STUB0(ia32, sys_##name)
    115
    116#define __IA32_SYS_STUBx(x, name, ...)					\
    117	__SYS_STUBx(ia32, sys##name,					\
    118		    SC_IA32_REGS_TO_ARGS(x, __VA_ARGS__))
    119
    120#define __IA32_COND_SYSCALL(name)					\
    121	__COND_SYSCALL(ia32, sys_##name)
    122
    123#define __IA32_SYS_NI(name)						\
    124	__SYS_NI(ia32, sys_##name)
    125#else /* CONFIG_X86_32 || CONFIG_IA32_EMULATION */
    126#define __IA32_SYS_STUB0(name)
    127#define __IA32_SYS_STUBx(x, name, ...)
    128#define __IA32_COND_SYSCALL(name)
    129#define __IA32_SYS_NI(name)
    130#endif /* CONFIG_X86_32 || CONFIG_IA32_EMULATION */
    131
    132#ifdef CONFIG_IA32_EMULATION
    133/*
    134 * For IA32 emulation, we need to handle "compat" syscalls *and* create
    135 * additional wrappers (aptly named __ia32_sys_xyzzy) which decode the
    136 * ia32 regs in the proper order for shared or "common" syscalls. As some
    137 * syscalls may not be implemented, we need to expand COND_SYSCALL in
    138 * kernel/sys_ni.c and SYS_NI in kernel/time/posix-stubs.c to cover this
    139 * case as well.
    140 */
    141#define __IA32_COMPAT_SYS_STUB0(name)					\
    142	__SYS_STUB0(ia32, compat_sys_##name)
    143
    144#define __IA32_COMPAT_SYS_STUBx(x, name, ...)				\
    145	__SYS_STUBx(ia32, compat_sys##name,				\
    146		    SC_IA32_REGS_TO_ARGS(x, __VA_ARGS__))
    147
    148#define __IA32_COMPAT_COND_SYSCALL(name)				\
    149	__COND_SYSCALL(ia32, compat_sys_##name)
    150
    151#define __IA32_COMPAT_SYS_NI(name)					\
    152	__SYS_NI(ia32, compat_sys_##name)
    153
    154#else /* CONFIG_IA32_EMULATION */
    155#define __IA32_COMPAT_SYS_STUB0(name)
    156#define __IA32_COMPAT_SYS_STUBx(x, name, ...)
    157#define __IA32_COMPAT_COND_SYSCALL(name)
    158#define __IA32_COMPAT_SYS_NI(name)
    159#endif /* CONFIG_IA32_EMULATION */
    160
    161
    162#ifdef CONFIG_X86_X32_ABI
    163/*
    164 * For the x32 ABI, we need to create a stub for compat_sys_*() which is aware
    165 * of the x86-64-style parameter ordering of x32 syscalls. The syscalls common
    166 * with x86_64 obviously do not need such care.
    167 */
    168#define __X32_COMPAT_SYS_STUB0(name)					\
    169	__SYS_STUB0(x64, compat_sys_##name)
    170
    171#define __X32_COMPAT_SYS_STUBx(x, name, ...)				\
    172	__SYS_STUBx(x64, compat_sys##name,				\
    173		    SC_X86_64_REGS_TO_ARGS(x, __VA_ARGS__))
    174
    175#define __X32_COMPAT_COND_SYSCALL(name)					\
    176	__COND_SYSCALL(x64, compat_sys_##name)
    177
    178#define __X32_COMPAT_SYS_NI(name)					\
    179	__SYS_NI(x64, compat_sys_##name)
    180#else /* CONFIG_X86_X32_ABI */
    181#define __X32_COMPAT_SYS_STUB0(name)
    182#define __X32_COMPAT_SYS_STUBx(x, name, ...)
    183#define __X32_COMPAT_COND_SYSCALL(name)
    184#define __X32_COMPAT_SYS_NI(name)
    185#endif /* CONFIG_X86_X32_ABI */
    186
    187
    188#ifdef CONFIG_COMPAT
    189/*
    190 * Compat means IA32_EMULATION and/or X86_X32. As they use a different
    191 * mapping of registers to parameters, we need to generate stubs for each
    192 * of them.
    193 */
    194#define COMPAT_SYSCALL_DEFINE0(name)					\
    195	static long							\
    196	__do_compat_sys_##name(const struct pt_regs *__unused);		\
    197	__IA32_COMPAT_SYS_STUB0(name)					\
    198	__X32_COMPAT_SYS_STUB0(name)					\
    199	static long							\
    200	__do_compat_sys_##name(const struct pt_regs *__unused)
    201
    202#define COMPAT_SYSCALL_DEFINEx(x, name, ...)					\
    203	static long __se_compat_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__));	\
    204	static inline long __do_compat_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));\
    205	__IA32_COMPAT_SYS_STUBx(x, name, __VA_ARGS__)				\
    206	__X32_COMPAT_SYS_STUBx(x, name, __VA_ARGS__)				\
    207	static long __se_compat_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__))	\
    208	{									\
    209		return __do_compat_sys##name(__MAP(x,__SC_DELOUSE,__VA_ARGS__));\
    210	}									\
    211	static inline long __do_compat_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))
    212
    213/*
    214 * As some compat syscalls may not be implemented, we need to expand
    215 * COND_SYSCALL_COMPAT in kernel/sys_ni.c and COMPAT_SYS_NI in
    216 * kernel/time/posix-stubs.c to cover this case as well.
    217 */
    218#define COND_SYSCALL_COMPAT(name) 					\
    219	__IA32_COMPAT_COND_SYSCALL(name)				\
    220	__X32_COMPAT_COND_SYSCALL(name)
    221
    222#define COMPAT_SYS_NI(name)						\
    223	__IA32_COMPAT_SYS_NI(name)					\
    224	__X32_COMPAT_SYS_NI(name)
    225
    226#endif /* CONFIG_COMPAT */
    227
    228#define __SYSCALL_DEFINEx(x, name, ...)					\
    229	static long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__));	\
    230	static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));\
    231	__X64_SYS_STUBx(x, name, __VA_ARGS__)				\
    232	__IA32_SYS_STUBx(x, name, __VA_ARGS__)				\
    233	static long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__))	\
    234	{								\
    235		long ret = __do_sys##name(__MAP(x,__SC_CAST,__VA_ARGS__));\
    236		__MAP(x,__SC_TEST,__VA_ARGS__);				\
    237		__PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__));	\
    238		return ret;						\
    239	}								\
    240	static inline long __do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__))
    241
    242/*
    243 * As the generic SYSCALL_DEFINE0() macro does not decode any parameters for
    244 * obvious reasons, and passing struct pt_regs *regs to it in %rdi does not
    245 * hurt, we only need to re-define it here to keep the naming congruent to
    246 * SYSCALL_DEFINEx() -- which is essential for the COND_SYSCALL() and SYS_NI()
    247 * macros to work correctly.
    248 */
    249#define SYSCALL_DEFINE0(sname)						\
    250	SYSCALL_METADATA(_##sname, 0);					\
    251	static long __do_sys_##sname(const struct pt_regs *__unused);	\
    252	__X64_SYS_STUB0(sname)						\
    253	__IA32_SYS_STUB0(sname)						\
    254	static long __do_sys_##sname(const struct pt_regs *__unused)
    255
    256#define COND_SYSCALL(name)						\
    257	__X64_COND_SYSCALL(name)					\
    258	__IA32_COND_SYSCALL(name)
    259
    260#define SYS_NI(name)							\
    261	__X64_SYS_NI(name)						\
    262	__IA32_SYS_NI(name)
    263
    264
    265/*
    266 * For VSYSCALLS, we need to declare these three syscalls with the new
    267 * pt_regs-based calling convention for in-kernel use.
    268 */
    269long __x64_sys_getcpu(const struct pt_regs *regs);
    270long __x64_sys_gettimeofday(const struct pt_regs *regs);
    271long __x64_sys_time(const struct pt_regs *regs);
    272
    273#endif /* _ASM_X86_SYSCALL_WRAPPER_H */