From patchwork Sat Aug 1 01:11:52 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Collingbourne X-Patchwork-Id: 11695653 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 008136C1 for ; Sat, 1 Aug 2020 01:13:51 +0000 (UTC) Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id B9DBE20836 for ; Sat, 1 Aug 2020 01:13:51 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="3BwwgwPQ"; dkim=fail reason="signature verification failed" (2048-bit key) header.d=google.com header.i=@google.com header.b="WYszf95v" DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org B9DBE20836 Authentication-Results: mail.kernel.org; dmarc=fail (p=reject dis=none) header.from=google.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=merlin.20170209; h=Sender:Content-Transfer-Encoding: Content-Type:Cc:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:To:From:Subject:Mime-Version:Message-Id:Date: Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender :Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References:List-Owner; bh=m37zpRxu4bak/hJ9odQ/N9zvNvExwmXiT9M+it3T1B0=; b=3BwwgwPQuYKHQfvfNhT2aHGzRm s2fEYZOQbOrHcPdPYVUtOojtqrjgO45Lo6TFqodk6/A8zj4/NG98OiqhaxtGd4FFjR22sBMJSckbZ lDwSkMoIm/izYLpRqOcwnqX+m8A5qeI7fGPd/ELzzb8A2slK1pIL82LK/S7eNFsN80w/RHFEBV9Oi dcLH8N7YW/IfjeSbfPN23mM8G+xN4lyhzYsAXSlwMRPSNt1kiXzuAJRO2YQqaEYyMctj9wmnrj9BJ Q5SNkbCkILczmt6czpFj7MiLj3SkEZVHcGElWA7f2CmDNo949acsva2AbqQOu/zkjItpM5SGF2/o7 /1s1DTiA==; Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.92.3 #3 (Red Hat Linux)) id 1k1g4D-000572-No; Sat, 01 Aug 2020 01:12:05 +0000 Received: from mail-yb1-xb4a.google.com ([2607:f8b0:4864:20::b4a]) by merlin.infradead.org with esmtps (Exim 4.92.3 #3 (Red Hat Linux)) id 1k1g4A-00056B-P8 for linux-arm-kernel@lists.infradead.org; Sat, 01 Aug 2020 01:12:03 +0000 Received: by mail-yb1-xb4a.google.com with SMTP id 7so38031931ybl.5 for ; Fri, 31 Jul 2020 18:12:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:message-id:mime-version:subject:from:to:cc; bh=3TndnBK0Jueabd3Az5phhVphIL8bWw8kDWSbcSJTW9U=; b=WYszf95v+zt3yPQkwPw69uc+WFNkR1f9lNKZ24lyvs23HQNK3NEi9jvDhjJ7b4XeDM cYhwRMhV30S7gyL3aX/t35z/T6iResL7QwDQJW7PbjP7Tu1TSBzyQkHCKS/bsvyv1hzp ooB9qa0S8YoJlLmO1wmtQE82vlmOHlOJw+aMh8rg7LS+qQPnsvAAihzjgL94neCS9iHQ 7b4Lmd1yjd26731q6wV86ophhAQaEmmH+35fhWruioI2z2EkFO3OQLapEqlstKTmPv66 mVCL1OgU8GvTeMaNCTVZshU0UsXtzqsbFw8NKs1ZwAUkPmPTetzZvNYchh75lEcIe5/b KUcg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:message-id:mime-version:subject:from:to:cc; bh=3TndnBK0Jueabd3Az5phhVphIL8bWw8kDWSbcSJTW9U=; b=QNAyUbIxM0a2aKl6Ma5GNhn1fHBfry71iaaSjzFW18OljAXGqQ5RFcSzhzWxz7/Bqs cAI5gQaeS9nHdxInESVgzZEmzWZrJpKg7wVDYywog6kExrgwcD2fueI8rfS+hxbRj5QT A1nw0d0SiB+SAnMokbE/MwIRrVMEzCPDJ5ps0lT5PL8JjS9JFaaqSbQ9ntypJb6quYmg W3FqkQ+T+03eFE9lqmbkdNTbmy1lnkHnu0wreLIRP+pS4L5e9BbBS5RTYRfUlRkr66J+ O46ZAFKp4/eMmsiWXK1LeXI35eXvgXXM9DwEpecax0NE60FEsGDAxO1jXEFIlZQtAWy7 cnLA== X-Gm-Message-State: AOAM531UbgSbIqPBaKt3ZDP1EmcJaSNZ1U2zSu3qp7WcB6++A/QRXAKX Wz15EwPp1CfqAfL4TPaGrxXI3LU= X-Google-Smtp-Source: ABdhPJyxvZKAizY5X7MTxRUjcoM4onWvrPFbQx7nTuXCtzHOost4Xzof3ucfym83/TXrEiC+mexwABE= X-Received: by 2002:a25:2e46:: with SMTP id b6mr10274898ybn.196.1596244318845; Fri, 31 Jul 2020 18:11:58 -0700 (PDT) Date: Fri, 31 Jul 2020 18:11:52 -0700 Message-Id: <20200801011152.39838-1-pcc@google.com> Mime-Version: 1.0 X-Mailer: git-send-email 2.28.0.163.g6104cc2f0b6-goog Subject: [PATCH] arm64: add prctl(PR_PAC_SET_ENABLED_KEYS) From: Peter Collingbourne To: Catalin Marinas , Evgenii Stepanov , Kostya Serebryany , Vincenzo Frascino , Dave Martin X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20200731_211202_857204_66E96EC2 X-CRM114-Status: GOOD ( 21.16 ) X-Spam-Score: -7.7 (-------) X-Spam-Report: SpamAssassin version 3.4.4 on merlin.infradead.org summary: Content analysis details: (-7.7 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at https://www.dnswl.org/, no trust [2607:f8b0:4864:20:0:0:0:b4a listed in] [list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -7.5 USER_IN_DEF_DKIM_WL From: address is in the default DKIM white-list -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.0 DKIMWL_WL_MED DKIMwl.org - Medium sender X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Andrey Konovalov , Will Deacon , Kevin Brodsky , Peter Collingbourne , Linux ARM Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org This prctl allows the user program to control which PAC keys are enabled in a particular task. The main reason why this is useful is to enable a userspace ABI that uses PAC to sign and authenticate function pointers and other pointers exposed outside of the function, while still allowing binaries conforming to the ABI to interoperate with legacy binaries that do not sign or authenticate pointers. The idea is that a dynamic loader or early startup code would issue this prctl very early after establishing that a process may load legacy binaries, but before executing any PAC instructions. Signed-off-by: Peter Collingbourne --- .../arm64/pointer-authentication.rst | 27 +++++++++++++++ arch/arm64/include/asm/asm_pointer_auth.h | 19 +++++++++++ arch/arm64/include/asm/pointer_auth.h | 10 ++++-- arch/arm64/include/asm/processor.h | 5 +++ arch/arm64/kernel/asm-offsets.c | 1 + arch/arm64/kernel/pointer_auth.c | 34 +++++++++++++++++++ include/uapi/linux/prctl.h | 3 ++ kernel/sys.c | 8 +++++ 8 files changed, 105 insertions(+), 2 deletions(-) diff --git a/Documentation/arm64/pointer-authentication.rst b/Documentation/arm64/pointer-authentication.rst index 30b2ab06526b..1f7e064deeb3 100644 --- a/Documentation/arm64/pointer-authentication.rst +++ b/Documentation/arm64/pointer-authentication.rst @@ -107,3 +107,30 @@ filter out the Pointer Authentication system key registers from KVM_GET/SET_REG_* ioctls and mask those features from cpufeature ID register. Any attempt to use the Pointer Authentication instructions will result in an UNDEFINED exception being injected into the guest. + + +Enabling and disabling keys +--------------------------- + +The prctl PR_PAC_SET_ENABLED_KEYS allows the user program to control which +PAC keys are enabled in a particular task. It takes two arguments, the +first being a bitmask of PR_PAC_APIAKEY, PR_PAC_APIBKEY, PR_PAC_APDAKEY +and PR_PAC_APDBKEY specifying which keys shall be affected by this prctl, +and the second being a bitmask of the same bits specifying whether the key +should be enabled or disabled. For example:: + + prctl(PR_PAC_SET_ENABLED_KEYS, + PR_PAC_APIAKEY | PR_PAC_APIBKEY | PR_PAC_APDAKEY | PR_PAC_APDBKEY, + PR_PAC_APIBKEY, 0, 0); + +disables all keys except the IB key. + +The main reason why this is useful is to enable a userspace ABI that uses PAC +instructions to sign and authenticate function pointers and other pointers +exposed outside of the function, while still allowing binaries conforming to +the ABI to interoperate with legacy binaries that do not sign or authenticate +pointers. + +The idea is that a dynamic loader or early startup code would issue this +prctl very early after establishing that a process may load legacy binaries, +but before executing any PAC instructions. diff --git a/arch/arm64/include/asm/asm_pointer_auth.h b/arch/arm64/include/asm/asm_pointer_auth.h index 52dead2a8640..d121fa5fed5f 100644 --- a/arch/arm64/include/asm/asm_pointer_auth.h +++ b/arch/arm64/include/asm/asm_pointer_auth.h @@ -31,6 +31,14 @@ alternative_else_nop_endif ldp \tmp2, \tmp3, [\tmp1, #PTRAUTH_USER_KEY_APDB] msr_s SYS_APDBKEYLO_EL1, \tmp2 msr_s SYS_APDBKEYHI_EL1, \tmp3 + + ldr \tmp2, [\tsk, #THREAD_SCTLR_ENXX_MASK] + cbz \tmp2, .Laddr_auth_skip_\@ + + mrs_s \tmp3, SYS_SCTLR_EL1 + bic \tmp3, \tmp3, \tmp2 + msr_s SYS_SCTLR_EL1, \tmp3 + .Laddr_auth_skip_\@: alternative_if ARM64_HAS_GENERIC_AUTH ldp \tmp2, \tmp3, [\tmp1, #PTRAUTH_USER_KEY_APGA] @@ -45,6 +53,17 @@ alternative_else_nop_endif ldp \tmp2, \tmp3, [\tmp1, #PTRAUTH_KERNEL_KEY_APIA] msr_s SYS_APIAKEYLO_EL1, \tmp2 msr_s SYS_APIAKEYHI_EL1, \tmp3 + + ldr \tmp2, [\tsk, #THREAD_SCTLR_ENXX_MASK] + cbz \tmp2, .Lset_sctlr_skip_\@ + + mrs_s \tmp1, SYS_SCTLR_EL1 + mov \tmp2, #(SCTLR_ELx_ENIA | SCTLR_ELx_ENIB | SCTLR_ELx_ENDA) + movk \tmp2, #SCTLR_ELx_ENDB + orr \tmp1, \tmp1, \tmp2 + msr_s SYS_SCTLR_EL1, \tmp1 + +.Lset_sctlr_skip_\@: .endm .macro ptrauth_keys_install_kernel_nosync tsk, tmp1, tmp2, tmp3 diff --git a/arch/arm64/include/asm/pointer_auth.h b/arch/arm64/include/asm/pointer_auth.h index c6b4f0603024..d4c375454a36 100644 --- a/arch/arm64/include/asm/pointer_auth.h +++ b/arch/arm64/include/asm/pointer_auth.h @@ -70,14 +70,19 @@ static __always_inline void ptrauth_keys_switch_kernel(struct ptrauth_keys_kerne } extern int ptrauth_prctl_reset_keys(struct task_struct *tsk, unsigned long arg); +extern int ptrauth_prctl_set_enabled_keys(struct task_struct *tsk, + unsigned long keys, + unsigned long enabled); static inline unsigned long ptrauth_strip_insn_pac(unsigned long ptr) { return ptrauth_clear_pac(ptr); } -#define ptrauth_thread_init_user(tsk) \ - ptrauth_keys_init_user(&(tsk)->thread.keys_user) +#define ptrauth_thread_init_user(tsk) do { \ + ptrauth_keys_init_user(&(tsk)->thread.keys_user); \ + (tsk)->thread.sctlr_enxx_mask = 0; \ + } while (0) #define ptrauth_thread_init_kernel(tsk) \ ptrauth_keys_init_kernel(&(tsk)->thread.keys_kernel) #define ptrauth_thread_switch_kernel(tsk) \ @@ -85,6 +90,7 @@ static inline unsigned long ptrauth_strip_insn_pac(unsigned long ptr) #else /* CONFIG_ARM64_PTR_AUTH */ #define ptrauth_prctl_reset_keys(tsk, arg) (-EINVAL) +#define ptrauth_prctl_set_enabled_keys(tsk, keys, enabled) (-EINVAL) #define ptrauth_strip_insn_pac(lr) (lr) #define ptrauth_thread_init_user(tsk) #define ptrauth_thread_init_kernel(tsk) diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h index 240fe5e5b720..6974d227b01f 100644 --- a/arch/arm64/include/asm/processor.h +++ b/arch/arm64/include/asm/processor.h @@ -150,6 +150,7 @@ struct thread_struct { #ifdef CONFIG_ARM64_PTR_AUTH struct ptrauth_keys_user keys_user; struct ptrauth_keys_kernel keys_kernel; + u64 sctlr_enxx_mask; #endif }; @@ -313,6 +314,10 @@ extern void __init minsigstksz_setup(void); /* PR_PAC_RESET_KEYS prctl */ #define PAC_RESET_KEYS(tsk, arg) ptrauth_prctl_reset_keys(tsk, arg) +/* PR_PAC_SET_ENABLED_KEYS prctl */ +#define PAC_SET_ENABLED_KEYS(tsk, keys, enabled) \ + ptrauth_prctl_set_enabled_keys(tsk, keys, enabled) + #ifdef CONFIG_ARM64_TAGGED_ADDR_ABI /* PR_{SET,GET}_TAGGED_ADDR_CTRL prctl */ long set_tagged_addr_ctrl(unsigned long arg); diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c index 0577e2142284..dac80e16fe35 100644 --- a/arch/arm64/kernel/asm-offsets.c +++ b/arch/arm64/kernel/asm-offsets.c @@ -47,6 +47,7 @@ int main(void) #ifdef CONFIG_ARM64_PTR_AUTH DEFINE(THREAD_KEYS_USER, offsetof(struct task_struct, thread.keys_user)); DEFINE(THREAD_KEYS_KERNEL, offsetof(struct task_struct, thread.keys_kernel)); + DEFINE(THREAD_SCTLR_ENXX_MASK,offsetof(struct task_struct, thread.sctlr_enxx_mask)); #endif BLANK(); DEFINE(S_X0, offsetof(struct pt_regs, regs[0])); diff --git a/arch/arm64/kernel/pointer_auth.c b/arch/arm64/kernel/pointer_auth.c index 1e77736a4f66..8c385b7f324a 100644 --- a/arch/arm64/kernel/pointer_auth.c +++ b/arch/arm64/kernel/pointer_auth.c @@ -42,3 +42,37 @@ int ptrauth_prctl_reset_keys(struct task_struct *tsk, unsigned long arg) return 0; } + +static u64 arg_to_enxx_mask(unsigned long arg) +{ + u64 sctlr_enxx_mask = 0; + if (arg & PR_PAC_APIAKEY) + sctlr_enxx_mask |= SCTLR_ELx_ENIA; + if (arg & PR_PAC_APIBKEY) + sctlr_enxx_mask |= SCTLR_ELx_ENIB; + if (arg & PR_PAC_APDAKEY) + sctlr_enxx_mask |= SCTLR_ELx_ENDA; + if (arg & PR_PAC_APDBKEY) + sctlr_enxx_mask |= SCTLR_ELx_ENDB; + return sctlr_enxx_mask; +} + +int ptrauth_prctl_set_enabled_keys(struct task_struct *tsk, unsigned long keys, + unsigned long enabled) +{ + u64 sctlr_enxx_mask = tsk->thread.sctlr_enxx_mask; + unsigned long addr_key_mask = PR_PAC_APIAKEY | PR_PAC_APIBKEY | + PR_PAC_APDAKEY | PR_PAC_APDBKEY; + + if (!system_supports_address_auth()) + return -EINVAL; + + if ((keys & ~addr_key_mask) || (enabled & ~keys)) + return -EINVAL; + + sctlr_enxx_mask |= arg_to_enxx_mask(keys); + sctlr_enxx_mask &= ~arg_to_enxx_mask(enabled); + + tsk->thread.sctlr_enxx_mask = sctlr_enxx_mask; + return 0; +} diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h index 07b4f8131e36..18e1ae4a37a2 100644 --- a/include/uapi/linux/prctl.h +++ b/include/uapi/linux/prctl.h @@ -238,4 +238,7 @@ struct prctl_mm_map { #define PR_SET_IO_FLUSHER 57 #define PR_GET_IO_FLUSHER 58 +/* Set enabled arm64 pointer authentication keys */ +#define PR_PAC_SET_ENABLED_KEYS 59 + #endif /* _LINUX_PRCTL_H */ diff --git a/kernel/sys.c b/kernel/sys.c index 00a96746e28a..623df216183b 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -119,6 +119,9 @@ #ifndef PAC_RESET_KEYS # define PAC_RESET_KEYS(a, b) (-EINVAL) #endif +#ifndef PAC_SET_ENABLED_KEYS +# define PAC_SET_ENABLED_KEYS(a, b, c) (-EINVAL) +#endif #ifndef SET_TAGGED_ADDR_CTRL # define SET_TAGGED_ADDR_CTRL(a) (-EINVAL) #endif @@ -2494,6 +2497,11 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3, return -EINVAL; error = PAC_RESET_KEYS(me, arg2); break; + case PR_PAC_SET_ENABLED_KEYS: + if (arg4 || arg5) + return -EINVAL; + error = PAC_SET_ENABLED_KEYS(me, arg2, arg3); + break; case PR_SET_TAGGED_ADDR_CTRL: if (arg3 || arg4 || arg5) return -EINVAL;