x86/bugs, kvm: Introduce boot-time control of L1TF mitigations
authorJiri Kosina <jkosina@suse.cz>
Fri, 13 Jul 2018 14:23:25 +0000 (16:23 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 15 Aug 2018 16:12:56 +0000 (18:12 +0200)
commit d90a7a0ec83fb86622cd7dae23255d3c50a99ec8 upstream

Introduce the 'l1tf=' kernel command line option to allow for boot-time
switching of mitigation that is used on processors affected by L1TF.

The possible values are:

  full
Provides all available mitigations for the L1TF vulnerability. Disables
SMT and enables all mitigations in the hypervisors. SMT control via
/sys/devices/system/cpu/smt/control is still possible after boot.
Hypervisors will issue a warning when the first VM is started in
a potentially insecure configuration, i.e. SMT enabled or L1D flush
disabled.

  full,force
Same as 'full', but disables SMT control. Implies the 'nosmt=force'
command line option. sysfs control of SMT and the hypervisor flush
control is disabled.

  flush
Leaves SMT enabled and enables the conditional hypervisor mitigation.
Hypervisors will issue a warning when the first VM is started in a
potentially insecure configuration, i.e. SMT enabled or L1D flush
disabled.

  flush,nosmt
Disables SMT and enables the conditional hypervisor mitigation. SMT
control via /sys/devices/system/cpu/smt/control is still possible
after boot. If SMT is reenabled or flushing disabled at runtime
hypervisors will issue a warning.

  flush,nowarn
Same as 'flush', but hypervisors will not warn when
a VM is started in a potentially insecure configuration.

  off
Disables hypervisor mitigations and doesn't emit any warnings.

Default is 'flush'.

Let KVM adhere to these semantics, which means:

  - 'lt1f=full,force' : Performe L1D flushes. No runtime control
       possible.

  - 'l1tf=full'
  - 'l1tf-flush'
  - 'l1tf=flush,nosmt' : Perform L1D flushes and warn on VM start if
  SMT has been runtime enabled or L1D flushing
  has been run-time enabled

  - 'l1tf=flush,nowarn' : Perform L1D flushes and no warnings are emitted.

  - 'l1tf=off' : L1D flushes are not performed and no warnings
  are emitted.

KVM can always override the L1D flushing behavior using its 'vmentry_l1d_flush'
module parameter except when lt1f=full,force is set.

This makes KVM's private 'nosmt' option redundant, and as it is a bit
non-systematic anyway (this is something to control globally, not on
hypervisor level), remove that option.

Add the missing Documentation entry for the l1tf vulnerability sysfs file
while at it.

Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Jiri Kosina <jkosina@suse.cz>
Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Josh Poimboeuf <jpoimboe@redhat.com>
Link: https://lkml.kernel.org/r/20180713142323.202758176@linutronix.de
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Documentation/ABI/testing/sysfs-devices-system-cpu
Documentation/admin-guide/kernel-parameters.txt
arch/x86/include/asm/processor.h
arch/x86/kernel/cpu/bugs.c
arch/x86/kvm/vmx.c

index c9c9e60d3e7cd24dc479dd3e64a1e998f9b58ce8..6cae60929cb6f4446e73b5104aaf356a4c4bf3a0 100644 (file)
@@ -379,6 +379,7 @@ What:               /sys/devices/system/cpu/vulnerabilities
                /sys/devices/system/cpu/vulnerabilities/spectre_v1
                /sys/devices/system/cpu/vulnerabilities/spectre_v2
                /sys/devices/system/cpu/vulnerabilities/spec_store_bypass
+               /sys/devices/system/cpu/vulnerabilities/l1tf
 Date:          January 2018
 Contact:       Linux kernel mailing list <linux-kernel@vger.kernel.org>
 Description:   Information about CPU vulnerabilities
@@ -391,6 +392,9 @@ Description:        Information about CPU vulnerabilities
                "Vulnerable"      CPU is affected and no mitigation in effect
                "Mitigation: $M"  CPU is affected and mitigation $M is in effect
 
+               Details about the l1tf file can be found in
+               Documentation/admin-guide/l1tf.rst
+
 What:          /sys/devices/system/cpu/smt
                /sys/devices/system/cpu/smt/active
                /sys/devices/system/cpu/smt/control
index e928ccff7d2353b97bc4ecefeb9cecac96cc062e..9841bad6f271f31496b64af11928f34919537c5d 100644 (file)
                        [KVM,ARM] Trap guest accesses to GICv3 common
                        system registers
 
-       kvm-intel.nosmt=[KVM,Intel] If the L1TF CPU bug is present (CVE-2018-3620)
-                       and the system has SMT (aka Hyper-Threading) enabled then
-                       don't allow guests to be created.
-
-                       Default is 0 (allow guests to be created).
-
        kvm-intel.ept=  [KVM,Intel] Disable extended page tables
                        (virtualized MMU) support on capable Intel chips.
                        Default is 1 (enabled)
                        feature (tagged TLBs) on capable Intel chips.
                        Default is 1 (enabled)
 
+       l1tf=           [X86] Control mitigation of the L1TF vulnerability on
+                             affected CPUs
+
+                       The kernel PTE inversion protection is unconditionally
+                       enabled and cannot be disabled.
+
+                       full
+                               Provides all available mitigations for the
+                               L1TF vulnerability. Disables SMT and
+                               enables all mitigations in the
+                               hypervisors, i.e. unconditional L1D flush.
+
+                               SMT control and L1D flush control via the
+                               sysfs interface is still possible after
+                               boot.  Hypervisors will issue a warning
+                               when the first VM is started in a
+                               potentially insecure configuration,
+                               i.e. SMT enabled or L1D flush disabled.
+
+                       full,force
+                               Same as 'full', but disables SMT and L1D
+                               flush runtime control. Implies the
+                               'nosmt=force' command line option.
+                               (i.e. sysfs control of SMT is disabled.)
+
+                       flush
+                               Leaves SMT enabled and enables the default
+                               hypervisor mitigation, i.e. conditional
+                               L1D flush.
+
+                               SMT control and L1D flush control via the
+                               sysfs interface is still possible after
+                               boot.  Hypervisors will issue a warning
+                               when the first VM is started in a
+                               potentially insecure configuration,
+                               i.e. SMT enabled or L1D flush disabled.
+
+                       flush,nosmt
+
+                               Disables SMT and enables the default
+                               hypervisor mitigation.
+
+                               SMT control and L1D flush control via the
+                               sysfs interface is still possible after
+                               boot.  Hypervisors will issue a warning
+                               when the first VM is started in a
+                               potentially insecure configuration,
+                               i.e. SMT enabled or L1D flush disabled.
+
+                       flush,nowarn
+                               Same as 'flush', but hypervisors will not
+                               warn when a VM is started in a potentially
+                               insecure configuration.
+
+                       off
+                               Disables hypervisor mitigations and doesn't
+                               emit any warnings.
+
+                       Default is 'flush'.
+
+                       For details see: Documentation/admin-guide/l1tf.rst
+
        l2cr=           [PPC]
 
        l3cr=           [PPC]
index 267a8da7c694f36b264f94b6428f082e6f9436c1..0e856c0628b350dd6d1aca368e213a927156da07 100644 (file)
@@ -974,4 +974,16 @@ bool xen_set_default_idle(void);
 void stop_this_cpu(void *dummy);
 void df_debug(struct pt_regs *regs, long error_code);
 void microcode_check(void);
+
+enum l1tf_mitigations {
+       L1TF_MITIGATION_OFF,
+       L1TF_MITIGATION_FLUSH_NOWARN,
+       L1TF_MITIGATION_FLUSH,
+       L1TF_MITIGATION_FLUSH_NOSMT,
+       L1TF_MITIGATION_FULL,
+       L1TF_MITIGATION_FULL_FORCE
+};
+
+extern enum l1tf_mitigations l1tf_mitigation;
+
 #endif /* _ASM_X86_PROCESSOR_H */
index 603a6e46685231dfb2df5c87a7340965d83797f7..2409446189e95ea28bb412ccc18b8ccdba9c3ab8 100644 (file)
@@ -644,7 +644,11 @@ void x86_spec_ctrl_setup_ap(void)
 #undef pr_fmt
 #define pr_fmt(fmt)    "L1TF: " fmt
 
+/* Default mitigation for L1TF-affected CPUs */
+enum l1tf_mitigations l1tf_mitigation __ro_after_init = L1TF_MITIGATION_FLUSH;
 #if IS_ENABLED(CONFIG_KVM_INTEL)
+EXPORT_SYMBOL_GPL(l1tf_mitigation);
+
 enum vmx_l1d_flush_state l1tf_vmx_mitigation = VMENTER_L1D_FLUSH_AUTO;
 EXPORT_SYMBOL_GPL(l1tf_vmx_mitigation);
 #endif
@@ -656,6 +660,20 @@ static void __init l1tf_select_mitigation(void)
        if (!boot_cpu_has_bug(X86_BUG_L1TF))
                return;
 
+       switch (l1tf_mitigation) {
+       case L1TF_MITIGATION_OFF:
+       case L1TF_MITIGATION_FLUSH_NOWARN:
+       case L1TF_MITIGATION_FLUSH:
+               break;
+       case L1TF_MITIGATION_FLUSH_NOSMT:
+       case L1TF_MITIGATION_FULL:
+               cpu_smt_disable(false);
+               break;
+       case L1TF_MITIGATION_FULL_FORCE:
+               cpu_smt_disable(true);
+               break;
+       }
+
 #if CONFIG_PGTABLE_LEVELS == 2
        pr_warn("Kernel not compiled for PAE. No mitigation for L1TF\n");
        return;
@@ -674,6 +692,32 @@ static void __init l1tf_select_mitigation(void)
 
        setup_force_cpu_cap(X86_FEATURE_L1TF_PTEINV);
 }
+
+static int __init l1tf_cmdline(char *str)
+{
+       if (!boot_cpu_has_bug(X86_BUG_L1TF))
+               return 0;
+
+       if (!str)
+               return -EINVAL;
+
+       if (!strcmp(str, "off"))
+               l1tf_mitigation = L1TF_MITIGATION_OFF;
+       else if (!strcmp(str, "flush,nowarn"))
+               l1tf_mitigation = L1TF_MITIGATION_FLUSH_NOWARN;
+       else if (!strcmp(str, "flush"))
+               l1tf_mitigation = L1TF_MITIGATION_FLUSH;
+       else if (!strcmp(str, "flush,nosmt"))
+               l1tf_mitigation = L1TF_MITIGATION_FLUSH_NOSMT;
+       else if (!strcmp(str, "full"))
+               l1tf_mitigation = L1TF_MITIGATION_FULL;
+       else if (!strcmp(str, "full,force"))
+               l1tf_mitigation = L1TF_MITIGATION_FULL_FORCE;
+
+       return 0;
+}
+early_param("l1tf", l1tf_cmdline);
+
 #undef pr_fmt
 
 #ifdef CONFIG_SYSFS
index c158821bec301b6f89707d290798434d7d25b3c2..d077869f9228f81763d434ff641c14e76b4a758a 100644 (file)
@@ -70,9 +70,6 @@ static const struct x86_cpu_id vmx_cpu_id[] = {
 };
 MODULE_DEVICE_TABLE(x86cpu, vmx_cpu_id);
 
-static bool __read_mostly nosmt;
-module_param(nosmt, bool, S_IRUGO);
-
 static bool __read_mostly enable_vpid = 1;
 module_param_named(vpid, enable_vpid, bool, 0444);
 
@@ -218,15 +215,31 @@ static int vmx_setup_l1d_flush(enum vmx_l1d_flush_state l1tf)
 {
        struct page *page;
 
-       /* If set to 'auto' select 'cond' */
-       if (l1tf == VMENTER_L1D_FLUSH_AUTO)
-               l1tf = VMENTER_L1D_FLUSH_COND;
-
        if (!enable_ept) {
                l1tf_vmx_mitigation = VMENTER_L1D_FLUSH_EPT_DISABLED;
                return 0;
        }
 
+       /* If set to auto use the default l1tf mitigation method */
+       if (l1tf == VMENTER_L1D_FLUSH_AUTO) {
+               switch (l1tf_mitigation) {
+               case L1TF_MITIGATION_OFF:
+                       l1tf = VMENTER_L1D_FLUSH_NEVER;
+                       break;
+               case L1TF_MITIGATION_FLUSH_NOWARN:
+               case L1TF_MITIGATION_FLUSH:
+               case L1TF_MITIGATION_FLUSH_NOSMT:
+                       l1tf = VMENTER_L1D_FLUSH_COND;
+                       break;
+               case L1TF_MITIGATION_FULL:
+               case L1TF_MITIGATION_FULL_FORCE:
+                       l1tf = VMENTER_L1D_FLUSH_ALWAYS;
+                       break;
+               }
+       } else if (l1tf_mitigation == L1TF_MITIGATION_FULL_FORCE) {
+               l1tf = VMENTER_L1D_FLUSH_ALWAYS;
+       }
+
        if (l1tf != VMENTER_L1D_FLUSH_NEVER && !vmx_l1d_flush_pages &&
            !boot_cpu_has(X86_FEATURE_FLUSH_L1D)) {
                page = alloc_pages(GFP_KERNEL, L1D_CACHE_ORDER);
@@ -10036,16 +10049,33 @@ free_vcpu:
        return ERR_PTR(err);
 }
 
-#define L1TF_MSG "SMT enabled with L1TF CPU bug present. Refer to CVE-2018-3620 for details.\n"
+#define L1TF_MSG_SMT "L1TF CPU bug present and SMT on, data leak possible. See CVE-2018-3646 and https://www.kernel.org/doc/html/latest/admin-guide/l1tf.html for details.\n"
+#define L1TF_MSG_L1D "L1TF CPU bug present and virtualization mitigation disabled, data leak possible. See CVE-2018-3646 and https://www.kernel.org/doc/html/latest/admin-guide/l1tf.html for details.\n"
 
 static int vmx_vm_init(struct kvm *kvm)
 {
-       if (boot_cpu_has(X86_BUG_L1TF) && cpu_smt_control == CPU_SMT_ENABLED) {
-               if (nosmt) {
-                       pr_err(L1TF_MSG);
-                       return -EOPNOTSUPP;
+       if (boot_cpu_has(X86_BUG_L1TF) && enable_ept) {
+               switch (l1tf_mitigation) {
+               case L1TF_MITIGATION_OFF:
+               case L1TF_MITIGATION_FLUSH_NOWARN:
+                       /* 'I explicitly don't care' is set */
+                       break;
+               case L1TF_MITIGATION_FLUSH:
+               case L1TF_MITIGATION_FLUSH_NOSMT:
+               case L1TF_MITIGATION_FULL:
+                       /*
+                        * Warn upon starting the first VM in a potentially
+                        * insecure environment.
+                        */
+                       if (cpu_smt_control == CPU_SMT_ENABLED)
+                               pr_warn_once(L1TF_MSG_SMT);
+                       if (l1tf_vmx_mitigation == VMENTER_L1D_FLUSH_NEVER)
+                               pr_warn_once(L1TF_MSG_L1D);
+                       break;
+               case L1TF_MITIGATION_FULL_FORCE:
+                       /* Flush is enforced */
+                       break;
                }
-               pr_warn(L1TF_MSG);
        }
        return 0;
 }