From: kettenis Date: Wed, 17 Jan 2018 10:22:25 +0000 (+0000) Subject: Defend agains branch predictor target injection (Spectre "variant 2") X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=d855ec95cfe64f13b6899415be9c24dc9be8ec49;p=openbsd Defend agains branch predictor target injection (Spectre "variant 2") 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@ --- diff --git a/sys/arch/arm64/arm64/cpu.c b/sys/arch/arm64/arm64/cpu.c index fbfe46152f1..e216c7091b1 100644 --- a/sys/arch/arm64/arm64/cpu.c +++ b/sys/arch/arm64/arm64/cpu.c @@ -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 @@ -28,6 +28,11 @@ #include #include +#include "psci.h" +#if NPSCI > 0 +#include +#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) { diff --git a/sys/arch/arm64/arm64/pmap.c b/sys/arch/arm64/arm64/pmap.c index 65503d8d33d..56ffaf34b1f 100644 --- a/sys/arch/arm64/arm64/pmap.c +++ b/sys/arch/arm64/arm64/pmap.c @@ -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 * @@ -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; } diff --git a/sys/arch/arm64/arm64/trap.c b/sys/arch/arm64/arm64/trap.c index 6ba244f9da9..29321aec439 100644 --- a/sys/arch/arm64/arm64/trap.c +++ b/sys/arch/arm64/arm64/trap.c @@ -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(); diff --git a/sys/arch/arm64/include/cpu.h b/sys/arch/arm64/include/cpu.h index c425e027cca..8329fc5097b 100644 --- a/sys/arch/arm64/include/cpu.h +++ b/sys/arch/arm64/include/cpu.h @@ -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 * @@ -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