Improve defense against branch predictor target injection (Spectre "variant 2")
authorkettenis <kettenis@openbsd.org>
Mon, 15 Jan 2018 14:11:16 +0000 (14:11 +0000)
committerkettenis <kettenis@openbsd.org>
Mon, 15 Jan 2018 14:11:16 +0000 (14:11 +0000)
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@

sys/arch/arm/arm/cpu.c
sys/arch/arm/arm/cpufunc_asm_armv7.S
sys/arch/arm/arm/fault.c
sys/arch/arm/include/cpu.h
sys/arch/arm/include/cpufunc.h

index d51f20e..5b6a9ce 100644 (file)
@@ -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;
index 05679df..20e9db1 100644 (file)
@@ -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 <drahn@openbsd.org>
  *
@@ -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.
  *
index 47f3081..96c0e1b 100644 (file)
@@ -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
index 12df5df..2d783aa 100644 (file)
@@ -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;
index 65da821..b58e248 100644 (file)
@@ -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);