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_ */
