Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/arch/x86 Mitigation for CVE-2019-11135: TSX Asynchronous...



details:   https://anonhg.NetBSD.org/src/rev/350529b5ceaf
branches:  trunk
changeset: 460990:350529b5ceaf
user:      maxv <maxv%NetBSD.org@localhost>
date:      Tue Nov 12 18:00:13 2019 +0000

description:
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.

diffstat:

 sys/arch/x86/include/specialreg.h |    7 +-
 sys/arch/x86/x86/spectre.c        |  234 ++++++++++++++++++++++++++++++++++++-
 2 files changed, 228 insertions(+), 13 deletions(-)

diffs (truncated from 320 to 300 lines):

diff -r f0e673ef2348 -r 350529b5ceaf sys/arch/x86/include/specialreg.h
--- a/sys/arch/x86/include/specialreg.h Tue Nov 12 17:27:59 2019 +0000
+++ b/sys/arch/x86/include/specialreg.h Tue Nov 12 18:00:13 2019 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: specialreg.h,v 1.156 2019/10/30 05:35:36 msaitoh Exp $ */
+/*     $NetBSD: specialreg.h,v 1.157 2019/11/12 18:00:13 maxv 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 */
diff -r f0e673ef2348 -r 350529b5ceaf sys/arch/x86/x86/spectre.c
--- a/sys/arch/x86/x86/spectre.c        Tue Nov 12 17:27:59 2019 +0000
+++ b/sys/arch/x86/x86/spectre.c        Tue Nov 12 18:00:13 2019 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: spectre.c,v 1.30 2019/08/30 13:29:17 msaitoh Exp $     */
+/*     $NetBSD: spectre.c,v 1.31 2019/11/12 18:00:13 maxv 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.30 2019/08/30 13:29:17 msaitoh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: spectre.c,v 1.31 2019/11/12 18:00:13 maxv Exp $");
 
 #include "opt_spectre.h"
 
@@ -773,6 +773,185 @@
 
 /* -------------------------------------------------------------------------- */
 
+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 @@
        }
 }
 
+/*
+ * 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 @@
        /*
         * 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 @@
 
        /*
         * 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 @@
            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 @@
                       NULL, 0,
                       mds_mitigation_name, 0,
                       CTL_CREATE, CTL_EOL);
+
+       /* TSX Asynchronous Abort */
+       spec_rnode = NULL;



Home | Main Index | Thread Index | Old Index