All of lore.kernel.org
 help / color / mirror / Atom feed
From: Thomas Gleixner <tglx@linutronix.de>
To: speck@linutronix.de
Subject: [patch 1/2] Command line and documentation 1
Date: Sun, 08 Jul 2018 14:52:17 +0200	[thread overview]
Message-ID: <20180708125654.729119463@linutronix.de> (raw)
In-Reply-To: 20180708125216.197406530@linutronix.de

From: Jiri Kosina <jkosina@suse.cz>
Subject: [patch 1/2] x86/bugs, kvm: introduce boot-time control of L1TF mitigations

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

The possible values are:

  full
	Provide all available mitigations for the L1TF
	vulnerability. Disable SMT and enable all mitigations
	in the hypervisors. SMT control is still possible
	after boot.

  full,force
	Same as 'full', but disables SMT control. Implies the
	'nosmt=force' command line option.

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

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

Default is 'novirt'.

Let KVM adhere to these semantics, which means:

  - 'lt1f=full,force'	: start performing L1D flushes
  - 'l1tf=full'		: start performing L1D flushes,
			  warn on VM start if SMT has
			  been runtime enabled
  - 'l1tf=novirt'	: warn on first VM start
  - 'l1tf=novirt,nowarn': no extra action is taken

This makes the 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.

Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---

v6->v7:
	- Fixed the CVE number
	- Slightly reworded the parameter description
	- Take the l1tf command line parameter into account when
	  initializing the VMX L1TF mitigation and expose the
	  vmx mitigation state to the core.
	- Make the sysfs l1tf file show the VMX mitigation state
	  in detail.

v5->v6:
	- 'full' implies 'nosmt', 'full,force' implies nosmt=force;
	  print KVM warnings accordingly (one state more, and having
	  bitflags would be needed for clarity)
	- now that we have full and full,force, drop KVM's private
	  nosmt option
	- drop compile-time option to chose the default default :)
	- typo/grammar fixes

v4->v5:
	- rebase on top of KVM bundle

v3->v4:
        - unconfuse the meaning of 'off', both in the documentation and in 
          the code (spotted by Josh)

v2->v3:
        - provide l1tf=[full,novirt,off]
        - provide config option to chose the default
        - let KVM warn in novirt case

v1->v2: add forgotten dependency on X86_BUG_L1TF


 Documentation/admin-guide/kernel-parameters.txt |   38 +++++++++-
 arch/x86/include/asm/processor.h                |   10 ++
 arch/x86/include/asm/vmx.h                      |    9 ++
 arch/x86/kernel/cpu/bugs.c                      |   84 +++++++++++++++++++++++-
 arch/x86/kvm/vmx.c                              |   58 ++++++++++++----
 include/linux/cpu.h                             |    2 
 kernel/cpu.c                                    |    9 ++
 7 files changed, 183 insertions(+), 27 deletions(-)

--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -1946,12 +1946,6 @@
 			[KVM,ARM] Allow use of GICv4 for direct injection of
 			LPIs.
 
-	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)
@@ -1989,6 +1983,38 @@
 			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 controlled.
+
+			full
+				Provide all available mitigations for the
+				L1TF vulnerability. Disable SMT and enable
+				all mitigations in the hypervisors. SMT
+				control is still possible after boot.
+
+			full,force
+				Same as 'full', but disables SMT
+				control. Implies the 'nosmt=force' command
+				line option.
+
+			novirt
+				Leaves SMT enabled and does not enable the
+				hypervisor mitigation. Hypervisors will
+				issue a warning when the first VM is being
+				started in a potentially insecure
+				configuration, i.e. SMT enabled or L1D
+				flush disabled.
+
+			novirt,nowarn
+				Same as 'novirt', but hypervisors will not
+				warn when a VM is started in a potentially
+				insecure configuration.
+
+			Default is 'novirt'.
+
 	l2cr=		[PPC]
 
 	l3cr=		[PPC]
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -982,4 +982,14 @@ 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_NOVIRT_NOWARN,
+	L1TF_MITIGATION_NOVIRT,
+	L1TF_MITIGATION_FULL,
+	L1TF_MITIGATION_FULL_FORCE
+};
+
+extern enum l1tf_mitigations l1tf_mitigation;
+
 #endif /* _ASM_X86_PROCESSOR_H */
--- a/arch/x86/include/asm/vmx.h
+++ b/arch/x86/include/asm/vmx.h
@@ -573,4 +573,13 @@ enum vm_instruction_error_number {
 	VMXERR_INVALID_OPERAND_TO_INVEPT_INVVPID = 28,
 };
 
+/* These MUST be in sync with vmentry_l1d_param order. */
+enum vmx_l1d_flush_state {
+	VMENTER_L1D_FLUSH_NEVER,
+	VMENTER_L1D_FLUSH_COND,
+	VMENTER_L1D_FLUSH_ALWAYS,
+};
+
+extern enum vmx_l1d_flush_state l1tf_vmx_mitigation;
+
 #endif
--- a/arch/x86/kernel/cpu/bugs.c
+++ b/arch/x86/kernel/cpu/bugs.c
@@ -23,6 +23,7 @@
 #include <asm/fpu/internal.h>
 #include <asm/msr.h>
 #include <asm/paravirt.h>
+#include <asm/vmx.h>
 #include <asm/alternative.h>
 #include <asm/pgtable.h>
 #include <asm/set_memory.h>
@@ -657,6 +658,20 @@ 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_NOVIRT;
+#if IS_ENABLED(CONFIG_KVM_INTEL)
+EXPORT_SYMBOL_GPL(l1tf_mitigation);
+
+/* Initialize it to unknown which indicates that VMX has not been initialized */
+#define L1TF_VMX_UNKNOWN	INT_MAX
+
+enum vmx_l1d_flush_state l1tf_vmx_mitigation = L1TF_VMX_UNKNOWN;
+EXPORT_SYMBOL_GPL(l1tf_vmx_mitigation);
+#endif
+
 static void __init l1tf_select_mitigation(void)
 {
 	u64 half_pa;
@@ -664,6 +679,18 @@ static void __init l1tf_select_mitigatio
 	if (!boot_cpu_has_bug(X86_BUG_L1TF))
 		return;
 
+	switch (l1tf_mitigation) {
+	case L1TF_MITIGATION_FULL_FORCE:
+		cpu_smt_disable(true);
+		break;
+	case L1TF_MITIGATION_FULL:
+		cpu_smt_disable(false);
+		break;
+	case L1TF_MITIGATION_NOVIRT:
+	case L1TF_MITIGATION_NOVIRT_NOWARN:
+		break;
+	}
+
 #if CONFIG_PGTABLE_LEVELS == 2
 	pr_warn("Kernel not compiled for PAE. No mitigation for L1TF\n");
 	return;
@@ -682,10 +709,63 @@ static void __init l1tf_select_mitigatio
 
 	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 0;
+
+	if (!strcmp(str, "full"))
+		l1tf_mitigation = L1TF_MITIGATION_FULL;
+	else if (!strcmp(str, "full,force"))
+		l1tf_mitigation = L1TF_MITIGATION_FULL_FORCE;
+	else if (!strcmp(str, "novirt"))
+		l1tf_mitigation = L1TF_MITIGATION_NOVIRT;
+	else if (!strcmp(str, "novirt,nowarn"))
+		l1tf_mitigation = L1TF_MITIGATION_NOVIRT_NOWARN;
+
+	return 0;
+}
+early_param("l1tf", l1tf_cmdline);
+
 #undef pr_fmt
 
 #ifdef CONFIG_SYSFS
 
+static const char *l1tf_states[] = {
+	[L1TF_MITIGATION_FULL]		= "Mitigation: Full",
+	[L1TF_MITIGATION_FULL_FORCE]	= "Mitigation: Full [force]",
+	[L1TF_MITIGATION_NOVIRT]	= "Mitigation: Page Table Inversion",
+	[L1TF_MITIGATION_NOVIRT_NOWARN]	= "Mitigation: Page Table Inversion"
+};
+
+#if IS_ENABLED(CONFIG_KVM_INTEL)
+static const char *l1tf_vmx_states[] = {
+	[VMENTER_L1D_FLUSH_NEVER]	= "vulnerable",
+	[VMENTER_L1D_FLUSH_COND]	= "mostly protected",
+	[VMENTER_L1D_FLUSH_ALWAYS]	= "fully protected"
+};
+
+static ssize_t l1tf_show_state(char *buf)
+{
+	if (l1tf_vmx_mitigation == L1TF_VMX_UNKNOWN)
+		return sprintf(buf, "%s\n", l1tf_states[l1tf_mitigation]);
+
+	return sprintf(buf, "%s, VMX: SMT %s L1D %s\n",
+		       l1tf_states[l1tf_mitigation],
+		       cpu_smt_control == CPU_SMT_ENABLED ? "vulnerable" : "disabled",
+		       l1tf_vmx_states[l1tf_vmx_mitigation]);
+}
+#else
+static ssize_t l1tf_show_state(char *buf)
+{
+	return sprintf(buf, "%s\n", l1tf_states[l1tf_mitigation]);
+}
+#endif
+
 static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr,
 			       char *buf, unsigned int bug)
 {
@@ -712,9 +792,7 @@ static ssize_t cpu_show_common(struct de
 		return sprintf(buf, "%s\n", ssb_strings[ssb_mode]);
 
 	case X86_BUG_L1TF:
-		if (boot_cpu_has(X86_FEATURE_L1TF_PTEINV))
-			return sprintf(buf, "Mitigation: Page Table Inversion\n");
-		break;
+		return l1tf_show_state(buf);
 
 	default:
 		break;
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -71,9 +71,6 @@ static const struct x86_cpu_id vmx_cpu_i
 };
 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);
 
@@ -193,13 +190,6 @@ extern const ulong vmx_return;
 
 static DEFINE_STATIC_KEY_FALSE(vmx_l1d_should_flush);
 
-/* These MUST be in sync with vmentry_l1d_param order. */
-enum vmx_l1d_flush_state {
-	VMENTER_L1D_FLUSH_NEVER,
-	VMENTER_L1D_FLUSH_COND,
-	VMENTER_L1D_FLUSH_ALWAYS,
-};
-
 static enum vmx_l1d_flush_state __read_mostly vmentry_l1d_flush = VMENTER_L1D_FLUSH_COND;
 
 static const struct {
@@ -10539,19 +10529,41 @@ static struct kvm_vcpu *vmx_create_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_NOVIRT "L1TF CPU bug present and virtualization mitigation disabled, data leak possible. Refer to CVE-2018-3646 for details.\n"
+#define L1TF_MSG_SMT "L1TF CPU bug present and SMT enabled, data leak possible. Refer to CVE-2018-3646 for details.\n"
 
 static int vmx_vm_init(struct kvm *kvm)
 {
 	if (!ple_gap)
 		kvm->arch.pause_in_guest = true;
 
-	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)) {
+		switch (l1tf_mitigation) {
+			case L1TF_MITIGATION_NOVIRT_NOWARN:
+				/* The 'I explicitly don't care' flag is set */
+				break;
+			case L1TF_MITIGATION_NOVIRT:
+				/*
+				 * Warn upon starting the first VM in a
+				 * potentially insecure environment.
+				 */
+				if (cpu_smt_control == CPU_SMT_ENABLED ||
+				    vmentry_l1d_flush == VMENTER_L1D_FLUSH_NEVER)
+					pr_warn_once(L1TF_MSG_NOVIRT);
+				break;
+			case L1TF_MITIGATION_FULL:
+				/*
+				 * Warn if SMT has been runtime-enabled. We can't
+				 * really warn only once here, as SMT state is
+				 * not constant.
+				 */
+				if (cpu_smt_control == CPU_SMT_ENABLED)
+					pr_warn(L1TF_MSG_SMT);
+				break;
+			case L1TF_MITIGATION_FULL_FORCE:
+				/* All is good, proceed without hiccup */
+				break;
 		}
-		pr_warn(L1TF_MSG);
 	}
 	return 0;
 }
@@ -13235,6 +13247,20 @@ static int __init vmx_setup_l1d_flush(vo
 {
 	struct page *page;
 
+	/* Take the l1tf command line parameter into account */
+	switch (l1tf_mitigation) {
+	case L1TF_MITIGATION_FULL:
+	case L1TF_MITIGATION_FULL_FORCE:
+		/* Respect the FLUSH ALWAYS module param */
+		if (vmentry_l1d_flush == VMENTER_L1D_FLUSH_NEVER)
+			vmentry_l1d_flush = VMENTER_L1D_FLUSH_COND;
+		break;
+	default:
+		break;
+	}
+
+	l1tf_vmx_mitigation = vmentry_l1d_flush;
+
 	if (vmentry_l1d_flush == VMENTER_L1D_FLUSH_NEVER ||
 	    !boot_cpu_has_bug(X86_BUG_L1TF) ||
 	    vmx_l1d_use_msr_save_list())
--- a/include/linux/cpu.h
+++ b/include/linux/cpu.h
@@ -177,8 +177,10 @@ enum cpuhp_smt_control {
 
 #if defined(CONFIG_SMP) && defined(CONFIG_HOTPLUG_SMT)
 extern enum cpuhp_smt_control cpu_smt_control;
+void cpu_smt_disable(bool force);
 #else
 # define cpu_smt_control		(CPU_SMT_ENABLED)
+static inline void cpu_smt_disable(bool force) { }
 #endif
 
 #endif /* _LINUX_CPU_H_ */
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -347,13 +347,18 @@ EXPORT_SYMBOL_GPL(cpu_hotplug_enable);
 enum cpuhp_smt_control cpu_smt_control __read_mostly = CPU_SMT_ENABLED;
 EXPORT_SYMBOL_GPL(cpu_smt_control);
 
-static int __init smt_cmdline_disable(char *str)
+void __init cpu_smt_disable(bool force)
 {
 	cpu_smt_control = CPU_SMT_DISABLED;
-	if (str && !strcmp(str, "force")) {
+	if (force) {
 		pr_info("SMT: Force disabled\n");
 		cpu_smt_control = CPU_SMT_FORCE_DISABLED;
 	}
+}
+
+static int __init smt_cmdline_disable(char *str)
+{
+	cpu_smt_disable(str && !strcmp(str, "force"));
 	return 0;
 }
 early_param("nosmt", smt_cmdline_disable);

  reply	other threads:[~2018-07-08 13:11 UTC|newest]

Thread overview: 53+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-07-08 12:52 [patch 0/2] Command line and documentation 0 Thomas Gleixner
2018-07-08 12:52 ` Thomas Gleixner [this message]
2018-07-08 14:00   ` [MODERATED] Re: [patch 1/2] Command line and documentation 1 Josh Poimboeuf
2018-07-08 14:13     ` Thomas Gleixner
2018-07-08 15:21       ` [MODERATED] " Josh Poimboeuf
2018-07-09  7:07         ` Thomas Gleixner
2018-07-09 13:14           ` Thomas Gleixner
2018-07-09 13:21             ` [MODERATED] " Jiri Kosina
2018-07-09 13:25               ` Jiri Kosina
2018-07-09 15:32             ` Josh Poimboeuf
2018-07-09 15:40               ` Thomas Gleixner
2018-07-09 15:44               ` [MODERATED] " Jiri Kosina
2018-07-08 20:32   ` Jiri Kosina
2018-07-09  0:33     ` Jon Masters
2018-07-09 10:26   ` Ingo Molnar
2018-07-09 21:45   ` Andi Kleen
2018-07-09 22:08     ` Andi Kleen
2018-07-09 22:40     ` Jiri Kosina
2018-07-10 11:53     ` Thomas Gleixner
2018-07-08 12:52 ` [patch 2/2] Command line and documentation 2 Thomas Gleixner
2018-07-08 14:40   ` [MODERATED] " Andrew Cooper
2018-07-09  7:05     ` Thomas Gleixner
2018-07-08 15:40   ` [MODERATED] " Josh Poimboeuf
2018-07-09 11:04   ` Ingo Molnar
2018-07-09 11:08     ` Jiri Kosina
2018-07-09 11:47       ` Ingo Molnar
2018-07-09 15:18     ` Thomas Gleixner
2018-07-09 22:07   ` [MODERATED] " Andi Kleen
2018-07-09 23:00     ` Josh Poimboeuf
2018-07-09 23:11       ` Andi Kleen
2018-07-09 23:45         ` Linus Torvalds
2018-07-10  2:44           ` Josh Poimboeuf
2018-07-10  5:57             ` Jiri Kosina
2018-07-10  6:22               ` Jiri Kosina
2018-07-10 17:46             ` Linus Torvalds
2018-07-10 21:22               ` Thomas Gleixner
2018-07-10 21:30                 ` [MODERATED] " Linus Torvalds
2018-07-10 21:53                   ` Linus Torvalds
2018-07-10 22:27                     ` Thomas Gleixner
2018-07-10 22:37                       ` [MODERATED] " Linus Torvalds
2018-07-10 22:42                         ` Linus Torvalds
2018-07-10 22:50                       ` Josh Poimboeuf
2018-07-11 13:56                         ` Jon Masters
2018-07-11 14:48                           ` Josh Poimboeuf
2018-07-10 22:20                   ` Thomas Gleixner
2018-07-10 22:35                     ` [MODERATED] " Linus Torvalds
2018-07-10  7:41         ` Thomas Gleixner
2018-07-10  8:44           ` [MODERATED] " Jiri Kosina
2018-07-10 10:32             ` Jiri Kosina
2018-07-10 22:57             ` Josh Poimboeuf
2018-07-10 19:36     ` Thomas Gleixner
2018-07-11 14:03     ` [MODERATED] " Jon Masters
2018-07-08 13:11 ` [patch 0/2] Command line and documentation 0 Thomas Gleixner

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180708125654.729119463@linutronix.de \
    --to=tglx@linutronix.de \
    --cc=speck@linutronix.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.