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); }