kvm: mmu: ITLB_MULTIHIT mitigation
[linux-2.6-block.git] / arch / x86 / kernel / cpu / bugs.c
index 91c2561b905f3e1b264e72eec420af50bd820469..850005590167d5bafca70503650b6aea3bba156f 100644 (file)
@@ -39,6 +39,7 @@ static void __init spectre_v2_select_mitigation(void);
 static void __init ssb_select_mitigation(void);
 static void __init l1tf_select_mitigation(void);
 static void __init mds_select_mitigation(void);
+static void __init taa_select_mitigation(void);
 
 /* The base value of the SPEC_CTRL MSR that always has to be preserved. */
 u64 x86_spec_ctrl_base;
@@ -105,6 +106,7 @@ void __init check_bugs(void)
        ssb_select_mitigation();
        l1tf_select_mitigation();
        mds_select_mitigation();
+       taa_select_mitigation();
 
        arch_smt_update();
 
@@ -268,6 +270,100 @@ static int __init mds_cmdline(char *str)
 }
 early_param("mds", mds_cmdline);
 
+#undef pr_fmt
+#define pr_fmt(fmt)    "TAA: " fmt
+
+/* Default mitigation for TAA-affected CPUs */
+static enum taa_mitigations taa_mitigation __ro_after_init = TAA_MITIGATION_VERW;
+static bool taa_nosmt __ro_after_init;
+
+static const char * const taa_strings[] = {
+       [TAA_MITIGATION_OFF]            = "Vulnerable",
+       [TAA_MITIGATION_UCODE_NEEDED]   = "Vulnerable: Clear CPU buffers attempted, no microcode",
+       [TAA_MITIGATION_VERW]           = "Mitigation: Clear CPU buffers",
+       [TAA_MITIGATION_TSX_DISABLED]   = "Mitigation: TSX disabled",
+};
+
+static void __init taa_select_mitigation(void)
+{
+       u64 ia32_cap;
+
+       if (!boot_cpu_has_bug(X86_BUG_TAA)) {
+               taa_mitigation = TAA_MITIGATION_OFF;
+               return;
+       }
+
+       /* TSX previously disabled by tsx=off */
+       if (!boot_cpu_has(X86_FEATURE_RTM)) {
+               taa_mitigation = TAA_MITIGATION_TSX_DISABLED;
+               goto out;
+       }
+
+       if (cpu_mitigations_off()) {
+               taa_mitigation = TAA_MITIGATION_OFF;
+               return;
+       }
+
+       /* TAA mitigation is turned off on the cmdline (tsx_async_abort=off) */
+       if (taa_mitigation == TAA_MITIGATION_OFF)
+               goto out;
+
+       if (boot_cpu_has(X86_FEATURE_MD_CLEAR))
+               taa_mitigation = TAA_MITIGATION_VERW;
+       else
+               taa_mitigation = TAA_MITIGATION_UCODE_NEEDED;
+
+       /*
+        * VERW doesn't clear the CPU buffers when MD_CLEAR=1 and MDS_NO=1.
+        * A microcode update fixes this behavior to clear CPU buffers. It also
+        * adds support for MSR_IA32_TSX_CTRL which is enumerated by the
+        * ARCH_CAP_TSX_CTRL_MSR bit.
+        *
+        * On MDS_NO=1 CPUs if ARCH_CAP_TSX_CTRL_MSR is not set, microcode
+        * update is required.
+        */
+       ia32_cap = x86_read_arch_cap_msr();
+       if ( (ia32_cap & ARCH_CAP_MDS_NO) &&
+           !(ia32_cap & ARCH_CAP_TSX_CTRL_MSR))
+               taa_mitigation = TAA_MITIGATION_UCODE_NEEDED;
+
+       /*
+        * TSX is enabled, select alternate mitigation for TAA which is
+        * the same as MDS. Enable MDS static branch to clear CPU buffers.
+        *
+        * For guests that can't determine whether the correct microcode is
+        * present on host, enable the mitigation for UCODE_NEEDED as well.
+        */
+       static_branch_enable(&mds_user_clear);
+
+       if (taa_nosmt || cpu_mitigations_auto_nosmt())
+               cpu_smt_disable(false);
+
+out:
+       pr_info("%s\n", taa_strings[taa_mitigation]);
+}
+
+static int __init tsx_async_abort_parse_cmdline(char *str)
+{
+       if (!boot_cpu_has_bug(X86_BUG_TAA))
+               return 0;
+
+       if (!str)
+               return -EINVAL;
+
+       if (!strcmp(str, "off")) {
+               taa_mitigation = TAA_MITIGATION_OFF;
+       } else if (!strcmp(str, "full")) {
+               taa_mitigation = TAA_MITIGATION_VERW;
+       } else if (!strcmp(str, "full,nosmt")) {
+               taa_mitigation = TAA_MITIGATION_VERW;
+               taa_nosmt = true;
+       }
+
+       return 0;
+}
+early_param("tsx_async_abort", tsx_async_abort_parse_cmdline);
+
 #undef pr_fmt
 #define pr_fmt(fmt)     "Spectre V1 : " fmt
 
@@ -786,6 +882,7 @@ static void update_mds_branch_idle(void)
 }
 
 #define MDS_MSG_SMT "MDS CPU bug present and SMT on, data leak possible. See https://www.kernel.org/doc/html/latest/admin-guide/hw-vuln/mds.html for more details.\n"
+#define TAA_MSG_SMT "TAA CPU bug present and SMT on, data leak possible. See https://www.kernel.org/doc/html/latest/admin-guide/hw-vuln/tsx_async_abort.html for more details.\n"
 
 void cpu_bugs_smt_update(void)
 {
@@ -819,6 +916,17 @@ void cpu_bugs_smt_update(void)
                break;
        }
 
+       switch (taa_mitigation) {
+       case TAA_MITIGATION_VERW:
+       case TAA_MITIGATION_UCODE_NEEDED:
+               if (sched_smt_active())
+                       pr_warn_once(TAA_MSG_SMT);
+               break;
+       case TAA_MITIGATION_TSX_DISABLED:
+       case TAA_MITIGATION_OFF:
+               break;
+       }
+
        mutex_unlock(&spec_ctrl_mutex);
 }
 
@@ -1149,6 +1257,9 @@ void x86_spec_ctrl_setup_ap(void)
                x86_amd_ssb_disable();
 }
 
+bool itlb_multihit_kvm_mitigation;
+EXPORT_SYMBOL_GPL(itlb_multihit_kvm_mitigation);
+
 #undef pr_fmt
 #define pr_fmt(fmt)    "L1TF: " fmt
 
@@ -1304,11 +1415,24 @@ static ssize_t l1tf_show_state(char *buf)
                       l1tf_vmx_states[l1tf_vmx_mitigation],
                       sched_smt_active() ? "vulnerable" : "disabled");
 }
+
+static ssize_t itlb_multihit_show_state(char *buf)
+{
+       if (itlb_multihit_kvm_mitigation)
+               return sprintf(buf, "KVM: Mitigation: Split huge pages\n");
+       else
+               return sprintf(buf, "KVM: Vulnerable\n");
+}
 #else
 static ssize_t l1tf_show_state(char *buf)
 {
        return sprintf(buf, "%s\n", L1TF_DEFAULT_MSG);
 }
+
+static ssize_t itlb_multihit_show_state(char *buf)
+{
+       return sprintf(buf, "Processor vulnerable\n");
+}
 #endif
 
 static ssize_t mds_show_state(char *buf)
@@ -1328,6 +1452,21 @@ static ssize_t mds_show_state(char *buf)
                       sched_smt_active() ? "vulnerable" : "disabled");
 }
 
+static ssize_t tsx_async_abort_show_state(char *buf)
+{
+       if ((taa_mitigation == TAA_MITIGATION_TSX_DISABLED) ||
+           (taa_mitigation == TAA_MITIGATION_OFF))
+               return sprintf(buf, "%s\n", taa_strings[taa_mitigation]);
+
+       if (boot_cpu_has(X86_FEATURE_HYPERVISOR)) {
+               return sprintf(buf, "%s; SMT Host state unknown\n",
+                              taa_strings[taa_mitigation]);
+       }
+
+       return sprintf(buf, "%s; SMT %s\n", taa_strings[taa_mitigation],
+                      sched_smt_active() ? "vulnerable" : "disabled");
+}
+
 static char *stibp_state(void)
 {
        if (spectre_v2_enabled == SPECTRE_V2_IBRS_ENHANCED)
@@ -1398,6 +1537,12 @@ static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr
        case X86_BUG_MDS:
                return mds_show_state(buf);
 
+       case X86_BUG_TAA:
+               return tsx_async_abort_show_state(buf);
+
+       case X86_BUG_ITLB_MULTIHIT:
+               return itlb_multihit_show_state(buf);
+
        default:
                break;
        }
@@ -1434,4 +1579,14 @@ ssize_t cpu_show_mds(struct device *dev, struct device_attribute *attr, char *bu
 {
        return cpu_show_common(dev, attr, buf, X86_BUG_MDS);
 }
+
+ssize_t cpu_show_tsx_async_abort(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return cpu_show_common(dev, attr, buf, X86_BUG_TAA);
+}
+
+ssize_t cpu_show_itlb_multihit(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return cpu_show_common(dev, attr, buf, X86_BUG_ITLB_MULTIHIT);
+}
 #endif