Module Name:    src
Committed By:   maxv
Date:           Tue May 22 07:11:54 UTC 2018

Modified Files:
        src/sys/arch/x86/include: specialreg.h
        src/sys/arch/x86/x86: spectre.c x86_machdep.c

Log Message:
Mitigation for SpectreV4, based on SSBD. The following sysctl branches
are added:

        machdep.spectre_v4.mitigated = {0/1} user-settable
        machdep.spectre_v4.affected = {0/1} set by the kernel

The mitigation is not enabled by default yet. It is not tested either,
because no microcode update has been published yet.

On current CPUs a microcode/bios update must be applied for SSBD to be
available. The user can then set mitigated=1. Even with an update applied
the kernel will set affected=1.

On future CPUs, where the problem will presumably be fixed by default,
the CPU will report SSB_NO, and the kernel will set affected=0. In this
case we also have mitigated=0, but the mitigation is not needed.

For now the feature is system-wide. Perhaps we will want a more
fine-grained, per-process approach in the future.


To generate a diff of this commit:
cvs rdiff -u -r1.120 -r1.121 src/sys/arch/x86/include/specialreg.h
cvs rdiff -u -r1.11 -r1.12 src/sys/arch/x86/x86/spectre.c
cvs rdiff -u -r1.112 -r1.113 src/sys/arch/x86/x86/x86_machdep.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/arch/x86/include/specialreg.h
diff -u src/sys/arch/x86/include/specialreg.h:1.120 src/sys/arch/x86/include/specialreg.h:1.121
--- src/sys/arch/x86/include/specialreg.h:1.120	Fri Mar 30 19:49:49 2018
+++ src/sys/arch/x86/include/specialreg.h	Tue May 22 07:11:53 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: specialreg.h,v 1.120 2018/03/30 19:49:49 maxv Exp $	*/
+/*	$NetBSD: specialreg.h,v 1.121 2018/05/22 07:11:53 maxv Exp $	*/
 
 /*-
  * Copyright (c) 1991 The Regents of the University of California.
@@ -405,11 +405,11 @@
 #define CPUID_SEF_IBRS		__BIT(26) /* IBRS / IBPB Speculation Control */
 #define CPUID_SEF_STIBP		__BIT(27) /* STIBP Speculation Control */
 #define CPUID_SEF_ARCH_CAP	__BIT(29) /* IA32_ARCH_CAPABILITIES */
+#define CPUID_SEF_SSBD		__BIT(31) /* Speculative Store Bypass Disable */
 
-#define CPUID_SEF_FLAGS2	"\20" \
-				"\3" "AVX512_4VNNIW" "\4" "AVX512_4FMAPS" \
-					"\33" "IBRS"	"\34" "STIBP"	\
-			"\36" "ARCH_CAP"
+#define CPUID_SEF_FLAGS2	\
+	"\20" "\3" "AVX512_4VNNIW" "\4" "AVX512_4FMAPS" \
+	"\33" "IBRS" "\34" "STIBP" "\36" "ARCH_CAP" "\38" "SSBD"
 
 /*
  * CPUID Processor extended state Enumeration Fn0000000d
@@ -643,6 +643,7 @@
 #define MSR_IA32_SPEC_CTRL	0x048
 #define 	IA32_SPEC_CTRL_IBRS	0x01
 #define 	IA32_SPEC_CTRL_STIBP	0x02
+#define 	IA32_SPEC_CTRL_SSBD	0x04
 #define MSR_IA32_PRED_CMD	0x049
 #define 	IA32_PRED_CMD_IBPB	0x01
 #define MSR_BIOS_UPDT_TRIG	0x079
@@ -660,6 +661,7 @@
 #define MSR_IA32_ARCH_CAPABILITIES 0x10a
 #define 	IA32_ARCH_RDCL_NO	0x01
 #define 	IA32_ARCH_IBRS_ALL	0x02
+#define 	IA32_ARCH_SSB_NO	0x10
 #define MSR_BBL_CR_ADDR		0x116	/* PII+ only */
 #define MSR_BBL_CR_DECC		0x118	/* PII+ only */
 #define MSR_BBL_CR_CTL		0x119	/* PII+ only */

Index: src/sys/arch/x86/x86/spectre.c
diff -u src/sys/arch/x86/x86/spectre.c:1.11 src/sys/arch/x86/x86/spectre.c:1.12
--- src/sys/arch/x86/x86/spectre.c:1.11	Tue May 22 06:31:05 2018
+++ src/sys/arch/x86/x86/spectre.c	Tue May 22 07:11:53 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: spectre.c,v 1.11 2018/05/22 06:31:05 maxv Exp $	*/
+/*	$NetBSD: spectre.c,v 1.12 2018/05/22 07:11:53 maxv Exp $	*/
 
 /*
  * Copyright (c) 2018 NetBSD Foundation, Inc.
@@ -34,7 +34,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: spectre.c,v 1.11 2018/05/22 06:31:05 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: spectre.c,v 1.12 2018/05/22 07:11:53 maxv Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -347,6 +347,140 @@ sysctl_machdep_spectreV2_mitigated(SYSCT
 
 /* -------------------------------------------------------------------------- */
 
+bool spec_v4_mitigation_enabled __read_mostly = false;
+bool spec_v4_affected __read_mostly = true;
+
+int sysctl_machdep_spectreV4_mitigated(SYSCTLFN_ARGS);
+
+static bool ssbd_needed(void)
+{
+	uint64_t msr;
+
+	if (cpu_info_primary.ci_feat_val[7] & CPUID_SEF_ARCH_CAP) {
+		msr = rdmsr(MSR_IA32_ARCH_CAPABILITIES);
+		if (msr & IA32_ARCH_SSB_NO) {
+			/*
+			 * The processor indicates it is not vulnerable to the
+			 * Speculative Store Bypass (SpectreV4) flaw.
+			 */
+			return false;
+		}
+	}
+
+	return true;
+}
+
+static bool ssbd_supported(void)
+{
+	u_int descs[4];
+
+	if (cpu_vendor == CPUVENDOR_INTEL) {
+		if (cpuid_level >= 7) {
+			x86_cpuid(7, descs);
+			if (descs[3] & CPUID_SEF_SSBD) {
+				/* descs[3] = %edx */
+				return true;
+			}
+		}
+	}
+	return false;
+}
+
+static void
+mitigation_v4_apply_cpu(bool enabled)
+{
+	uint64_t msr;
+
+	msr = rdmsr(MSR_IA32_SPEC_CTRL);
+
+	if (enabled) {
+		msr |= IA32_SPEC_CTRL_SSBD;
+	} else {
+		msr &= ~IA32_SPEC_CTRL_SSBD;
+	}
+
+	wrmsr(MSR_IA32_SPEC_CTRL, msr);
+}
+
+static void
+mitigation_v4_change_cpu(void *arg1, void *arg2)
+{
+	bool enabled = (bool)arg1;
+
+	mitigation_v4_apply_cpu(enabled);
+}
+
+static int mitigation_v4_change(bool enabled)
+{
+	struct cpu_info *ci = NULL;
+	CPU_INFO_ITERATOR cii;
+	uint64_t xc;
+
+	if (!ssbd_supported()) {
+			printf("[!] No mitigation available\n");
+			return EOPNOTSUPP;
+	}
+
+	mutex_enter(&cpu_lock);
+
+	/*
+	 * We expect all the CPUs to be online.
+	 */
+	for (CPU_INFO_FOREACH(cii, ci)) {
+		struct schedstate_percpu *spc = &ci->ci_schedstate;
+		if (spc->spc_flags & SPCF_OFFLINE) {
+			printf("[!] cpu%d offline, SpectreV4 not changed\n",
+			    cpu_index(ci));
+			mutex_exit(&cpu_lock);
+			return EOPNOTSUPP;
+		}
+	}
+
+	printf("[+] %s SpectreV4 Mitigation...",
+	    enabled ? "Enabling" : "Disabling");
+	xc = xc_broadcast(0, mitigation_v4_change_cpu,
+	    (void *)enabled, NULL);
+	xc_wait(xc);
+	printf(" done!\n");
+	spec_v4_mitigation_enabled = enabled;
+	mutex_exit(&cpu_lock);
+
+	return 0;
+}
+
+int
+sysctl_machdep_spectreV4_mitigated(SYSCTLFN_ARGS)
+{
+	struct sysctlnode node;
+	int error;
+	bool val;
+
+	val = *(bool *)rnode->sysctl_data;
+
+	node = *rnode;
+	node.sysctl_data = &val;
+
+	error = sysctl_lookup(SYSCTLFN_CALL(&node));
+	if (error != 0 || newp == NULL)
+		return error;
+
+	if (val == 0) {
+		if (!spec_v4_mitigation_enabled)
+			error = 0;
+		else
+			error = mitigation_v4_change(false);
+	} else {
+		if (spec_v4_mitigation_enabled)
+			error = 0;
+		else
+			error = mitigation_v4_change(true);
+	}
+
+	return error;
+}
+
+/* -------------------------------------------------------------------------- */
+
 void speculation_barrier(struct lwp *, struct lwp *);
 
 void
@@ -393,4 +527,15 @@ cpu_speculation_init(struct cpu_info *ci
 	if (mitigation_v2_method != MITIGATION_NONE) {
 		mitigation_v2_apply_cpu(ci, true);
 	}
+
+	/*
+	 * Spectre V4.
+	 */
+	if (ssbd_needed()) {
+		if (ci == &cpu_info_primary) {
+			spec_v4_affected = true;
+		}
+		/* mitigation_v4_apply_cpu(true); */
+		/* spec_v4_mitigation_enabled = true; */
+	}
 }

Index: src/sys/arch/x86/x86/x86_machdep.c
diff -u src/sys/arch/x86/x86/x86_machdep.c:1.112 src/sys/arch/x86/x86/x86_machdep.c:1.113
--- src/sys/arch/x86/x86/x86_machdep.c:1.112	Tue May 22 06:31:05 2018
+++ src/sys/arch/x86/x86/x86_machdep.c	Tue May 22 07:11:53 2018
@@ -1,4 +1,4 @@
-/*	$NetBSD: x86_machdep.c,v 1.112 2018/05/22 06:31:05 maxv Exp $	*/
+/*	$NetBSD: x86_machdep.c,v 1.113 2018/05/22 07:11:53 maxv Exp $	*/
 
 /*-
  * Copyright (c) 2002, 2006, 2007 YAMAMOTO Takashi,
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: x86_machdep.c,v 1.112 2018/05/22 06:31:05 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: x86_machdep.c,v 1.113 2018/05/22 07:11:53 maxv Exp $");
 
 #include "opt_modular.h"
 #include "opt_physmem.h"
@@ -1273,8 +1273,11 @@ SYSCTL_SETUP(sysctl_machdep_setup, "sysc
 
 #ifndef XEN
 	int sysctl_machdep_spectreV2_mitigated(SYSCTLFN_ARGS);
+	int sysctl_machdep_spectreV4_mitigated(SYSCTLFN_ARGS);
 	extern bool spec_v2_mitigation_enabled;
+	extern bool spec_v4_mitigation_enabled;
 	extern char spec_v2_mitigation_name[];
+	extern bool spec_v4_affected;
 	const struct sysctlnode *spec_rnode;
 
 	/* SpectreV1 */
@@ -1312,6 +1315,28 @@ SYSCTL_SETUP(sysctl_machdep_setup, "sysc
 		       NULL, 0,
 		       spec_v2_mitigation_name, 0,
 		       CTL_CREATE, CTL_EOL);
+
+	/* SpectreV4 */
+	spec_rnode = NULL;
+	sysctl_createv(clog, 0, NULL, &spec_rnode,
+		       CTLFLAG_PERMANENT,
+		       CTLTYPE_NODE, "spectre_v4", NULL,
+		       NULL, 0, NULL, 0,
+		       CTL_MACHDEP, CTL_CREATE);
+	sysctl_createv(clog, 0, &spec_rnode, NULL,
+		       CTLFLAG_READWRITE,
+		       CTLTYPE_BOOL, "mitigated",
+		       SYSCTL_DESCR("Whether Spectre Variant 4 is mitigated"),
+		       sysctl_machdep_spectreV4_mitigated, 0,
+		       &spec_v4_mitigation_enabled, 0,
+		       CTL_CREATE, CTL_EOL);
+	sysctl_createv(clog, 0, &spec_rnode, NULL,
+		       CTLFLAG_PERMANENT,
+		       CTLTYPE_BOOL, "affected",
+		       SYSCTL_DESCR("Whether the CPU is affected by SpectreV4"),
+		       NULL, 0,
+	           &spec_v4_affected, 0,
+		       CTL_CREATE, CTL_EOL);
 #endif
 
 	/* None of these can ever change once the system has booted */

Reply via email to