Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 4 Apr 2018 06:11:06 +0000 (UTC)
From:      Michal Meloun <mmel@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org
Subject:   svn commit: r331988 - in stable/11/sys/arm: arm include
Message-ID:  <201804040611.w346B6Xq054410@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mmel
Date: Wed Apr  4 06:11:05 2018
New Revision: 331988
URL: https://svnweb.freebsd.org/changeset/base/331988

Log:
  MFC r328467:
  
    Implement mitigation for Spectre version 2 attacks on ARMv7.

Modified:
  stable/11/sys/arm/arm/cpuinfo.c
  stable/11/sys/arm/arm/genassym.c
  stable/11/sys/arm/arm/machdep.c
  stable/11/sys/arm/arm/mp_machdep.c
  stable/11/sys/arm/arm/swtch-v6.S
  stable/11/sys/arm/arm/trap-v6.c
  stable/11/sys/arm/include/cpuinfo.h
  stable/11/sys/arm/include/pcpu.h
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sys/arm/arm/cpuinfo.c
==============================================================================
--- stable/11/sys/arm/arm/cpuinfo.c	Wed Apr  4 05:43:03 2018	(r331987)
+++ stable/11/sys/arm/arm/cpuinfo.c	Wed Apr  4 06:11:05 2018	(r331988)
@@ -31,6 +31,8 @@ __FBSDID("$FreeBSD$");
 #include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/kernel.h>
+#include <sys/pcpu.h>
+#include <sys/smp.h>
 #include <sys/sysctl.h>
 
 #include <machine/cpu.h>
@@ -40,6 +42,9 @@ __FBSDID("$FreeBSD$");
 
 #if __ARM_ARCH >= 6
 void reinit_mmu(uint32_t ttb, uint32_t aux_clr, uint32_t aux_set);
+
+int disable_bp_hardening;
+int spectre_v2_safe = 1;
 #endif
 
 struct cpuinfo cpuinfo =
@@ -253,6 +258,7 @@ cpuinfo_get_actlr_modifier(uint32_t *actlr_mask, uint3
 
 	if (cpuinfo.implementer == CPU_IMPLEMENTER_ARM) {
 		switch (cpuinfo.part_number) {
+		case CPU_ARCH_CORTEX_A75:
 		case CPU_ARCH_CORTEX_A73:
 		case CPU_ARCH_CORTEX_A72:
 		case CPU_ARCH_CORTEX_A57:
@@ -335,5 +341,198 @@ cpuinfo_reinit_mmu(uint32_t ttb)
 	actlr_set |= cpu_quirks_actlr_set;
 	reinit_mmu(ttb, actlr_mask, actlr_set);
 }
+
+static bool
+modify_actlr(uint32_t clear, uint32_t set)
+{
+	uint32_t reg, newreg;
+
+	reg = cp15_actlr_get();
+	newreg = reg;
+	newreg &= ~clear;
+	newreg |= set;
+	if (reg == newreg)
+		return (true);
+	cp15_actlr_set(newreg);
+
+	reg = cp15_actlr_get();
+	if (reg == newreg)
+		return (true);
+	return (false);
+}
+
+/* Apply/restore BP hardening on current core. */
+static int
+apply_bp_hardening(bool enable, int kind, bool actrl, uint32_t set_mask)
+{
+	if (enable) {
+		if (actrl && !modify_actlr(0, set_mask))
+			return (-1);
+		PCPU_SET(bp_harden_kind, kind);
+	} else {
+		PCPU_SET(bp_harden_kind, PCPU_BP_HARDEN_KIND_NONE);
+		if (actrl)
+			modify_actlr(~0, PCPU_GET(original_actlr));
+		spectre_v2_safe = 0;
+	}
+	return (0);
+}
+
+static void
+handle_bp_hardening(bool enable)
+{
+	int kind;
+	char *kind_str;
+
+	kind = PCPU_BP_HARDEN_KIND_NONE;
+	/*
+	 * Note: Access to ACTRL is locked to secure world on most boards.
+	 * This means that full BP hardening depends on updated u-boot/firmware
+	 * or is impossible at all (if secure monitor is in on-chip ROM).
+	 */
+	if (cpuinfo.implementer == CPU_IMPLEMENTER_ARM) {
+		switch (cpuinfo.part_number) {
+		case CPU_ARCH_CORTEX_A8:
+			/*
+			 * For Cortex-A8, IBE bit must be set otherwise
+			 * BPIALL is effectively NOP.
+			 * Unfortunately, Cortex-A is also affected by
+			 * ARM erratum 687067 which causes non-working
+			 * BPIALL if IBE bit is set and 'Instruction L1 System
+			 * Array Debug Register 0' is not 0.
+			 * This register is not reset on power-up and is
+			 * accessible only from secure world, so we cannot do
+			 * nothing (nor detect) to fix this issue.
+			 * I afraid that on chip ROM based secure monitor on
+			 * AM335x (BeagleBone) doesn't reset this debug
+			 * register.
+			 */
+			kind = PCPU_BP_HARDEN_KIND_BPIALL;
+			if (apply_bp_hardening(enable, kind, true, 1 << 6) != 0)
+				goto actlr_err;
+			break;
+		break;
+
+		case CPU_ARCH_CORTEX_A9:
+		case CPU_ARCH_CORTEX_A12:
+		case CPU_ARCH_CORTEX_A17:
+		case CPU_ARCH_CORTEX_A57:
+		case CPU_ARCH_CORTEX_A72:
+		case CPU_ARCH_CORTEX_A73:
+		case CPU_ARCH_CORTEX_A75:
+			kind = PCPU_BP_HARDEN_KIND_BPIALL;
+			if (apply_bp_hardening(enable, kind, false, 0) != 0)
+				goto actlr_err;
+			break;
+
+		case CPU_ARCH_CORTEX_A15:
+			/*
+			 * For Cortex-A15, set 'Enable invalidates of BTB' bit.
+			 * Despite this, the BPIALL is still effectively NOP,
+			 * but with this bit set, the ICIALLU also flushes
+			 * branch predictor as side effect.
+			 */
+			kind = PCPU_BP_HARDEN_KIND_ICIALLU;
+			if (apply_bp_hardening(enable, kind, true, 1 << 0) != 0)
+				goto actlr_err;
+			break;
+
+		default:
+			break;
+		}
+	} else if (cpuinfo.implementer == CPU_IMPLEMENTER_QCOM) {
+		printf("!!!WARNING!!! CPU(%d) is vulnerable to speculative "
+		    "branch attacks. !!!\n"
+		    "Qualcomm Krait cores are known (or believed) to be "
+		    "vulnerable to \n"
+		    "speculative branch attacks, no mitigation exists yet.\n",
+		    PCPU_GET(cpuid));
+		goto unkonown_mitigation;
+	}  else {
+		goto unkonown_mitigation;
+	}
+
+	if (bootverbose) {
+		switch (kind) {
+		case PCPU_BP_HARDEN_KIND_NONE:
+			kind_str = "not necessary";
+			break;
+		case PCPU_BP_HARDEN_KIND_BPIALL:
+			kind_str = "BPIALL";
+			break;
+		case PCPU_BP_HARDEN_KIND_ICIALLU:
+			kind_str = "ICIALLU";
+			break;
+		default:
+			panic("Unknown BP hardering kind (%d).", kind);
+		}
+		printf("CPU(%d) applied BP hardening: %s\n", PCPU_GET(cpuid),
+		    kind_str);
+	}
+
+	return;
+
+unkonown_mitigation:
+	PCPU_SET(bp_harden_kind, PCPU_BP_HARDEN_KIND_NONE);
+	spectre_v2_safe = 0;
+	return;
+
+actlr_err:
+	PCPU_SET(bp_harden_kind, PCPU_BP_HARDEN_KIND_NONE);
+	spectre_v2_safe = 0;
+	printf("!!!WARNING!!! CPU(%d) is vulnerable to speculative branch "
+	    "attacks. !!!\n"
+	    "We cannot enable required bit(s) in ACTRL register\n"
+	    "because it's locked by secure monitor and/or firmware.\n",
+	    PCPU_GET(cpuid));
+}
+
+void
+cpuinfo_init_bp_hardening(void)
+{
+
+	/*
+	 * Store original unmodified ACTRL, so we can restore it when
+	 * BP hardening is disabled by sysctl.
+	 */
+	PCPU_SET(original_actlr, cp15_actlr_get());
+	handle_bp_hardening(true);
+}
+
+static void
+bp_hardening_action(void *arg)
+{
+
+	handle_bp_hardening(disable_bp_hardening == 0);
+}
+
+static int
+sysctl_disable_bp_hardening(SYSCTL_HANDLER_ARGS)
+{
+	int rv;
+
+	rv = sysctl_handle_int(oidp, oidp->oid_arg1, oidp->oid_arg2, req);
+
+	if (!rv && req->newptr) {
+		spectre_v2_safe = 1;
+		dmb();
+#ifdef SMP
+		smp_rendezvous_cpus(all_cpus, smp_no_rendezvous_barrier,
+		bp_hardening_action, NULL, NULL);
+#else
+		bp_hardening_action(NULL);
+#endif
+	}
+
+	return (rv);
+}
+
+SYSCTL_PROC(_machdep, OID_AUTO, disable_bp_hardening,
+    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
+    &disable_bp_hardening, 0, sysctl_disable_bp_hardening, "I",
+    "Disable BP hardening mitigation.");
+
+SYSCTL_INT(_machdep, OID_AUTO, spectre_v2_safe, CTLFLAG_RD,
+    &spectre_v2_safe, 0, "System is safe to Spectre Version 2 attacks");
 
 #endif /* __ARM_ARCH >= 6 */

Modified: stable/11/sys/arm/arm/genassym.c
==============================================================================
--- stable/11/sys/arm/arm/genassym.c	Wed Apr  4 05:43:03 2018	(r331987)
+++ stable/11/sys/arm/arm/genassym.c	Wed Apr  4 06:11:05 2018	(r331988)
@@ -31,6 +31,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/cpuset.h>
 #include <sys/systm.h>
 #include <sys/assym.h>
+#include <sys/pcpu.h>
 #include <sys/proc.h>
 #include <sys/mbuf.h>
 #include <sys/vmmeter.h>
@@ -134,6 +135,10 @@ ASSYM(PCB_VFPSTATE, offsetof(struct pcb, pcb_vfpstate)
 
 #if __ARM_ARCH >= 6
 ASSYM(PC_CURPMAP, offsetof(struct pcpu, pc_curpmap));
+ASSYM(PC_BP_HARDEN_KIND, offsetof(struct pcpu, pc_bp_harden_kind));
+ASSYM(PCPU_BP_HARDEN_KIND_NONE, PCPU_BP_HARDEN_KIND_NONE);
+ASSYM(PCPU_BP_HARDEN_KIND_BPIALL, PCPU_BP_HARDEN_KIND_BPIALL);
+ASSYM(PCPU_BP_HARDEN_KIND_ICIALLU, PCPU_BP_HARDEN_KIND_ICIALLU);
 #endif
 
 ASSYM(PAGE_SIZE, PAGE_SIZE);

Modified: stable/11/sys/arm/arm/machdep.c
==============================================================================
--- stable/11/sys/arm/arm/machdep.c	Wed Apr  4 05:43:03 2018	(r331987)
+++ stable/11/sys/arm/arm/machdep.c	Wed Apr  4 06:11:05 2018	(r331988)
@@ -1260,6 +1260,8 @@ initarm(struct arm_boot_params *abp)
 	msgbufinit(msgbufp, msgbufsize);
 	dbg_monitor_init();
 	arm_kdb_init();
+	/* Apply possible BP hardening. */
+	cpuinfo_init_bp_hardening();
 	return ((void *)STACKALIGN(thread0.td_pcb));
 
 }

Modified: stable/11/sys/arm/arm/mp_machdep.c
==============================================================================
--- stable/11/sys/arm/arm/mp_machdep.c	Wed Apr  4 05:43:03 2018	(r331987)
+++ stable/11/sys/arm/arm/mp_machdep.c	Wed Apr  4 06:11:05 2018	(r331988)
@@ -200,6 +200,9 @@ init_secondary(int cpu)
 	/* Configure the interrupt controller */
 	intr_pic_init_secondary();
 
+	/* Apply possible BP hardening */
+	cpuinfo_init_bp_hardening();
+
 	mtx_lock_spin(&ap_boot_mtx);
 
 	atomic_add_rel_32(&smp_cpus, 1);

Modified: stable/11/sys/arm/arm/swtch-v6.S
==============================================================================
--- stable/11/sys/arm/arm/swtch-v6.S	Wed Apr  4 05:43:03 2018	(r331987)
+++ stable/11/sys/arm/arm/swtch-v6.S	Wed Apr  4 06:11:05 2018	(r331988)
@@ -145,7 +145,16 @@ ENTRY(cpu_context_switch)
 	* predictors and Requirements for branch predictor maintenance
 	* operations sections.
 	*/
-	mcr	CP15_BPIALL		/* flush entire Branch Target Cache */
+	/*
+	 * Additionally, to mitigate mistrained branch predictor attack
+	 * we must invalidate it on affected CPUs. Unfortunately, BPIALL
+	 * is effectively NOP on Cortex-A15 so it needs special treatment.
+	 */
+	ldr	r0, [r8, #PC_BP_HARDEN_KIND]
+	cmp	r0, #PCPU_BP_HARDEN_KIND_ICIALLU
+	mcrne	CP15_BPIALL		/* Flush entire Branch Target Cache   */
+	mcreq	CP15_ICIALLU		/* This is the only way how to flush  */
+					/* Branch Target Cache on Cortex-A15. */
 	DSB
 	mov	pc, lr
 END(cpu_context_switch)

Modified: stable/11/sys/arm/arm/trap-v6.c
==============================================================================
--- stable/11/sys/arm/arm/trap-v6.c	Wed Apr  4 05:43:03 2018	(r331987)
+++ stable/11/sys/arm/arm/trap-v6.c	Wed Apr  4 06:11:05 2018	(r331988)
@@ -287,6 +287,7 @@ abort_handler(struct trapframe *tf, int prefetch)
 	struct vmspace *vm;
 	vm_prot_t ftype;
 	bool usermode;
+	int bp_harden;
 #ifdef INVARIANTS
 	void *onfault;
 #endif
@@ -303,6 +304,20 @@ abort_handler(struct trapframe *tf, int prefetch)
 
 	idx = FSR_TO_FAULT(fsr);
 	usermode = TRAPF_USERMODE(tf);	/* Abort came from user mode? */
+
+	/*
+	 * Apply BP hardening by flushing the branch prediction cache
+	 * for prefaults on kernel addresses.
+	 */
+	if (__predict_false(prefetch && far > VM_MAXUSER_ADDRESS &&
+	    (idx == FAULT_TRAN_L2 || idx == FAULT_PERM_L2))) {
+		bp_harden = PCPU_GET(bp_harden_kind);
+		if (bp_harden == PCPU_BP_HARDEN_KIND_BPIALL)
+			_CP15_BPIALL();
+		else if (bp_harden == PCPU_BP_HARDEN_KIND_ICIALLU)
+			_CP15_ICIALLU();
+	}
+
 	if (usermode)
 		td->td_frame = tf;
 

Modified: stable/11/sys/arm/include/cpuinfo.h
==============================================================================
--- stable/11/sys/arm/include/cpuinfo.h	Wed Apr  4 05:43:03 2018	(r331987)
+++ stable/11/sys/arm/include/cpuinfo.h	Wed Apr  4 06:11:05 2018	(r331988)
@@ -49,6 +49,7 @@
 #define CPU_ARCH_CORTEX_A57		0xD07
 #define CPU_ARCH_CORTEX_A72		0xD08
 #define CPU_ARCH_CORTEX_A73		0xD09
+#define CPU_ARCH_CORTEX_A75		0xD0A
 
 
 /* QCOM */
@@ -122,6 +123,7 @@ extern struct cpuinfo cpuinfo;
 
 void cpuinfo_init(void);
 #if __ARM_ARCH >= 6
+void cpuinfo_init_bp_hardening(void);
 void cpuinfo_reinit_mmu(uint32_t ttb);
 #endif
 #endif	/* _MACHINE_CPUINFO_H_ */

Modified: stable/11/sys/arm/include/pcpu.h
==============================================================================
--- stable/11/sys/arm/include/pcpu.h	Wed Apr  4 05:43:03 2018	(r331987)
+++ stable/11/sys/arm/include/pcpu.h	Wed Apr  4 06:11:05 2018	(r331988)
@@ -42,6 +42,10 @@ struct vmspace;
 #endif	/* _KERNEL */
 
 #if __ARM_ARCH >= 6
+/* Branch predictor hardening method */
+#define PCPU_BP_HARDEN_KIND_NONE		0
+#define PCPU_BP_HARDEN_KIND_BPIALL		1
+#define PCPU_BP_HARDEN_KIND_ICIALLU		2
 
 #define PCPU_MD_FIELDS							\
 	unsigned int pc_vfpsid;						\
@@ -57,7 +61,9 @@ struct vmspace;
 	void *pc_qmap_pte2p;						\
 	unsigned int pc_dbreg[32];					\
 	int pc_dbreg_cmd;						\
-	char __pad[19]
+	int pc_bp_harden_kind;						\
+	uint32_t pc_original_actlr;					\
+	char __pad[11]
 #else
 #define PCPU_MD_FIELDS							\
 	char __pad[157]



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201804040611.w346B6Xq054410>