From: kettenis Date: Mon, 15 Jan 2018 14:11:16 +0000 (+0000) Subject: Improve defense against branch predictor target injection (Spectre "variant 2") X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=539a71cba0b68b136c6ce3fc7e39370b555408b0;p=openbsd Improve defense against branch predictor target injection (Spectre "variant 2") attacks. OpenBSD/armv7 is already in pretty good shape as we have always been flushing the branch predictor cache on context switches. This diff adds additional flushes to page faults in kernel address space. The impact on performance should be minimal as these page faults should only happen when userland (deliberately or accidentally) tries to access kernel addres space which would lead to a fatal signal (SIGSEGV or SIGBUS). Loosely based on changes made by Marc Zyngier in Linux and based on information in Arm Trusted Firmware Security Advisory TFV 6. Note that for Cortex-A15 (and Cortex-A72) you will need firmware that sets the ACTRL[0] bit for this diff to be effective. Also note that with this diff Cortex-A57 is still vulnerable. ok jsg@ --- diff --git a/sys/arch/arm/arm/cpu.c b/sys/arch/arm/arm/cpu.c index d51f20e9849..5b6a9ce1f8a 100644 --- a/sys/arch/arm/arm/cpu.c +++ b/sys/arch/arm/arm/cpu.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.c,v 1.43 2017/12/29 14:45:15 kettenis Exp $ */ +/* $OpenBSD: cpu.c,v 1.44 2018/01/15 14:11:16 kettenis Exp $ */ /* $NetBSD: cpu.c,v 1.56 2004/04/14 04:01:49 bsh Exp $ */ @@ -257,6 +257,49 @@ identify_arm_cpu(struct device *dv, struct cpu_info *ci) printf("\n"); + /* + * Some ARM processors are vulnerable to branch target + * injection attacks. + */ + switch (cpuid & CPU_ID_CORTEX_MASK) { + case CPU_ID_CORTEX_A5: + case CPU_ID_CORTEX_A7: + case CPU_ID_CORTEX_A32: + case CPU_ID_CORTEX_A35: + case CPU_ID_CORTEX_A53: + case CPU_ID_CORTEX_A55: + /* Not vulnerable; no need to flush. */ + ci->ci_flush_bp = cpufunc_nullop; + break; + case CPU_ID_CORTEX_A8: + case CPU_ID_CORTEX_A9: + case CPU_ID_CORTEX_A12: + case CPU_ID_CORTEX_A17: + case CPU_ID_CORTEX_A73: + case CPU_ID_CORTEX_A75: + default: + /* Vulnerable; flush BP cache. */ + ci->ci_flush_bp = armv7_flush_bp; + break; + case CPU_ID_CORTEX_A15: + case CPU_ID_CORTEX_A72: + /* + * Vulnerable; BPIALL is "not effective" so must use + * ICIALLU and hope the firmware set the magic bit in + * the ACTLR that actually forces a BTB flush. + */ + ci->ci_flush_bp = cortex_a15_flush_bp; + break; + case CPU_ID_CORTEX_A57: + /* + * Vulnerable; must disable and enable the MMU which + * can be done by a PSCI call on firmware with the + * appropriate fixes. Punt for now. + */ + ci->ci_flush_bp = cpufunc_nullop; + break; + } + /* Print cache info. */ if (arm_picache_line_size == 0 && arm_pdcache_line_size == 0) goto skip_pcache; diff --git a/sys/arch/arm/arm/cpufunc_asm_armv7.S b/sys/arch/arm/arm/cpufunc_asm_armv7.S index 05679df15fa..20e9db1435d 100644 --- a/sys/arch/arm/arm/cpufunc_asm_armv7.S +++ b/sys/arch/arm/arm/cpufunc_asm_armv7.S @@ -1,4 +1,4 @@ -/* $OpenBSD: cpufunc_asm_armv7.S,v 1.14 2016/08/15 21:08:56 kettenis Exp $ */ +/* $OpenBSD: cpufunc_asm_armv7.S,v 1.15 2018/01/15 14:11:16 kettenis Exp $ */ /* * Copyright (c) 2008 Dale Rahn * @@ -208,6 +208,17 @@ ENTRY(armv7_dcache_inv_range) mov pc, lr +/* + * BTB functions. + */ +ENTRY(armv7_flush_bp) + mcr CP15_BPIALL + mov pc, lr + +ENTRY(cortex_a15_flush_bp) + mcr CP15_ICIALLU /* Heavy hammer; BPIALL is a no-op */ + mov pc, lr + /* * Context switch. * diff --git a/sys/arch/arm/arm/fault.c b/sys/arch/arm/arm/fault.c index 47f308121d1..96c0e1b54a5 100644 --- a/sys/arch/arm/arm/fault.c +++ b/sys/arch/arm/arm/fault.c @@ -1,4 +1,4 @@ -/* $OpenBSD: fault.c,v 1.30 2017/09/08 05:36:51 deraadt Exp $ */ +/* $OpenBSD: fault.c,v 1.31 2018/01/15 14:11:16 kettenis Exp $ */ /* $NetBSD: fault.c,v 1.46 2004/01/21 15:39:21 skrll Exp $ */ /* @@ -209,6 +209,15 @@ data_abort_handler(trapframe_t *tf) goto out; } + va = trunc_page((vaddr_t)far); + + /* + * Flush BP cache on processors that are vulnerable to branch + * target injection attacks if access is outside user space. + */ + if (va < VM_MIN_ADDRESS || va >= VM_MAX_ADDRESS) + curcpu()->ci_flush_bp(); + /* * At this point, we're dealing with one of the following data aborts: * @@ -256,8 +265,6 @@ data_abort_handler(trapframe_t *tf) dab_fatal(tf, fsr, far, p, NULL); } - va = trunc_page((vaddr_t)far); - /* * It is only a kernel address space fault iff: * 1. user == 0 and diff --git a/sys/arch/arm/include/cpu.h b/sys/arch/arm/include/cpu.h index 12df5df0146..2d783aaf374 100644 --- a/sys/arch/arm/include/cpu.h +++ b/sys/arch/arm/include/cpu.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpu.h,v 1.48 2017/08/12 13:18:48 tedu Exp $ */ +/* $OpenBSD: cpu.h,v 1.49 2018/01/15 14:11:16 kettenis Exp $ */ /* $NetBSD: cpu.h,v 1.34 2003/06/23 11:01:08 martin Exp $ */ /* @@ -206,6 +206,8 @@ struct cpu_info { #ifdef GPROF struct gmonparam *ci_gmon; #endif + + void (*ci_flush_bp)(void); }; extern struct cpu_info cpu_info_primary; diff --git a/sys/arch/arm/include/cpufunc.h b/sys/arch/arm/include/cpufunc.h index 65da821b49a..b58e2487dfb 100644 --- a/sys/arch/arm/include/cpufunc.h +++ b/sys/arch/arm/include/cpufunc.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cpufunc.h,v 1.29 2017/01/06 00:06:02 jsg Exp $ */ +/* $OpenBSD: cpufunc.h,v 1.30 2018/01/15 14:11:16 kettenis Exp $ */ /* $NetBSD: cpufunc.h,v 1.29 2003/09/06 09:08:35 rearnsha Exp $ */ /* @@ -231,6 +231,9 @@ void armv7_tlb_flushI (void); void armv7_tlb_flushD (void); void armv7_tlb_flushD_SE (u_int va); +void armv7_flush_bp(void); +void cortex_a15_flush_bp(void); + void armv7_drain_writebuf (void); void armv7_cpu_sleep (int mode);