From 4378a7d4be30ec6994702b19936f7d1465193541 Mon Sep 17 00:00:00 2001 From: Mark Rutland Date: Wed, 11 Jul 2018 14:56:56 +0100 Subject: arm64: implement syscall wrappers 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_sys_ is the "real" syscall implementation, with the expected prototype. * __se_sys_ 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_sys_. 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__sys_ takes a struct pt_regs pointer, and extracts *only* the relevant register values, passing these on to the __se_sys_ wrapper. The syscall invocation code is updated to handle the calling convention required by __arm64__sys_, 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 Reviewed-by: Dominik Brodowski Reviewed-by: Catalin Marinas Cc: Catalin Marinas Cc: Will Deacon Signed-off-by: Will Deacon --- arch/arm64/kernel/syscall.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'arch/arm64/kernel/syscall.c') diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c index 7ff2d7b9f517..be00c85794db 100644 --- a/arch/arm64/kernel/syscall.c +++ b/arch/arm64/kernel/syscall.c @@ -15,6 +15,8 @@ long compat_arm_syscall(struct pt_regs *regs); +long sys_ni_syscall(void); + asmlinkage long do_ni_syscall(struct pt_regs *regs) { #ifdef CONFIG_COMPAT @@ -31,8 +33,7 @@ asmlinkage long do_ni_syscall(struct pt_regs *regs) static long __invoke_syscall(struct pt_regs *regs, syscall_fn_t syscall_fn) { - return syscall_fn(regs->regs[0], regs->regs[1], regs->regs[2], - regs->regs[3], regs->regs[4], regs->regs[5]); + return syscall_fn(regs); } static void invoke_syscall(struct pt_regs *regs, unsigned int scno, -- cgit