-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
To minimize the risk of userspace-controlled values being used under speculation, this patch adds pt_regs based syscall wrappers for arm64, which pass the minimum set of required userspace values to syscall implementations. For each syscall, a wrapper which takes a pt_regs argument is automatically generated, and this extracts the arguments before calling the "real" syscall implementation. Each syscall has three functions generated: * __do_<compat_>sys_<name> is the "real" syscall implementation, with the expected prototype. * __se_<compat_>sys_<name> is the sign-extension/narrowing wrapper, inherited from common code. This takes a series of long parameters, casting each to the requisite types required by the "real" syscall implementation in __do_<compat_>sys_<name>. This wrapper *may* not be necessary on arm64 given the AAPCS rules on unused register bits, but it seemed safer to keep the wrapper for now. * __arm64_<compat_>_sys_<name> takes a struct pt_regs pointer, and extracts *only* the relevant register values, passing these on to the __se_<compat_>sys_<name> wrapper. The syscall invocation code is updated to handle the calling convention required by __arm64_<compat_>_sys_<name>, and passes a single struct pt_regs pointer. The compiler can fold the syscall implementation and its wrappers, such that the overhead of this approach is minimized. Note that we play games with sys_ni_syscall(). It can't be defined with SYSCALL_DEFINE0() because we must avoid the possibility of error injection. Additionally, there are a couple of locations where we need to call it from C code, and we don't (currently) have a ksys_ni_syscall(). While it has no wrapper, passing in a redundant pt_regs pointer is benign per the AAPCS. When ARCH_HAS_SYSCALL_WRAPPER is selected, no prototype is defines for sys_ni_syscall(). Since we need to treat it differently for in-kernel calls and the syscall tables, the prototype is defined as-required. The wrappers are largely the same as their x86 counterparts, but simplified as we don't have a variety of compat calling conventions that require separate stubs. Unlike x86, we have some zero-argument compat syscalls, and must define COMPAT_SYSCALL_DEFINE0() to ensure that these are also given an __arm64_compat_sys_ prefix. Signed-off-by: Mark Rutland <mark.rutland@arm.com> Reviewed-by: Dominik Brodowski <linux@dominikbrodowski.net> Reviewed-by: Catalin Marinas <catalin.marinas@arm.com> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Will Deacon <will.deacon@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
- Loading branch information
Mark Rutland
authored and
Will Deacon
committed
Jul 12, 2018
1 parent
55f8492
commit 4378a7d
Showing
6 changed files
with
101 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
/* SPDX-License-Identifier: GPL-2.0 */ | ||
/* | ||
* syscall_wrapper.h - arm64 specific wrappers to syscall definitions | ||
* | ||
* Based on arch/x86/include/asm_syscall_wrapper.h | ||
*/ | ||
|
||
#ifndef __ASM_SYSCALL_WRAPPER_H | ||
#define __ASM_SYSCALL_WRAPPER_H | ||
|
||
#define SC_ARM64_REGS_TO_ARGS(x, ...) \ | ||
__MAP(x,__SC_ARGS \ | ||
,,regs->regs[0],,regs->regs[1],,regs->regs[2] \ | ||
,,regs->regs[3],,regs->regs[4],,regs->regs[5]) | ||
|
||
#ifdef CONFIG_COMPAT | ||
|
||
#define COMPAT_SYSCALL_DEFINEx(x, name, ...) \ | ||
asmlinkage long __arm64_compat_sys##name(const struct pt_regs *regs); \ | ||
ALLOW_ERROR_INJECTION(__arm64_compat_sys##name, ERRNO); \ | ||
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__)); \ | ||
asmlinkage long __arm64_compat_sys##name(const struct pt_regs *regs) \ | ||
{ \ | ||
return __se_compat_sys##name(SC_ARM64_REGS_TO_ARGS(x,__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__)) | ||
|
||
#define COMPAT_SYSCALL_DEFINE0(sname) \ | ||
asmlinkage long __arm64_compat_sys_##sname(void); \ | ||
ALLOW_ERROR_INJECTION(__arm64_compat_sys_##sname, ERRNO); \ | ||
asmlinkage long __arm64_compat_sys_##sname(void) | ||
|
||
#define COND_SYSCALL_COMPAT(name) \ | ||
cond_syscall(__arm64_compat_sys_##name); | ||
|
||
#define COMPAT_SYS_NI(name) \ | ||
SYSCALL_ALIAS(__arm64_compat_sys_##name, sys_ni_posix_timers); | ||
|
||
#endif /* CONFIG_COMPAT */ | ||
|
||
#define __SYSCALL_DEFINEx(x, name, ...) \ | ||
asmlinkage long __arm64_sys##name(const struct pt_regs *regs); \ | ||
ALLOW_ERROR_INJECTION(__arm64_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 __arm64_sys##name(const struct pt_regs *regs) \ | ||
{ \ | ||
return __se_sys##name(SC_ARM64_REGS_TO_ARGS(x,__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__)) | ||
|
||
#ifndef SYSCALL_DEFINE0 | ||
#define SYSCALL_DEFINE0(sname) \ | ||
SYSCALL_METADATA(_##sname, 0); \ | ||
asmlinkage long __arm64_sys_##sname(void); \ | ||
ALLOW_ERROR_INJECTION(__arm64_sys_##sname, ERRNO); \ | ||
asmlinkage long __arm64_sys_##sname(void) | ||
#endif | ||
|
||
#ifndef COND_SYSCALL | ||
#define COND_SYSCALL(name) cond_syscall(__arm64_sys_##name) | ||
#endif | ||
|
||
#ifndef SYS_NI | ||
#define SYS_NI(name) SYSCALL_ALIAS(__arm64_sys_##name, sys_ni_posix_timers); | ||
#endif | ||
|
||
#endif /* __ASM_SYSCALL_WRAPPER_H */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters