Print this page
11967 need TAA mitigation
Portions contributed by: Robert Mustacchi <rm@fingolfin.org>
Reviewed by: Dan McDonald <danmcd@joyent.com>

@@ -30,11 +30,11 @@
  */
 /*
  * Portions Copyright 2009 Advanced Micro Devices, Inc.
  */
 /*
- * Copyright 2019 Joyent, Inc.
+ * Copyright 2020 Joyent, Inc.
  */
 
 /*
  * CPU Identification logic
  *

@@ -1184,10 +1184,58 @@
  * trust each other. Practically speaking, this would mean that a system call
  * would have to issue an inter-processor interrupt (IPI) to the other thread.
  * Rather than implement this, we recommend that one disables hyper-threading
  * through the use of psradm -aS.
  *
+ * TSX ASYNCHRONOUS ABORT
+ *
+ * TSX Asynchronous Abort (TAA) is another side-channel vulnerability that
+ * behaves like MDS, but leverages Intel's transactional instructions as another
+ * vector. Effectively, when a transaction hits one of these cases (unmapped
+ * page, various cache snoop activity, etc.) then the same data can be exposed
+ * as in the case of MDS. This means that you can attack your twin.
+ *
+ * Intel has described that there are two different ways that we can mitigate
+ * this problem on affected processors:
+ *
+ *   1) We can use the same techniques used to deal with MDS. Flushing the
+ *      microarchitectural buffers and disabling hyperthreading will mitigate
+ *      this in the same way.
+ *
+ *   2) Using microcode to disable TSX.
+ *
+ * Now, most processors that are subject to MDS (as in they don't have MDS_NO in
+ * the IA32_ARCH_CAPABILITIES MSR) will not receive microcode to disable TSX.
+ * That's OK as we're already doing all such mitigations. On the other hand,
+ * processors with MDS_NO are all supposed to receive microcode updates that
+ * enumerate support for disabling TSX. In general, we'd rather use this method
+ * when available as it doesn't require disabling hyperthreading to be
+ * effective. Currently we basically are relying on microcode for processors
+ * that enumerate MDS_NO.
+ *
+ * The microcode features are enumerated as part of the IA32_ARCH_CAPABILITIES.
+ * When bit 7 (IA32_ARCH_CAP_TSX_CTRL) is present, then we are given two
+ * different powers. The first allows us to cause all transactions to
+ * immediately abort. The second gives us a means of disabling TSX completely,
+ * which includes removing it from cpuid. If we have support for this in
+ * microcode during the first cpuid pass, then we'll disable TSX completely such
+ * that user land never has a chance to observe the bit. However, if we are late
+ * loading the microcode, then we must use the functionality to cause
+ * transactions to automatically abort. This is necessary for user land's sake.
+ * Once a program sees a cpuid bit, it must not be taken away.
+ *
+ * We track whether or not we should do this based on what cpuid pass we're in.
+ * Whenever we hit cpuid_scan_security() on the boot CPU and we're still on pass
+ * 1 of the cpuid logic, then we can completely turn off TSX. Notably this
+ * should happen twice. Once in the normal cpuid_pass1() code and then a second
+ * time after we do the initial microcode update.
+ *
+ * If TAA has been fixed, then it will be enumerated in IA32_ARCH_CAPABILITIES
+ * as TAA_NO. In such a case, we will still disable TSX: it's proven to be an
+ * unfortunate feature in a number of ways, and taking the opportunity to
+ * finally be able to turn it off is likely to be of benefit in the future.
+ *
  * SUMMARY
  *
  * The following table attempts to summarize the mitigations for various issues
  * and what's done in various places:
  *

@@ -1197,17 +1245,19 @@
  *  - Meltdown: Kernel Page Table Isolation
  *  - Spectre v3a: Updated CPU microcode
  *  - Spectre v4: Not currently mitigated
  *  - SpectreRSB: SMEP and RSB Stuffing
  *  - L1TF: spec_uarch_flush, SMT exclusion, requires microcode
- *  - MDS: x86_md_clear, requires microcode, disabling hyper threading
+ *  - MDS: x86_md_clear, requires microcode, disabling SMT
+ *  - TAA: x86_md_clear and disabling SMT OR microcode and disabling TSX
  *
  * The following table indicates the x86 feature set bits that indicate that a
  * given problem has been solved or a notable feature is present:
  *
  *  - RDCL_NO: Meltdown, L1TF, MSBDS subset of MDS
  *  - MDS_NO: All forms of MDS
+ *  - TAA_NO: TAA
  */
 
 #include <sys/types.h>
 #include <sys/archsystm.h>
 #include <sys/x86_archext.h>

@@ -1260,10 +1310,31 @@
 
 uint_t x86_disable_spectrev2 = 0;
 static x86_spectrev2_mitigation_t x86_spectrev2_mitigation =
     X86_SPECTREV2_RETPOLINE;
 
+/*
+ * The mitigation status for TAA:
+ * X86_TAA_NOTHING -- no mitigation available for TAA side-channels
+ * X86_TAA_DISABLED -- mitigation disabled via x86_disable_taa
+ * X86_TAA_MD_CLEAR -- MDS mitigation also suffices for TAA
+ * X86_TAA_TSX_FORCE_ABORT -- transactions are forced to abort
+ * X86_TAA_TSX_DISABLE -- force abort transactions and hide from CPUID
+ * X86_TAA_HW_MITIGATED -- TSX potentially active but H/W not TAA-vulnerable
+ */
+typedef enum {
+        X86_TAA_NOTHING,
+        X86_TAA_DISABLED,
+        X86_TAA_MD_CLEAR,
+        X86_TAA_TSX_FORCE_ABORT,
+        X86_TAA_TSX_DISABLE,
+        X86_TAA_HW_MITIGATED
+} x86_taa_mitigation_t;
+
+uint_t x86_disable_taa = 0;
+static x86_taa_mitigation_t x86_taa_mitigation = X86_TAA_NOTHING;
+
 uint_t pentiumpro_bug4046376;
 
 uchar_t x86_featureset[BT_SIZEOFMAP(NUM_X86_FEATURES)];
 
 static char *x86_feature_names[NUM_X86_FEATURES] = {

@@ -1361,11 +1432,13 @@
         "avx512_vnni",
         "amd_pcec",
         "mb_clear",
         "mds_no",
         "core_thermal",
-        "pkg_thermal"
+        "pkg_thermal",
+        "tsx_ctrl",
+        "taa_no"
 };
 
 boolean_t
 is_x86_feature(void *featureset, uint_t feature)
 {

@@ -2700,11 +2773,99 @@
                 return (B_TRUE);
         return (B_FALSE);
 }
 #endif  /* !__xpv */
 
+/*
+ * Determine how we should mitigate TAA or if we need to. Regardless of TAA, if
+ * we can disable TSX, we do so.
+ *
+ * This determination is done only on the boot CPU, potentially after loading
+ * updated microcode.
+ */
 static void
+cpuid_update_tsx(cpu_t *cpu, uchar_t *featureset)
+{
+        struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
+
+        VERIFY(cpu->cpu_id == 0);
+
+        if (cpi->cpi_vendor != X86_VENDOR_Intel) {
+                x86_taa_mitigation = X86_TAA_HW_MITIGATED;
+                return;
+        }
+
+        if (x86_disable_taa) {
+                x86_taa_mitigation = X86_TAA_DISABLED;
+                return;
+        }
+
+        /*
+         * If we do not have the ability to disable TSX, then our only
+         * mitigation options are in hardware (TAA_NO), or by using our existing
+         * MDS mitigation as described above.  The latter relies upon us having
+         * configured MDS mitigations correctly! This includes disabling SMT if
+         * we want to cross-CPU-thread protection.
+         */
+        if (!is_x86_feature(featureset, X86FSET_TSX_CTRL)) {
+                /*
+                 * It's not clear whether any parts will enumerate TAA_NO
+                 * *without* TSX_CTRL, but let's mark it as such if we see this.
+                 */
+                if (is_x86_feature(featureset, X86FSET_TAA_NO)) {
+                        x86_taa_mitigation = X86_TAA_HW_MITIGATED;
+                        return;
+                }
+
+                if (is_x86_feature(featureset, X86FSET_MD_CLEAR) &&
+                    !is_x86_feature(featureset, X86FSET_MDS_NO)) {
+                        x86_taa_mitigation = X86_TAA_MD_CLEAR;
+                } else {
+                        x86_taa_mitigation = X86_TAA_NOTHING;
+                }
+                return;
+        }
+
+        /*
+         * We have TSX_CTRL, but we can only fully disable TSX if we're early
+         * enough in boot.
+         *
+         * Otherwise, we'll fall back to causing transactions to abort as our
+         * mitigation. TSX-using code will always take the fallback path.
+         */
+        if (cpi->cpi_pass < 4) {
+                x86_taa_mitigation = X86_TAA_TSX_DISABLE;
+        } else {
+                x86_taa_mitigation = X86_TAA_TSX_FORCE_ABORT;
+        }
+}
+
+static void
+cpuid_apply_tsx(x86_taa_mitigation_t taa)
+{
+        uint64_t val;
+
+        switch (taa) {
+        case X86_TAA_TSX_DISABLE:
+                val = rdmsr(MSR_IA32_TSX_CTRL);
+                val |= IA32_TSX_CTRL_CPUID_CLEAR | IA32_TSX_CTRL_RTM_DISABLE;
+                wrmsr(MSR_IA32_TSX_CTRL, val);
+                break;
+        case X86_TAA_TSX_FORCE_ABORT:
+                val = rdmsr(MSR_IA32_TSX_CTRL);
+                val |= IA32_TSX_CTRL_RTM_DISABLE;
+                wrmsr(MSR_IA32_TSX_CTRL, val);
+                break;
+        case X86_TAA_HW_MITIGATED:
+        case X86_TAA_MD_CLEAR:
+        case X86_TAA_DISABLED:
+        case X86_TAA_NOTHING:
+                break;
+        }
+}
+
+static void
 cpuid_scan_security(cpu_t *cpu, uchar_t *featureset)
 {
         struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi;
         x86_spectrev2_mitigation_t v2mit;
 

@@ -2789,11 +2950,19 @@
                                 }
                                 if (reg & IA32_ARCH_CAP_MDS_NO) {
                                         add_x86_feature(featureset,
                                             X86FSET_MDS_NO);
                                 }
+                                if (reg & IA32_ARCH_CAP_TSX_CTRL) {
+                                        add_x86_feature(featureset,
+                                            X86FSET_TSX_CTRL);
                         }
+                                if (reg & IA32_ARCH_CAP_TAA_NO) {
+                                        add_x86_feature(featureset,
+                                            X86FSET_TAA_NO);
+                                }
+                        }
                         no_trap();
                 }
 #endif  /* !__xpv */
 
                 if (ecp->cp_edx & CPUID_INTC_EDX_7_0_SSBD)

@@ -2801,20 +2970,32 @@
 
                 if (ecp->cp_edx & CPUID_INTC_EDX_7_0_FLUSH_CMD)
                         add_x86_feature(featureset, X86FSET_FLUSH_CMD);
         }
 
+        /*
+         * Take care of certain mitigations on the non-boot CPU. The boot CPU
+         * will have already run this function and determined what we need to
+         * do. This gives us a hook for per-HW thread mitigations such as
+         * enhanced IBRS, or disabling TSX.  For TSX disabling, we need to be
+         * careful that we've had a chance to load ucode that enables the new
+         * MSRs.
+         */
         if (cpu->cpu_id != 0) {
                 if (x86_spectrev2_mitigation == X86_SPECTREV2_ENHANCED_IBRS) {
                         cpuid_enable_enhanced_ibrs();
                 }
+
+                if (cpi->cpi_pass >= 1)
+                        cpuid_apply_tsx(x86_taa_mitigation);
                 return;
         }
 
         /*
          * Go through and initialize various security mechanisms that we should
-         * only do on a single CPU. This includes Spectre V2, L1TF, and MDS.
+         * only do on a single CPU. This includes Spectre V2, L1TF, MDS, and
+         * TAA.
          */
 
         /*
          * By default we've come in with retpolines enabled. Check whether we
          * should disable them or enable enhanced IBRS. RSB stuffing is enabled

@@ -2860,10 +3041,17 @@
         /*
          * Determine whether SMT exclusion is required and whether or not we
          * need to perform an l1d flush.
          */
         cpuid_update_l1d_flush(cpu, featureset);
+
+        /*
+         * Determine what our mitigation strategy should be for TAA and then
+         * also apply TAA mitigations.
+         */
+        cpuid_update_tsx(cpu, featureset);
+        cpuid_apply_tsx(x86_taa_mitigation);
 }
 
 /*
  * Setup XFeature_Enabled_Mask register. Required by xsave feature.
  */