Workaround Spectre Variant 2 on arm64.

We need to handle two cases:

1. One process attacking another process.
2. A process attacking the kernel.

For the first case we clear the branch predictor state on context switch
between different processes. For the second we do this when taking an
instruction abort on a non-userspace address.

To clear the branch predictor state a per-CPU function pointer has been
added. This is set by the new cpu errata code based on if the CPU is
known to be affected.

On Cortex-A57, A72, A73, and A75 we call into the PSCI firmware as newer
versions of this will clear the branch predictor state for us.

It has been reported the ThunderX is unaffected, however the ThunderX2 is
vulnerable. The Qualcomm Falkor core is also affected. As FreeBSD doesn't
yet run on the ThunderX2 or Falkor no workaround is included for these CPUs.

MFC after:	3 days
Sponsored by:	DARPA, AFRL
Differential Revision:	https://reviews.freebsd.org/D13812
This commit is contained in:
Andrew Turner 2018-01-12 14:01:38 +00:00
parent 310f24d72a
commit 7023544aec
4 changed files with 65 additions and 2 deletions

View File

@ -30,6 +30,8 @@
* SUCH DAMAGE.
*/
#include "opt_platform.h"
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
@ -39,6 +41,10 @@ __FBSDID("$FreeBSD$");
#include <machine/cpu.h>
#ifdef DEV_PSCI
#include <dev/psci/psci.h>
#endif
typedef void (cpu_quirk_install)(void);
struct cpu_quirks {
cpu_quirk_install *quirk_install;
@ -49,8 +55,37 @@ struct cpu_quirks {
static cpu_quirk_install install_psci_bp_hardening;
static struct cpu_quirks cpu_quirks[] = {
{
.midr_mask = CPU_IMPL_MASK | CPU_PART_MASK,
.midr_value = CPU_ID_RAW(CPU_IMPL_ARM, CPU_PART_CORTEX_A57,0,0),
.quirk_install = install_psci_bp_hardening,
},
{
.midr_mask = CPU_IMPL_MASK | CPU_PART_MASK,
.midr_value = CPU_ID_RAW(CPU_IMPL_ARM, CPU_PART_CORTEX_A72,0,0),
.quirk_install = install_psci_bp_hardening,
},
{
.midr_mask = CPU_IMPL_MASK | CPU_PART_MASK,
.midr_value = CPU_ID_RAW(CPU_IMPL_ARM, CPU_PART_CORTEX_A73,0,0),
.quirk_install = install_psci_bp_hardening,
},
{
.midr_mask = CPU_IMPL_MASK | CPU_PART_MASK,
.midr_value = CPU_ID_RAW(CPU_IMPL_ARM, CPU_PART_CORTEX_A75,0,0),
.quirk_install = install_psci_bp_hardening,
},
};
static void
install_psci_bp_hardening(void)
{
#ifdef DEV_PSCI
PCPU_SET(bp_harden, psci_get_version);
#endif
}
void
install_cpu_errata(void)
{

View File

@ -4663,6 +4663,7 @@ pmap_activate(struct thread *td)
struct pcb *
pmap_switch(struct thread *old, struct thread *new)
{
pcpu_bp_harden bp_harden;
struct pcb *pcb;
/* Store the new curthread */
@ -4690,6 +4691,15 @@ pmap_switch(struct thread *old, struct thread *new)
"dsb ish \n"
"isb \n"
: : "r"(new->td_proc->p_md.md_l0addr));
/*
* Stop userspace from training the branch predictor against
* other processes. This will call into a CPU specific
* function that clears the branch predictor state.
*/
bp_harden = PCPU_GET(bp_harden);
if (bp_harden != NULL)
bp_harden();
}
return (pcb);

View File

@ -352,6 +352,7 @@ do_el1h_sync(struct thread *td, struct trapframe *frame)
void
do_el0_sync(struct thread *td, struct trapframe *frame)
{
pcpu_bp_harden bp_harden;
uint32_t exception;
uint64_t esr, far;
@ -363,11 +364,25 @@ do_el0_sync(struct thread *td, struct trapframe *frame)
esr = frame->tf_esr;
exception = ESR_ELx_EXCEPTION(esr);
switch (exception) {
case EXCP_UNKNOWN:
case EXCP_INSN_ABORT_L:
far = READ_SPECIALREG(far_el1);
/*
* Userspace may be trying to train the branch predictor to
* attack the kernel. If we are on a CPU affected by this
* call the handler to clear the branch predictor state.
*/
if (far > VM_MAXUSER_ADDRESS) {
bp_harden = PCPU_GET(bp_harden);
if (bp_harden != NULL)
bp_harden();
}
break;
case EXCP_UNKNOWN:
case EXCP_DATA_ABORT_L:
case EXCP_DATA_ABORT:
far = READ_SPECIALREG(far_el1);
break;
}
intr_enable();

View File

@ -35,11 +35,14 @@
#define ALT_STACK_SIZE 128
typedef int (*pcpu_bp_harden)(void);
#define PCPU_MD_FIELDS \
u_int pc_acpi_id; /* ACPI CPU id */ \
u_int pc_midr; /* stored MIDR value */ \
uint64_t pc_clock; \
char __pad[241]
pcpu_bp_harden pc_bp_harden; \
char __pad[233]
#ifdef _KERNEL