On arm64 the defense against "variant 2" is a bit more difficult as
Aarch64 does not define a way to flush the branch prediction cache.
The diff below basically follows the advice from:

https://github.com/ARM-software/arm-trusted-firmware/wiki/ARM-Trusted-Firmware-Security-Advisory-TFV-6

which is also what Linux does[1].  We flush upon context switches and
certain traps that could indicate an attempt to access kernel space
from userland in an attempt to "train" the branch predictor.

Unfortunately that means you'll need updated firmware to actually be
protected.  I'll update the port for the rk3399 firmware in the near
future; until we actually support SMP it isn't an issue as we run on
one of the "LITTLE" Cortex-A53 cores.  Unfortunately for machines with
true UEFI firmware we have to rely on the vendor to provide updated
firmware.  And there is no update for the Overdrive 1000 yet.

The diff itself has no significant impact on my "compile a RAMDISK
kernel" benchmark.  But as implicated above, the firmware doesn't
actually flush the BP cache.

ok?

[1] If they get their act together and actually merge things into the
official tree.


Index: arch/arm64/arm64/cpu.c
===================================================================
RCS file: /cvs/src/sys/arch/arm64/arm64/cpu.c,v
retrieving revision 1.10
diff -u -p -r1.10 cpu.c
--- arch/arm64/arm64/cpu.c      12 Jan 2018 22:20:28 -0000      1.10
+++ arch/arm64/arm64/cpu.c      15 Jan 2018 20:06:37 -0000
@@ -28,6 +28,11 @@
 #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 *);
@@ -190,6 +232,19 @@ cpu_attach(struct device *parent, struct
        }
 
        printf("\n");
+}
+
+void
+cpu_flush_bp_noop(void)
+{
+}
+
+void
+cpu_flush_bp_psci(void)
+{
+#if NPSCI > 0
+       psci_version();
+#endif
 }
 
 int
Index: arch/arm64/arm64/pmap.c
===================================================================
RCS file: /cvs/src/sys/arch/arm64/arm64/pmap.c,v
retrieving revision 1.45
diff -u -p -r1.45 pmap.c
--- arch/arm64/arm64/pmap.c     13 Jan 2018 10:58:50 -0000      1.45
+++ arch/arm64/arm64/pmap.c     15 Jan 2018 20:06:37 -0000
@@ -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: arch/arm64/arm64/trap.c
===================================================================
RCS file: /cvs/src/sys/arch/arm64/arm64/trap.c,v
retrieving revision 1.14
diff -u -p -r1.14 trap.c
--- arch/arm64/arm64/trap.c     12 Jan 2018 22:20:28 -0000      1.14
+++ arch/arm64/arm64/trap.c     15 Jan 2018 20:06:37 -0000
@@ -142,6 +142,9 @@ data_abort(struct trapframe *frame, uint
        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, uint
                        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: arch/arm64/include/cpu.h
===================================================================
RCS file: /cvs/src/sys/arch/arm64/include/cpu.h,v
retrieving revision 1.4
diff -u -p -r1.4 cpu.h
--- arch/arm64/include/cpu.h    12 Jan 2018 22:20:28 -0000      1.4
+++ arch/arm64/include/cpu.h    15 Jan 2018 20:06:37 -0000
@@ -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
Index: dev/fdt/files.fdt
===================================================================
RCS file: /cvs/src/sys/dev/fdt/files.fdt,v
retrieving revision 1.36
diff -u -p -r1.36 files.fdt
--- dev/fdt/files.fdt   6 Jan 2018 13:04:47 -0000       1.36
+++ dev/fdt/files.fdt   15 Jan 2018 20:06:38 -0000
@@ -69,7 +69,7 @@ file  dev/fdt/plrtc.c                 plrtc
 # ARM Power State Coordination Interface
 device psci
 attach psci at fdt
-file   dev/fdt/psci.c                  psci
+file   dev/fdt/psci.c                  psci needs-flag
 
 attach virtio at fdt with virtio_mmio
 file   dev/fdt/virtio_mmio.c           virtio_mmio
Index: dev/fdt/psci.c
===================================================================
RCS file: /cvs/src/sys/dev/fdt/psci.c,v
retrieving revision 1.3
diff -u -p -r1.3 psci.c
--- dev/fdt/psci.c      29 Dec 2017 14:45:15 -0000      1.3
+++ dev/fdt/psci.c      15 Jan 2018 20:06:38 -0000
@@ -26,10 +26,13 @@
 #include <dev/ofw/openfirm.h>
 #include <dev/ofw/fdt.h>
 
+#include <dev/fdt/pscivar.h>
+
 extern void (*cpuresetfn)(void);
 extern void (*powerdownfn)(void);
 extern int (*cpu_on_fn)(register_t, register_t);
 
+#define PSCI_VERSION   0x84000000
 #define SYSTEM_OFF     0x84000008
 #define SYSTEM_RESET   0x84000009
 #ifdef __LP64__
@@ -42,6 +45,7 @@ struct psci_softc {
        struct device    sc_dev;
        register_t       (*sc_callfn)(register_t, register_t, register_t,
                             register_t);
+       int              sc_psci_version; 
        int              sc_system_off;
        int              sc_system_reset;
        int              sc_cpu_on;
@@ -82,6 +86,7 @@ psci_attach(struct device *parent, struc
        struct psci_softc *sc = (struct psci_softc *)self;
        struct fdt_attach_args *faa = aux;
        char method[128];
+       uint32_t version;
 
        if (OF_getprop(faa->fa_node, "method", method, sizeof(method))) {
                if (strcmp(method, "hvc") == 0)
@@ -97,6 +102,7 @@ psci_attach(struct device *parent, struc
         */
        if (OF_is_compatible(faa->fa_node, "arm,psci-0.2") ||
            OF_is_compatible(faa->fa_node, "arm,psci-1.0")) {
+               sc->sc_psci_version = PSCI_VERSION;
                sc->sc_system_off = SYSTEM_OFF;
                sc->sc_system_reset = SYSTEM_RESET;
                sc->sc_cpu_on = CPU_ON;
@@ -108,15 +114,29 @@ psci_attach(struct device *parent, struc
                sc->sc_cpu_on = OF_getpropint(faa->fa_node, "cpu_on", 0);
        }
 
-       printf("\n");
-
        psci_sc = sc;
+
+       version = psci_version();
+       printf(": PSCI %d.%d\n", version >> 16, version & 0xffff);
+
        if (sc->sc_system_off != 0)
                powerdownfn = psci_powerdown;
        if (sc->sc_system_reset != 0)
                cpuresetfn = psci_reset;
        if (sc->sc_cpu_on != 0)
                cpu_on_fn = psci_cpu_on;
+}
+
+uint32_t
+psci_version(void)
+{
+       struct psci_softc *sc = psci_sc;
+
+       if (sc && sc->sc_callfn && sc->sc_psci_version != 0)
+               return (*sc->sc_callfn)(sc->sc_psci_version, 0, 0, 0);
+
+       /* No version support; return 0.0. */
+       return 0;
 }
 
 void
Index: dev/fdt/pscivar.h
===================================================================
RCS file: dev/fdt/pscivar.h
diff -N dev/fdt/pscivar.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ dev/fdt/pscivar.h   15 Jan 2018 20:06:38 -0000
@@ -0,0 +1,8 @@
+/* Public Domain */
+
+#ifndef _SYS_DEV_FDT_PSCIVAR_H_
+#define _SYS_DEV_FDT_PSCIVAR_H_
+
+uint32_t psci_version(void);
+
+#endif /* _SYS_DEV_FDT_PSCIVAR_H_ */

Reply via email to