Defend agains branch predictor target injection (Spectre "variant 2")
authorkettenis <kettenis@openbsd.org>
Wed, 17 Jan 2018 10:22:25 +0000 (10:22 +0000)
committerkettenis <kettenis@openbsd.org>
Wed, 17 Jan 2018 10:22:25 +0000 (10:22 +0000)
attacks by flushing the branch predictor cache (BTB) on context switches
and page faults in kkernel address space.  Note that this relies on the
presence of firmware (such as Arm Trusted Firmware) that provides PSCI
services that flush the BTB on entry as described in Arm Trusted Firmware
Security Advisory TFV 6.

ok patrick@, visa@

sys/arch/arm64/arm64/cpu.c
sys/arch/arm64/arm64/pmap.c
sys/arch/arm64/arm64/trap.c
sys/arch/arm64/include/cpu.h

index fbfe461..e216c70 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: cpu.c,v 1.10 2018/01/12 22:20:28 kettenis Exp $       */
+/*     $OpenBSD: cpu.c,v 1.11 2018/01/17 10:22:25 kettenis Exp $       */
 
 /*
  * Copyright (c) 2016 Dale Rahn <drahn@dalerahn.com>
 #include <dev/ofw/ofw_clock.h>
 #include <dev/ofw/fdt.h>
 
+#include "psci.h"
+#if NPSCI > 0
+#include <dev/fdt/pscivar.h>
+#endif
+
 /* CPU Identification */
 #define CPU_IMPL_ARM           0x41
 #define CPU_IMPL_CAVIUM                0x43
@@ -105,6 +110,9 @@ struct cfdriver cpu_cd = {
        NULL, "cpu", DV_DULL
 };
 
+void   cpu_flush_bp_noop(void);
+void   cpu_flush_bp_psci(void);
+
 void
 cpu_identify(struct cpu_info *ci)
 {
@@ -147,6 +155,40 @@ cpu_identify(struct cpu_info *ci)
                if (CPU_IS_PRIMARY(ci))
                        snprintf(cpu_model, sizeof(cpu_model), "Unknown");
        }
+
+       /*
+        * Some ARM processors are vulnerable to branch target
+        * injection attacks.
+        */
+       switch (impl) {
+       case CPU_IMPL_ARM:
+               switch (part) {
+               case CPU_PART_CORTEX_A35:
+               case CPU_PART_CORTEX_A53:
+               case CPU_PART_CORTEX_A55:
+                       /* Not vulnerable. */
+                       ci->ci_flush_bp = cpu_flush_bp_noop;
+                       break;
+               case CPU_PART_CORTEX_A57:
+               case CPU_PART_CORTEX_A72:
+               case CPU_PART_CORTEX_A73:
+               case CPU_PART_CORTEX_A75:
+               default:
+                       /*
+                        * Vulnerable; call PSCI_VERSION and hope
+                        * we're running on top of Arm Trusted
+                        * Firmware with a fix for Security Advisory
+                        * TFV 6.
+                        */
+                       ci->ci_flush_bp = cpu_flush_bp_psci;
+                       break;
+               }
+               break;
+       default:
+               /* Not much we can do for an unknown processor.  */
+               ci->ci_flush_bp = cpu_flush_bp_noop;
+               break;
+       }
 }
 
 int    cpu_clockspeed(int *);
@@ -192,6 +234,19 @@ cpu_attach(struct device *parent, struct device *dev, void *aux)
        printf("\n");
 }
 
+void
+cpu_flush_bp_noop(void)
+{
+}
+
+void
+cpu_flush_bp_psci(void)
+{
+#if NPSCI > 0
+       psci_version();
+#endif
+}
+
 int
 cpu_clockspeed(int *freq)
 {
index 65503d8..56ffaf3 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: pmap.c,v 1.45 2018/01/13 10:58:50 kettenis Exp $ */
+/* $OpenBSD: pmap.c,v 1.46 2018/01/17 10:22:25 kettenis Exp $ */
 /*
  * Copyright (c) 2008-2009,2014-2016 Dale Rahn <drahn@dalerahn.com>
  *
@@ -2099,10 +2099,12 @@ pmap_free_asid(pmap_t pm)
 void
 pmap_setttb(struct proc *p)
 {
+       struct cpu_info *ci = curcpu();
        pmap_t pm = p->p_vmspace->vm_map.pmap;
 
        WRITE_SPECIALREG(ttbr0_el1, pmap_kernel()->pm_pt0pa);
        __asm volatile("isb");
        cpu_setttb(pm->pm_asid, pm->pm_pt0pa);
-       curcpu()->ci_curpm = pm;
+       ci->ci_flush_bp();
+       ci->ci_curpm = pm;
 }
index 6ba244f..29321ae 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: trap.c,v 1.14 2018/01/12 22:20:28 kettenis Exp $ */
+/* $OpenBSD: trap.c,v 1.15 2018/01/17 10:22:25 kettenis Exp $ */
 /*-
  * Copyright (c) 2014 Andrew Turner
  * All rights reserved.
@@ -142,6 +142,9 @@ data_abort(struct trapframe *frame, uint64_t esr, int lower, int exe)
        p = curcpu()->ci_curproc;
 
        far = READ_SPECIALREG(far_el1);
+       va = trunc_page(far);
+       if (va >= VM_MAXUSER_ADDRESS)
+               curcpu()->ci_flush_bp();
 
        if (lower)
                map = &p->p_vmspace->vm_map;
@@ -153,7 +156,6 @@ data_abort(struct trapframe *frame, uint64_t esr, int lower, int exe)
                        map = &p->p_vmspace->vm_map;
        }
 
-       va = trunc_page(far);
        if (exe)
                access_type = PROT_EXEC;
        else
@@ -298,6 +300,7 @@ do_el0_sync(struct trapframe *frame)
        switch(exception) {
        case EXCP_UNKNOWN:
                vfp_save();
+               curcpu()->ci_flush_bp();
                sv.sival_ptr = (void *)frame->tf_elr;
                KERNEL_LOCK();
                trapsignal(p, SIGILL, 0, ILL_ILLOPC, sv);
@@ -317,6 +320,7 @@ do_el0_sync(struct trapframe *frame)
                break;
        case EXCP_PC_ALIGN:
                vfp_save();
+               curcpu()->ci_flush_bp();
                sv.sival_ptr = (void *)frame->tf_elr;
                KERNEL_LOCK();
                trapsignal(p, SIGBUS, 0, BUS_ADRALN, sv);
@@ -324,6 +328,7 @@ do_el0_sync(struct trapframe *frame)
                break;
        case EXCP_SP_ALIGN:
                vfp_save();
+               curcpu()->ci_flush_bp();
                sv.sival_ptr = (void *)frame->tf_sp;
                KERNEL_LOCK();
                trapsignal(p, SIGBUS, 0, BUS_ADRALN, sv);
@@ -349,6 +354,7 @@ do_el0_sync(struct trapframe *frame)
                        printf("exception %x esr_el1 %llx\n", exception, esr);
                        dumpregs(frame);
                }
+               curcpu()->ci_flush_bp();
                KERNEL_LOCK();
                sigexit(p, SIGILL);
                KERNEL_UNLOCK();
index c425e02..8329fc5 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.h,v 1.4 2018/01/12 22:20:28 kettenis Exp $ */
+/* $OpenBSD: cpu.h,v 1.5 2018/01/17 10:22:25 kettenis Exp $ */
 /*
  * Copyright (c) 2016 Dale Rahn <drahn@dalerahn.com>
  *
@@ -100,6 +100,8 @@ struct cpu_info {
 #endif
        int                     ci_want_resched;
 
+       void                    (*ci_flush_bp)(void);
+
 #ifdef MULTIPROCESSOR
        struct srp_hazard       ci_srp_hazards[SRP_HAZARD_NUM];
 #endif