4401709
From: Andrew Cooper <andrew.cooper3@citrix.com>
4401709
Subject: x86/spec-ctrl: Mitigations for LazyFPU
4401709
4401709
Intel Core processors since at least Nehalem speculate past #NM, which is the
4401709
mechanism by which lazy FPU context switching is implemented.
4401709
4401709
On affected processors, Xen must use fully eager FPU context switching to
4401709
prevent guests from being able to read FPU state (SSE/AVX/etc) from previously
4401709
scheduled vcpus.
4401709
4401709
This is part of XSA-267 / CVE-2018-3665
4401709
4401709
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
4401709
Reviewed-by: Jan Beulich <jbeulich@suse.com>
4401709
4401709
diff --git a/docs/misc/xen-command-line.markdown b/docs/misc/xen-command-line.markdown
4401709
index 6300f69..52ed051 100644
4401709
--- a/docs/misc/xen-command-line.markdown
4401709
+++ b/docs/misc/xen-command-line.markdown
4401709
@@ -1635,7 +1635,7 @@ false disable the quirk workaround, which is also the default.
4401709
 
4401709
 ### spec-ctrl (x86)
4401709
 > `= List of [ <bool>, xen=<bool>, {pv,hvm,msr-sc,rsb}=<bool>,
4401709
->              bti-thunk=retpoline|lfence|jmp, {ibrs,ibpb,ssbd}=<bool> ]`
4401709
+>              bti-thunk=retpoline|lfence|jmp, {ibrs,ibpb,ssbd,eager-fpu}=<bool> ]`
4401709
 
4401709
 Controls for speculative execution sidechannel mitigations.  By default, Xen
4401709
 will pick the most appropriate mitigations based on compiled in support,
4401709
@@ -1685,6 +1685,11 @@ hardware, this is a global option applied at boot, and not virtualised for
4401709
 guest use.  On Intel hardware, the feature is virtualised for guests,
4401709
 independently of Xen's choice of setting.
4401709
 
4401709
+On all hardware, the `eager-fpu=` option can be used to force or prevent Xen
4401709
+from using fully eager FPU context switches.  This is currently implemented as
4401709
+a global control.  By default, Xen will choose to use fully eager context
4401709
+switches on hardware believed to speculate past #NM exceptions.
4401709
+
4401709
 ### sync\_console
4401709
 > `= <boolean>`
4401709
 
4401709
diff --git a/xen/arch/x86/i387.c b/xen/arch/x86/i387.c
4401709
index 1da31af..c3fda87 100644
4401709
--- a/xen/arch/x86/i387.c
4401709
+++ b/xen/arch/x86/i387.c
4401709
@@ -15,6 +15,7 @@
4401709
 #include <asm/i387.h>
4401709
 #include <asm/xstate.h>
4401709
 #include <asm/asm_defns.h>
4401709
+#include <asm/spec_ctrl.h>
4401709
 
4401709
 /*******************************/
4401709
 /*     FPU Restore Functions   */
4401709
@@ -307,6 +308,8 @@ int vcpu_init_fpu(struct vcpu *v)
4401709
 {
4401709
     int rc;
4401709
     
4401709
+    v->arch.fully_eager_fpu = opt_eager_fpu;
4401709
+
4401709
     if ( (rc = xstate_alloc_save_area(v)) != 0 )
4401709
         return rc;
4401709
 
4401709
diff --git a/xen/arch/x86/spec_ctrl.c b/xen/arch/x86/spec_ctrl.c
4401709
index 8077000..ada4aac 100644
4401709
--- a/xen/arch/x86/spec_ctrl.c
4401709
+++ b/xen/arch/x86/spec_ctrl.c
4401709
@@ -44,6 +44,7 @@ static enum ind_thunk {
4401709
 static int8_t __initdata opt_ibrs = -1;
4401709
 bool __read_mostly opt_ibpb = true;
4401709
 bool __read_mostly opt_ssbd = false;
4401709
+int8_t __read_mostly opt_eager_fpu = -1;
4401709
 
4401709
 bool __initdata bsp_delay_spec_ctrl;
4401709
 uint8_t __read_mostly default_xen_spec_ctrl;
4401709
@@ -114,6 +115,7 @@ static int __init parse_spec_ctrl(char *s)
4401709
             opt_thunk = THUNK_JMP;
4401709
             opt_ibrs = 0;
4401709
             opt_ibpb = false;
4401709
+            opt_eager_fpu = 0;
4401709
         }
4401709
         else if ( val > 0 )
4401709
             rc = -EINVAL;
4401709
@@ -167,6 +169,8 @@ static int __init parse_spec_ctrl(char *s)
4401709
             opt_ibpb = val;
4401709
         else if ( (val = parse_boolean("ssbd", s, ss)) >= 0 )
4401709
             opt_ssbd = val;
4401709
+        else if ( (val = parse_boolean("eager-fpu", s, ss)) >= 0 )
4401709
+            opt_eager_fpu = val;
4401709
         else
4401709
             rc = -EINVAL;
4401709
 
4401709
@@ -223,15 +227,19 @@ static void __init print_details(enum ind_thunk thunk, uint64_t caps)
4401709
      * Alternatives blocks for protecting against and/or virtualising
4401709
      * mitigation support for guests.
4401709
      */
4401709
-    printk("  Support for VMs: PV:%s%s%s, HVM:%s%s%s\n",
4401709
+    printk("  Support for VMs: PV:%s%s%s%s, HVM:%s%s%s%s\n",
4401709
            (boot_cpu_has(X86_FEATURE_SC_MSR_PV) ||
4401709
-            boot_cpu_has(X86_FEATURE_SC_RSB_PV))     ? ""               : " None",
4401709
+            boot_cpu_has(X86_FEATURE_SC_RSB_PV) ||
4401709
+            opt_eager_fpu)                           ? ""               : " None",
4401709
            boot_cpu_has(X86_FEATURE_SC_MSR_PV)       ? " MSR_SPEC_CTRL" : "",
4401709
            boot_cpu_has(X86_FEATURE_SC_RSB_PV)       ? " RSB"           : "",
4401709
+           opt_eager_fpu                             ? " EAGER_FPU"     : "",
4401709
            (boot_cpu_has(X86_FEATURE_SC_MSR_HVM) ||
4401709
-            boot_cpu_has(X86_FEATURE_SC_RSB_HVM))    ? ""               : " None",
4401709
+            boot_cpu_has(X86_FEATURE_SC_RSB_HVM) ||
4401709
+            opt_eager_fpu)                           ? ""               : " None",
4401709
            boot_cpu_has(X86_FEATURE_SC_MSR_HVM)      ? " MSR_SPEC_CTRL" : "",
4401709
-           boot_cpu_has(X86_FEATURE_SC_RSB_HVM)      ? " RSB"           : "");
4401709
+           boot_cpu_has(X86_FEATURE_SC_RSB_HVM)      ? " RSB"           : "",
4401709
+           opt_eager_fpu                             ? " EAGER_FPU"     : "");
4401709
 
4401709
     printk("XPTI: %s\n",
4401709
            boot_cpu_has(X86_FEATURE_NO_XPTI) ? "disabled" : "enabled");
4401709
@@ -321,6 +329,82 @@ static bool __init retpoline_safe(uint64_t caps)
4401709
     }
4401709
 }
4401709
 
4401709
+/* Calculate whether this CPU speculates past #NM */
4401709
+static bool __init should_use_eager_fpu(void)
4401709
+{
4401709
+    /*
4401709
+     * Assume all unrecognised processors are ok.  This is only known to
4401709
+     * affect Intel Family 6 processors.
4401709
+     */
4401709
+    if ( boot_cpu_data.x86_vendor != X86_VENDOR_INTEL ||
4401709
+         boot_cpu_data.x86 != 6 )
4401709
+        return false;
4401709
+
4401709
+    switch ( boot_cpu_data.x86_model )
4401709
+    {
4401709
+        /*
4401709
+         * Core processors since at least Nehalem are vulnerable.
4401709
+         */
4401709
+    case 0x1e: /* Nehalem */
4401709
+    case 0x1f: /* Auburndale / Havendale */
4401709
+    case 0x1a: /* Nehalem EP */
4401709
+    case 0x2e: /* Nehalem EX */
4401709
+    case 0x25: /* Westmere */
4401709
+    case 0x2c: /* Westmere EP */
4401709
+    case 0x2f: /* Westmere EX */
4401709
+    case 0x2a: /* SandyBridge */
4401709
+    case 0x2d: /* SandyBridge EP/EX */
4401709
+    case 0x3a: /* IvyBridge */
4401709
+    case 0x3e: /* IvyBridge EP/EX */
4401709
+    case 0x3c: /* Haswell */
4401709
+    case 0x3f: /* Haswell EX/EP */
4401709
+    case 0x45: /* Haswell D */
4401709
+    case 0x46: /* Haswell H */
4401709
+    case 0x3d: /* Broadwell */
4401709
+    case 0x47: /* Broadwell H */
4401709
+    case 0x4f: /* Broadwell EP/EX */
4401709
+    case 0x56: /* Broadwell D */
4401709
+    case 0x4e: /* Skylake M */
4401709
+    case 0x55: /* Skylake X */
4401709
+    case 0x5e: /* Skylake D */
4401709
+    case 0x66: /* Cannonlake */
4401709
+    case 0x67: /* Cannonlake? */
4401709
+    case 0x8e: /* Kabylake M */
4401709
+    case 0x9e: /* Kabylake D */
4401709
+        return true;
4401709
+
4401709
+        /*
4401709
+         * Atom processors are not vulnerable.
4401709
+         */
4401709
+    case 0x1c: /* Pineview */
4401709
+    case 0x26: /* Lincroft */
4401709
+    case 0x27: /* Penwell */
4401709
+    case 0x35: /* Cloverview */
4401709
+    case 0x36: /* Cedarview */
4401709
+    case 0x37: /* Baytrail / Valleyview (Silvermont) */
4401709
+    case 0x4d: /* Avaton / Rangely (Silvermont) */
4401709
+    case 0x4c: /* Cherrytrail / Brasswell */
4401709
+    case 0x4a: /* Merrifield */
4401709
+    case 0x5a: /* Moorefield */
4401709
+    case 0x5c: /* Goldmont */
4401709
+    case 0x5f: /* Denverton */
4401709
+    case 0x7a: /* Gemini Lake */
4401709
+        return false;
4401709
+
4401709
+        /*
4401709
+         * Knights processors are not vulnerable.
4401709
+         */
4401709
+    case 0x57: /* Knights Landing */
4401709
+    case 0x85: /* Knights Mill */
4401709
+        return false;
4401709
+
4401709
+    default:
4401709
+        printk("Unrecognised CPU model %#x - assuming vulnerable to LazyFPU\n",
4401709
+               boot_cpu_data.x86_model);
4401709
+        return true;
4401709
+    }
4401709
+}
4401709
+
4401709
 void __init init_speculation_mitigations(void)
4401709
 {
4401709
     enum ind_thunk thunk = THUNK_DEFAULT;
4401709
@@ -519,6 +603,10 @@ void __init init_speculation_mitigations(void)
4401709
     if ( !boot_cpu_has(X86_FEATURE_IBRSB) && !boot_cpu_has(X86_FEATURE_IBPB) )
4401709
         opt_ibpb = false;
4401709
 
4401709
+    /* Check whether Eager FPU should be enabled by default. */
4401709
+    if ( opt_eager_fpu == -1 )
4401709
+        opt_eager_fpu = should_use_eager_fpu();
4401709
+
4401709
     /* (Re)init BSP state now that default_spec_ctrl_flags has been calculated. */
4401709
     init_shadow_spec_ctrl_state();
4401709
 
4401709
diff --git a/xen/include/asm-x86/spec_ctrl.h b/xen/include/asm-x86/spec_ctrl.h
4401709
index 91bed1b..5b40afb 100644
4401709
--- a/xen/include/asm-x86/spec_ctrl.h
4401709
+++ b/xen/include/asm-x86/spec_ctrl.h
4401709
@@ -28,6 +28,7 @@ void init_speculation_mitigations(void);
4401709
 
4401709
 extern bool opt_ibpb;
4401709
 extern bool opt_ssbd;
4401709
+extern int8_t opt_eager_fpu;
4401709
 
4401709
 extern bool bsp_delay_spec_ctrl;
4401709
 extern uint8_t default_xen_spec_ctrl;