Message ID | 20200707173232.5535-1-steve.capper@arm.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | arm64: Introduce sysctl to disable pointer authentication | expand |
On Tue, Jul 07, 2020 at 06:32:32PM +0100, Steve Capper wrote: > Pointer authentication is a mandatory feature in the Armv8.3 > architecture that provides protection against return oriented > programming attacks. (meaning that all Arm CPUs targetting at least > Armv8.3 will have this feature). > > Once CONFIG_ARM64_PTR_AUTH=y, any systems with the hardware support for > pointer authentication will automatically have it enabled by the kernel. > > There are, however, situations where end users may want to disable > pointer authentication. One could be tracking down/working around a bug > in userspace relating to pointer auth. Also, one may wish to quantify > the performance overhead of pointer auth by running a workload > with/without it. If you're debugging userspace, just recompile your userspace application without ptr auth, in the same way that you might recompile with -g. The performance argument sucks; this stuff needs to be fast otherwise it's pointless. If you really need that last bit of speed, try Gentoo ;) Will
Hi Will, On Wed, Jul 08, 2020 at 08:36:21AM +0100, Will Deacon wrote: > On Tue, Jul 07, 2020 at 06:32:32PM +0100, Steve Capper wrote: > > Pointer authentication is a mandatory feature in the Armv8.3 > > architecture that provides protection against return oriented > > programming attacks. (meaning that all Arm CPUs targetting at least > > Armv8.3 will have this feature). > > > > Once CONFIG_ARM64_PTR_AUTH=y, any systems with the hardware support for > > pointer authentication will automatically have it enabled by the kernel. > > > > There are, however, situations where end users may want to disable > > pointer authentication. One could be tracking down/working around a bug > > in userspace relating to pointer auth. Also, one may wish to quantify > > the performance overhead of pointer auth by running a workload > > with/without it. > > If you're debugging userspace, just recompile your userspace application > without ptr auth, in the same way that you might recompile with -g. > > The performance argument sucks; this stuff needs to be fast otherwise it's > pointless. If you really need that last bit of speed, try Gentoo ;) I've tried Gentoo, and I liked it :-). Apologies, I could have done a better job with the commit log... I am trying to enable pointer authentication in distros. One concern I have is that a pointer auth bug could slip through the cracks (with a lot of hardware not yet supporting pointer auth), and then affect an end user. Also, I have had interest from distros in the performance cost of pointer auth, and there will very likely be folk switching it off/on again in order to perform tests. One approach to deploying this could be to have pointer auth disabled in the kernel completely (via kconfig) and interested parties could then switch kernels. Trouble with this is that distros ship single binaries so it would be up to the end user to build/install another kernel + modules. So this could be a barrier to adoption. Having a mechanism in the kernel that an end user can employ to activate/ de-activate pointer auth would help with deployment greatly, and that is what I was trying to achieve with this patch. Another way to approach this could be via a kernel command line that completely disables pointer auth? (i.e. kernel not activating pointer auth at all, and userspace not seeing the feature) Cheers,
Hi Steve, On Wed, Jul 08, 2020 at 02:46:52PM +0100, Steve Capper wrote: > On Wed, Jul 08, 2020 at 08:36:21AM +0100, Will Deacon wrote: > > On Tue, Jul 07, 2020 at 06:32:32PM +0100, Steve Capper wrote: > > > Pointer authentication is a mandatory feature in the Armv8.3 > > > architecture that provides protection against return oriented > > > programming attacks. (meaning that all Arm CPUs targetting at least > > > Armv8.3 will have this feature). > > > > > > Once CONFIG_ARM64_PTR_AUTH=y, any systems with the hardware support for > > > pointer authentication will automatically have it enabled by the kernel. > > > > > > There are, however, situations where end users may want to disable > > > pointer authentication. One could be tracking down/working around a bug > > > in userspace relating to pointer auth. Also, one may wish to quantify > > > the performance overhead of pointer auth by running a workload > > > with/without it. > > > > If you're debugging userspace, just recompile your userspace application > > without ptr auth, in the same way that you might recompile with -g. > > > > The performance argument sucks; this stuff needs to be fast otherwise it's > > pointless. If you really need that last bit of speed, try Gentoo ;) > > I've tried Gentoo, and I liked it :-). In fact, I used to use it as well but it's a total bugger if you forget to update for a week or so. I remember an awful program called revdep-rebuild or something. Dreadful stuff, but good fun (and, incidentally, what got me interested in the kernel). > Apologies, I could have done a better job with the commit log... I've got to be honest, but the commit log smells of "I'm doing this because somebody asked me to, not because I think it's a good idea"... Maybe I'm wrong. > I am trying to enable pointer authentication in distros. One concern I have > is that a pointer auth bug could slip through the cracks (with a lot of > hardware not yet supporting pointer auth), and then affect an end user. Why is that different to any other feature we expose to userspace? Bugs happen, and we deal with them. > Also, I have had interest from distros in the performance cost of pointer > auth, and there will very likely be folk switching it off/on again in > order to perform tests. And they can do that with the compiler at the same time as they pass -funsafe-math -Ofast. > One approach to deploying this could be to have pointer auth disabled in > the kernel completely (via kconfig) and interested parties could then > switch kernels. Trouble with this is that distros ship single binaries so > it would be up to the end user to build/install another kernel + modules. > So this could be a barrier to adoption. Shipping multiple kernels is a non-starter, but I fail to see why that is even a consideration given that this really isn't a kernel problem afaict. > Having a mechanism in the kernel that an end user can employ to activate/ > de-activate pointer auth would help with deployment greatly, and that is > what I was trying to achieve with this patch. > > Another way to approach this could be via a kernel command line that > completely disables pointer auth? (i.e. kernel not activating pointer auth > at all, and userspace not seeing the feature) I did wonder briefly about overriding the sanitised ID registers on the command-line, but I think it opens a door that we'll regret opening later on. Will
Hi, On 7/8/20 5:08 PM, Will Deacon wrote: > Hi Steve, > > On Wed, Jul 08, 2020 at 02:46:52PM +0100, Steve Capper wrote: >> On Wed, Jul 08, 2020 at 08:36:21AM +0100, Will Deacon wrote: >>> On Tue, Jul 07, 2020 at 06:32:32PM +0100, Steve Capper wrote: >>>> Pointer authentication is a mandatory feature in the Armv8.3 >>>> architecture that provides protection against return oriented >>>> programming attacks. (meaning that all Arm CPUs targetting at least >>>> Armv8.3 will have this feature). >>>> >>>> Once CONFIG_ARM64_PTR_AUTH=y, any systems with the hardware support for >>>> pointer authentication will automatically have it enabled by the kernel. >>>> >>>> There are, however, situations where end users may want to disable >>>> pointer authentication. One could be tracking down/working around a bug >>>> in userspace relating to pointer auth. Also, one may wish to quantify >>>> the performance overhead of pointer auth by running a workload >>>> with/without it. >>> >>> If you're debugging userspace, just recompile your userspace application >>> without ptr auth, in the same way that you might recompile with -g >>> >>> The performance argument sucks; this stuff needs to be fast otherwise it's >>> pointless. If you really need that last bit of speed, try Gentoo ;) >> >> I've tried Gentoo, and I liked it :-). > > In fact, I used to use it as well but it's a total bugger if you forget > to update for a week or so. I remember an awful program called revdep-rebuild > or something. Dreadful stuff, but good fun (and, incidentally, what got me > interested in the kernel). > >> Apologies, I could have done a better job with the commit log... > > I've got to be honest, but the commit log smells of "I'm doing this because > somebody asked me to, not because I think it's a good idea"... Maybe I'm > wrong. > >> I am trying to enable pointer authentication in distros. One concern I have >> is that a pointer auth bug could slip through the cracks (with a lot of >> hardware not yet supporting pointer auth), and then affect an end user. > > Why is that different to any other feature we expose to userspace? Bugs > happen, and we deal with them. > >> Also, I have had interest from distros in the performance cost of pointer >> auth, and there will very likely be folk switching it off/on again in >> order to perform tests. > > And they can do that with the compiler at the same time as they pass > -funsafe-math -Ofast. So, a bit of background. Pointer auth has been accepted as a systemwide change for Fedora 33. That acceptance requires contingency planning for what to do if the feature is causing ship blocking/etc defects. While we are going to do our best to test it before release, as your aware, the 8.3+ machines are in short supply. Most of the community testing & debugging will simply be to assure that we don't break anything on v8.0 machines. Which means that its quite likely that the bugs are going to be reported by end users with 8.3+ hardware who don't compile their own packages, nor debug them (and the idea that we can get any kind of coverage on tens of thousands of packages is crazy). Given many of the bugs so far have been subtle glibc/gcc/etc they are also far ranging. So, being able to give the end user a simple way to a->b test whether a problem goes away helps us to triage whether we are looking at a generic bug, or one related to pointer auth (or for that matter an active attack). Further, should it happen to something during the boot process (which is significantly more complex on fedora than the usual kernel+busybox+disk image) then we need a straightforward method to boot the end users machines so they can in-place install/upgrade/test. In summary I see this sort of similar to selinux=0, a flag that no one should be using, but is still frequently used because its required just to boot a machine in order to fix a problem. > >> One approach to deploying this could be to have pointer auth disabled in >> the kernel completely (via kconfig) and interested parties could then >> switch kernels. Trouble with this is that distros ship single binaries so >> it would be up to the end user to build/install another kernel + modules. >> So this could be a barrier to adoption. > > Shipping multiple kernels is a non-starter, but I fail to see why that > is even a consideration given that this really isn't a kernel problem > afaict. We need a way to ship all the PAC enabled binary artifacts but assure they can be quickly/easily reverted to pre 8.3 pointer auth code paths, which have been more heavily tested. Rebuilding the entire distro to globally disable pointer auth is a non starter, particularly after it has shipped. > >> Having a mechanism in the kernel that an end user can employ to activate/ >> de-activate pointer auth would help with deployment greatly, and that is >> what I was trying to achieve with this patch. >> >> Another way to approach this could be via a kernel command line that >> completely disables pointer auth? (i.e. kernel not activating pointer auth >> at all, and userspace not seeing the feature) > > I did wonder briefly about overriding the sanitised ID registers on the > command-line, but I think it opens a door that we'll regret opening later > on. > > Will >
On Wed, Jul 08, 2020 at 11:08:06PM +0100, Will Deacon wrote: > On Wed, Jul 08, 2020 at 02:46:52PM +0100, Steve Capper wrote: > > On Wed, Jul 08, 2020 at 08:36:21AM +0100, Will Deacon wrote: > > > On Tue, Jul 07, 2020 at 06:32:32PM +0100, Steve Capper wrote: > > > > Pointer authentication is a mandatory feature in the Armv8.3 > > > > architecture that provides protection against return oriented > > > > programming attacks. (meaning that all Arm CPUs targetting at least > > > > Armv8.3 will have this feature). > > > > > > > > Once CONFIG_ARM64_PTR_AUTH=y, any systems with the hardware support for > > > > pointer authentication will automatically have it enabled by the kernel. > > > > > > > > There are, however, situations where end users may want to disable > > > > pointer authentication. One could be tracking down/working around a bug > > > > in userspace relating to pointer auth. Also, one may wish to quantify > > > > the performance overhead of pointer auth by running a workload > > > > with/without it. [...] > > Having a mechanism in the kernel that an end user can employ to activate/ > > de-activate pointer auth would help with deployment greatly, and that is > > what I was trying to achieve with this patch. > > > > Another way to approach this could be via a kernel command line that > > completely disables pointer auth? (i.e. kernel not activating pointer auth > > at all, and userspace not seeing the feature) > > I did wonder briefly about overriding the sanitised ID registers on the > command-line, but I think it opens a door that we'll regret opening later > on. I had attempted it in these two patches (together with the DT support): https://lore.kernel.org/linux-arm-kernel/20200515171612.1020-24-catalin.marinas@arm.com/ https://lore.kernel.org/linux-arm-kernel/20200515171612.1020-25-catalin.marinas@arm.com/ (both patches now dropped; we have a way to disable the tagged addr ABI already and reject the prctl() call) Overriding the ID regs disables the feature for both user and kernel. IIUC, Steve only wanted this disabled for user. A light concern with this patch is that it still keeps the HWCAP around, only that it makes this instructions behave as NOPs. So that would be a deviation from what the HWCAP bit actually implies. From this perspective, a big knob may be a cleaner option. Anyway, I agree that opening the door would lead to more such requests in the future. We should only do this if there is a high risk of the feature going terribly wrong in the user space out there. AFAICT, that's not entirely clear at the moment. Distros could carry such patch temporarily and, if proven useful in the long run, we can revisit the upstreaming story.
diff --git a/Documentation/arm64/pointer-authentication.rst b/Documentation/arm64/pointer-authentication.rst index 30b2ab06526b..e8bc8336bbf2 100644 --- a/Documentation/arm64/pointer-authentication.rst +++ b/Documentation/arm64/pointer-authentication.rst @@ -107,3 +107,35 @@ 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. + + +Disabling Pointer Authentication +-------------------------------- +There are situations where end users may want to disable pointer +authentication. One could be tracking down/working around a bug in +userspace relating to pointer authentication. Also, one may wish to +quantify the performance overhead of pointer authentication by running a +workload with/without it. + +For hardware with pointer auth, there is the following sysctl: + +.. code-block:: none + + abi.ptrauth_disabled=1 + +which will disable pointer authentication for any new processes that are +exec'ed. (Reverting to 0 will then re-enable pointer authentication for +any new processes). + +One can also set this sysctl on the kernel command line: + +.. code-block:: none + + sysctl.abi.ptrauth_disabled=1 + +And this will ensure that pointer authentication is disabled for the init +process onwards. + +Note that when pointer authentication is disabled by sysctl, the +capabilities are still exposed to userspace and pointer authentication +instructions can execute (it will just be as NOPs). diff --git a/arch/arm64/include/asm/asm_pointer_auth.h b/arch/arm64/include/asm/asm_pointer_auth.h index 52dead2a8640..29fdd379bf1c 100644 --- a/arch/arm64/include/asm/asm_pointer_auth.h +++ b/arch/arm64/include/asm/asm_pointer_auth.h @@ -82,6 +82,38 @@ alternative_else_nop_endif .Lno_addr_auth\@: .endm + .macro ptrauth_switch_to_user tsk, tmp1, tmp2, tmpw +alternative_if_not ARM64_HAS_ADDRESS_AUTH + b .Ldont_disable\@ +alternative_else_nop_endif + mov \tmp2, #THREAD_PTRAUTH_DISABLED + ldr \tmpw, [\tsk, \tmp2] + cbz \tmpw, .Ldont_disable\@ + mrs \tmp1, sctlr_el1 + mov_q \tmp2, ~(SCTLR_ELx_ENIA | SCTLR_ELx_ENIB | \ + SCTLR_ELx_ENDA | SCTLR_ELx_ENDB) + and \tmp1, \tmp1, \tmp2 + msr sctlr_el1, \tmp1 + // about to drop to EL0 which will give us an implicit isb +.Ldont_disable\@: + .endm + + .macro ptrauth_switch_to_kernel tsk, tmp1, tmp2, tmpw +alternative_if_not ARM64_HAS_ADDRESS_AUTH + b .Ldont_reenable\@ +alternative_else_nop_endif + mov \tmp2, #THREAD_PTRAUTH_DISABLED + ldr \tmpw, [\tsk, \tmp2] + cbz \tmpw, .Ldont_reenable\@ + mrs \tmp1, sctlr_el1 + mov_q \tmp2, (SCTLR_ELx_ENIA | SCTLR_ELx_ENIB | \ + SCTLR_ELx_ENDA | SCTLR_ELx_ENDB) + orr \tmp1, \tmp1, \tmp2 + msr sctlr_el1, \tmp1 + isb // already in kernel mode, need context synchronising event +.Ldont_reenable\@: + .endm + #else /* CONFIG_ARM64_PTR_AUTH */ .macro ptrauth_keys_install_user tsk, tmp1, tmp2, tmp3 @@ -93,6 +125,11 @@ alternative_else_nop_endif .macro ptrauth_keys_install_kernel tsk, tmp1, tmp2, tmp3 .endm + .macro ptrauth_switch_to_user tsk, tmp1, tmp2, tmpw + .endm + + .macro ptrauth_switch_to_kernel tsk, tmp1, tmp2, tmpw + .endm #endif /* CONFIG_ARM64_PTR_AUTH */ #endif /* __ASM_ASM_POINTER_AUTH_H */ diff --git a/arch/arm64/include/asm/pointer_auth.h b/arch/arm64/include/asm/pointer_auth.h index c6b4f0603024..82993561ddc4 100644 --- a/arch/arm64/include/asm/pointer_auth.h +++ b/arch/arm64/include/asm/pointer_auth.h @@ -76,8 +76,12 @@ 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, disabled) \ +do { \ + ptrauth_keys_init_user(&(tsk)->thread.keys_user); \ + (tsk)->thread.ptrauth_disabled = disabled; \ +} while (0) + #define ptrauth_thread_init_kernel(tsk) \ ptrauth_keys_init_kernel(&(tsk)->thread.keys_kernel) #define ptrauth_thread_switch_kernel(tsk) \ @@ -86,7 +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_strip_insn_pac(lr) (lr) -#define ptrauth_thread_init_user(tsk) +#define ptrauth_thread_init_user(tsk, disabled) #define ptrauth_thread_init_kernel(tsk) #define ptrauth_thread_switch_kernel(tsk) #endif /* CONFIG_ARM64_PTR_AUTH */ diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h index 240fe5e5b720..bb0b9edb5f9d 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; + unsigned int ptrauth_disabled; #endif }; diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c index 0577e2142284..eb686d9cf541 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_PTRAUTH_DISABLED, offsetof(struct task_struct, thread.ptrauth_disabled)); #endif BLANK(); DEFINE(S_X0, offsetof(struct pt_regs, regs[0])); diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S index 5304d193c79d..e3985521f763 100644 --- a/arch/arm64/kernel/entry.S +++ b/arch/arm64/kernel/entry.S @@ -180,6 +180,7 @@ alternative_cb_end apply_ssbd 1, x22, x23 ptrauth_keys_install_kernel tsk, x20, x22, x23 + ptrauth_switch_to_kernel tsk, x20, x22, w23 scs_load tsk, x20 .else @@ -350,6 +351,7 @@ alternative_else_nop_endif /* No kernel C function calls after this as user keys are set. */ ptrauth_keys_install_user tsk, x0, x1, x2 + ptrauth_switch_to_user tsk, x0, x1, w2 apply_ssbd 0, x0, x1 .endif @@ -920,6 +922,7 @@ SYM_FUNC_START(cpu_switch_to) mov sp, x9 msr sp_el0, x1 ptrauth_keys_install_kernel x1, x8, x9, x10 + ptrauth_switch_to_kernel x1, x8, x9, w10 scs_save x0, x8 scs_load x1, x8 ret diff --git a/arch/arm64/kernel/process.c b/arch/arm64/kernel/process.c index 6089638c7d43..781f2b7bd986 100644 --- a/arch/arm64/kernel/process.c +++ b/arch/arm64/kernel/process.c @@ -580,6 +580,8 @@ unsigned long arch_align_stack(unsigned long sp) return sp & ~0xf; } +static unsigned int ptrauth_disabled; + /* * Called from setup_new_exec() after (COMPAT_)SET_PERSONALITY. */ @@ -587,9 +589,36 @@ void arch_setup_new_exec(void) { current->mm->context.flags = is_compat_task() ? MMCF_AARCH32 : 0; - ptrauth_thread_init_user(current); + ptrauth_thread_init_user(current, ptrauth_disabled); +} + +#ifdef CONFIG_ARM64_PTR_AUTH + +static struct ctl_table ptrauth_disable_sysctl_table[] = { + { + .procname = "ptrauth_disabled", + .mode = 0644, + .data = &ptrauth_disabled, + .maxlen = sizeof(ptrauth_disabled), + .proc_handler = proc_dointvec_minmax, + .extra1 = SYSCTL_ZERO, + .extra2 = SYSCTL_ONE, + }, + {} + +}; + +static int __init ptrauth_disable_init(void) +{ + if (!register_sysctl("abi", ptrauth_disable_sysctl_table)) + return -EINVAL; + return 0; } +core_initcall(ptrauth_disable_init); + +#endif /* CONFIG_ARM64_PTR_AUTH */ + #ifdef CONFIG_ARM64_TAGGED_ADDR_ABI /* * Control the relaxed ABI allowing tagged user addresses into the kernel.
Pointer authentication is a mandatory feature in the Armv8.3 architecture that provides protection against return oriented programming attacks. (meaning that all Arm CPUs targetting at least Armv8.3 will have this feature). Once CONFIG_ARM64_PTR_AUTH=y, any systems with the hardware support for pointer authentication will automatically have it enabled by the kernel. There are, however, situations where end users may want to disable pointer authentication. One could be tracking down/working around a bug in userspace relating to pointer auth. Also, one may wish to quantify the performance overhead of pointer auth by running a workload with/without it. Linux distributions operate a single binary policy wherever possible, meaning any mechanism to disable pointer authentication as a parameter would be preferred greatly over building/supporting multiple kernels. For hardware with pointer auth, this patch introduces the sysctl: abi.ptrauth_disabled=1 which will disable pointer authentication for any new processes that are exec'ed. (Reverting to 0 will then re-enable pointer authentication for new processes). One can set this sysctl on the kernel command line: sysctl.abi.ptrauth_disabled=1 And this will ensure that pointer authentication is disabled for the init process onwards. Note that when pointer authentication is disabled by sysctl, the capabilities are still exposed to userspace and pointer authentication instructions can execute (it will just be as NOPs). Signed-off-by: Steve Capper <steve.capper@arm.com> --- .../arm64/pointer-authentication.rst | 32 ++++++++++++++++ arch/arm64/include/asm/asm_pointer_auth.h | 37 +++++++++++++++++++ arch/arm64/include/asm/pointer_auth.h | 10 +++-- arch/arm64/include/asm/processor.h | 1 + arch/arm64/kernel/asm-offsets.c | 1 + arch/arm64/kernel/entry.S | 3 ++ arch/arm64/kernel/process.c | 31 +++++++++++++++- 7 files changed, 111 insertions(+), 4 deletions(-)