Module Name:    src
Committed By:   martin
Date:           Tue Nov 12 18:24:37 UTC 2019

Modified Files:
        src/sys/arch/x86/include [netbsd-9]: specialreg.h
        src/sys/arch/x86/x86 [netbsd-9]: spectre.c

Log Message:
Pull up following revision(s) (requested by maxv in ticket #419):

        sys/arch/x86/include/specialreg.h: revision 1.157
        sys/arch/x86/x86/spectre.c: revision 1.31

Mitigation for CVE-2019-11135: TSX Asynchronous Abort (TAA).

Two sysctls are added:
        machdep.taa.mitigated = {0/1} user-settable
        machdep.taa.method = {string} constructed by the kernel

There are two cases:

  (1) If the CPU is affected by MDS, then the MDS mitigation will also
mitigate TAA, and we have nothing else to do. We make the 'mitigated' leaf
read-only, and force:

        machdep.taa.mitigated = machdep.mds.mitigated
        machdep.taa.method = [MDS]

The kernel already enables the MDS mitigation by default.

  (2) If the CPU is not affected by MDS but is affected by TAA, then we use
the new TSX_CTRL MSR to disable RTM. This MSR is provided via a microcode
update, now available on the Intel website. The kernel will automatically
enable the TAA mitigation if the updated microcode is present. If the new
microcode is not present, the user can load it via cpuctl, and set
machdep.taa.mitigated=1.


To generate a diff of this commit:
cvs rdiff -u -r1.150.2.3 -r1.150.2.4 src/sys/arch/x86/include/specialreg.h
cvs rdiff -u -r1.29.2.1 -r1.29.2.2 src/sys/arch/x86/x86/spectre.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.150.2.3 src/sys/arch/x86/include/specialreg.h:1.150.2.4
--- src/sys/arch/x86/include/specialreg.h:1.150.2.3	Sun Nov 10 13:06:46 2019
+++ src/sys/arch/x86/include/specialreg.h	Tue Nov 12 18:24:37 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: specialreg.h,v 1.150.2.3 2019/11/10 13:06:46 martin Exp $	*/
+/*	$NetBSD: specialreg.h,v 1.150.2.4 2019/11/12 18:24:37 martin Exp $	*/
 
 /*
  * Copyright (c) 2014-2019 The NetBSD Foundation, Inc.
@@ -853,9 +853,14 @@
 #define 	IA32_ARCH_SKIP_L1DFL_VMENTRY 0x08
 #define 	IA32_ARCH_SSB_NO	0x10
 #define 	IA32_ARCH_MDS_NO	0x20
+#define 	IA32_ARCH_TSX_CTRL	0x80
+#define 	IA32_ARCH_TAA_NO	0x100
 #define MSR_IA32_FLUSH_CMD	0x10b
 #define 	IA32_FLUSH_CMD_L1D_FLUSH 0x01
 #define MSR_TSX_FORCE_ABORT	0x10f
+#define MSR_IA32_TSX_CTRL	0x122
+#define 	IA32_TSX_CTRL_RTM_DISABLE	__BIT(0)
+#define 	IA32_TSX_CTRL_TSX_CPUID_CLEAR	__BIT(1)
 #define MSR_SYSENTER_CS		0x174	/* PII+ only */
 #define MSR_SYSENTER_ESP	0x175	/* PII+ only */
 #define MSR_SYSENTER_EIP	0x176	/* PII+ only */

Index: src/sys/arch/x86/x86/spectre.c
diff -u src/sys/arch/x86/x86/spectre.c:1.29.2.1 src/sys/arch/x86/x86/spectre.c:1.29.2.2
--- src/sys/arch/x86/x86/spectre.c:1.29.2.1	Thu Sep 26 18:47:14 2019
+++ src/sys/arch/x86/x86/spectre.c	Tue Nov 12 18:24:37 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: spectre.c,v 1.29.2.1 2019/09/26 18:47:14 martin Exp $	*/
+/*	$NetBSD: spectre.c,v 1.29.2.2 2019/11/12 18:24:37 martin Exp $	*/
 
 /*
  * Copyright (c) 2018-2019 NetBSD Foundation, Inc.
@@ -30,11 +30,11 @@
  */
 
 /*
- * Mitigations for the SpectreV2, SpectreV4 and MDS CPU flaws.
+ * Mitigations for the SpectreV2, SpectreV4, MDS and TAA CPU flaws.
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: spectre.c,v 1.29.2.1 2019/09/26 18:47:14 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: spectre.c,v 1.29.2.2 2019/11/12 18:24:37 martin Exp $");
 
 #include "opt_spectre.h"
 
@@ -773,6 +773,185 @@ sysctl_machdep_mds_mitigated(SYSCTLFN_AR
 
 /* -------------------------------------------------------------------------- */
 
+enum taa_mitigation {
+	TAA_MITIGATION_NONE,
+	TAA_MITIGATION_TAA_NO,
+	TAA_MITIGATION_MDS,
+	TAA_MITIGATION_RTM_DISABLE
+};
+
+static char taa_mitigation_name[64] = "(none)";
+
+static enum taa_mitigation taa_mitigation_method = TAA_MITIGATION_NONE;
+static bool taa_mitigation_enabled __read_mostly = false;
+static bool *taa_mitigation_enabled_ptr = &taa_mitigation_enabled;
+
+static void
+mitigation_taa_apply_cpu(struct cpu_info *ci, bool enabled)
+{
+	uint64_t msr;
+
+	switch (taa_mitigation_method) {
+	case TAA_MITIGATION_NONE:
+	case TAA_MITIGATION_TAA_NO:
+	case TAA_MITIGATION_MDS:
+		panic("impossible");
+	case TAA_MITIGATION_RTM_DISABLE:
+		msr = rdmsr(MSR_IA32_TSX_CTRL);
+		if (enabled) {
+			msr |= IA32_TSX_CTRL_RTM_DISABLE;
+		} else {
+			msr &= ~IA32_TSX_CTRL_RTM_DISABLE;
+		}
+		wrmsr(MSR_IA32_TSX_CTRL, msr);
+		break;
+	}
+}
+
+static void
+mitigation_taa_change_cpu(void *arg1, void *arg2)
+{
+	struct cpu_info *ci = curcpu();
+	bool enabled = (bool)arg1;
+
+	mitigation_taa_apply_cpu(ci, enabled);
+}
+
+static void
+taa_detect_method(void)
+{
+	u_int descs[4];
+	uint64_t msr;
+
+	taa_mitigation_enabled_ptr = &taa_mitigation_enabled;
+
+	if (cpu_vendor != CPUVENDOR_INTEL) {
+		taa_mitigation_method = TAA_MITIGATION_TAA_NO;
+		return;
+	}
+	if (!(cpu_feature[5] & CPUID_SEF_RTM)) {
+		taa_mitigation_method = TAA_MITIGATION_TAA_NO;
+		return;
+	}
+
+	/*
+	 * If the CPU doesn't have MDS_NO set, then the TAA mitigation is based
+	 * on the MDS mitigation.
+	 */
+	if (cpuid_level < 7) {
+		taa_mitigation_method = TAA_MITIGATION_MDS;
+		taa_mitigation_enabled_ptr = &mds_mitigation_enabled;
+		return;
+	}
+	x86_cpuid(0x7, descs);
+	if (!(descs[3] & CPUID_SEF_ARCH_CAP)) {
+		taa_mitigation_method = TAA_MITIGATION_MDS;
+		taa_mitigation_enabled_ptr = &mds_mitigation_enabled;
+		return;
+	}
+	msr = rdmsr(MSR_IA32_ARCH_CAPABILITIES);
+	if (!(msr & IA32_ARCH_MDS_NO)) {
+		taa_mitigation_method = TAA_MITIGATION_MDS;
+		taa_mitigation_enabled_ptr = &mds_mitigation_enabled;
+		return;
+	}
+
+	/*
+	 * Otherwise, we need the TAA-specific mitigation.
+	 */
+	if (msr & IA32_ARCH_TAA_NO) {
+		taa_mitigation_method = TAA_MITIGATION_TAA_NO;
+		return;
+	}
+	if (msr & IA32_ARCH_TSX_CTRL) {
+		taa_mitigation_method = TAA_MITIGATION_RTM_DISABLE;
+		return;
+	}
+}
+
+static void
+taa_set_name(void)
+{
+	char name[64] = "";
+
+	switch (taa_mitigation_method) {
+	case TAA_MITIGATION_NONE:
+		strlcpy(name, "(none)", sizeof(name));
+		break;
+	case TAA_MITIGATION_TAA_NO:
+		strlcpy(name, "[TAA_NO]", sizeof(name));
+		break;
+	case TAA_MITIGATION_MDS:
+		strlcpy(name, "[MDS]", sizeof(name));
+		break;
+	case TAA_MITIGATION_RTM_DISABLE:
+		if (!taa_mitigation_enabled) {
+			strlcpy(name, "(none)", sizeof(name));
+		} else {
+			strlcpy(name, "[RTM_DISABLE]", sizeof(name));
+		}
+		break;
+	}
+
+	strlcpy(taa_mitigation_name, name, sizeof(taa_mitigation_name));
+}
+
+static int
+mitigation_taa_change(bool enabled)
+{
+	uint64_t xc;
+
+	taa_detect_method();
+
+	switch (taa_mitigation_method) {
+	case TAA_MITIGATION_NONE:
+		printf("[!] No mitigation available\n");
+		return EOPNOTSUPP;
+	case TAA_MITIGATION_TAA_NO:
+		printf("[+] The CPU is not affected by TAA\n");
+		return 0;
+	case TAA_MITIGATION_MDS:
+		printf("[!] Mitigation based on MDS, use machdep.mds\n");
+		taa_set_name();
+		return EINVAL;
+	case TAA_MITIGATION_RTM_DISABLE:
+		printf("[+] %s TAA Mitigation...",
+		    enabled ? "Enabling" : "Disabling");
+		xc = xc_broadcast(XC_HIGHPRI, mitigation_taa_change_cpu,
+		    (void *)enabled, NULL);
+		xc_wait(xc);
+		printf(" done!\n");
+		taa_mitigation_enabled = enabled;
+		taa_set_name();
+		return 0;
+	default:
+		panic("impossible");
+	}
+}
+
+static int
+sysctl_machdep_taa_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 == *taa_mitigation_enabled_ptr)
+		return 0;
+	return mitigation_taa_change(val);
+}
+
+/* -------------------------------------------------------------------------- */
+
 void speculation_barrier(struct lwp *, struct lwp *);
 
 void
@@ -801,14 +980,15 @@ speculation_barrier(struct lwp *oldlwp, 
 	}
 }
 
+/*
+ * cpu0 is the one that detects the method and sets the global 'enabled'
+ * variable for each mitigation.
+ */
 void
 cpu_speculation_init(struct cpu_info *ci)
 {
 	/*
 	 * Spectre V2.
-	 *
-	 * cpu0 is the one that detects the method and sets the global
-	 * variable.
 	 */
 	if (ci == &cpu_info_primary) {
 		v2_detect_method();
@@ -823,9 +1003,6 @@ cpu_speculation_init(struct cpu_info *ci
 	/*
 	 * Spectre V4.
 	 *
-	 * cpu0 is the one that detects the method and sets the global
-	 * variable.
-	 *
 	 * Disabled by default, as recommended by AMD, but can be enabled
 	 * dynamically. We only detect if the CPU is not vulnerable, to
 	 * mark it as 'mitigated' in the sysctl.
@@ -855,9 +1032,6 @@ cpu_speculation_init(struct cpu_info *ci
 
 	/*
 	 * Microarchitectural Data Sampling.
-	 *
-	 * cpu0 is the one that detects the method and sets the global
-	 * variable.
 	 */
 	if (ci == &cpu_info_primary) {
 		mds_detect_method();
@@ -869,6 +1043,20 @@ cpu_speculation_init(struct cpu_info *ci
 	    mds_mitigation_method != MDS_MITIGATION_MDS_NO) {
 		mitigation_mds_apply_cpu(ci, true);
 	}
+
+	/*
+	 * TSX Asynchronous Abort.
+	 */
+	if (ci == &cpu_info_primary) {
+		taa_detect_method();
+		taa_mitigation_enabled =
+		    (taa_mitigation_method == TAA_MITIGATION_RTM_DISABLE) ||
+		    (taa_mitigation_method == TAA_MITIGATION_TAA_NO);
+		taa_set_name();
+	}
+	if (taa_mitigation_method == TAA_MITIGATION_RTM_DISABLE) {
+		mitigation_taa_apply_cpu(ci, true);
+	}
 }
 
 void sysctl_speculation_init(struct sysctllog **);
@@ -968,4 +1156,26 @@ sysctl_speculation_init(struct sysctllog
 		       NULL, 0,
 		       mds_mitigation_name, 0,
 		       CTL_CREATE, CTL_EOL);
+
+	/* TSX Asynchronous Abort */
+	spec_rnode = NULL;
+	sysctl_createv(clog, 0, NULL, &spec_rnode,
+		       CTLFLAG_PERMANENT,
+		       CTLTYPE_NODE, "taa", NULL,
+		       NULL, 0, NULL, 0,
+		       CTL_MACHDEP, CTL_CREATE);
+	sysctl_createv(clog, 0, &spec_rnode, NULL,
+		       CTLFLAG_READWRITE,
+		       CTLTYPE_BOOL, "mitigated",
+		       SYSCTL_DESCR("Whether TAA is mitigated"),
+		       sysctl_machdep_taa_mitigated, 0,
+		       taa_mitigation_enabled_ptr, 0,
+		       CTL_CREATE, CTL_EOL);
+	sysctl_createv(clog, 0, &spec_rnode, NULL,
+		       CTLFLAG_PERMANENT,
+		       CTLTYPE_STRING, "method",
+		       SYSCTL_DESCR("Mitigation method in use"),
+		       NULL, 0,
+		       taa_mitigation_name, 0,
+		       CTL_CREATE, CTL_EOL);
 }

Reply via email to