diff options
Diffstat (limited to 'arch/x86/kernel/cpu/bugs.c')
| -rw-r--r-- | arch/x86/kernel/cpu/bugs.c | 135 | 
1 files changed, 131 insertions, 4 deletions
diff --git a/arch/x86/kernel/cpu/bugs.c b/arch/x86/kernel/cpu/bugs.c index 29630393f300..03b4cc0ec3a7 100644 --- a/arch/x86/kernel/cpu/bugs.c +++ b/arch/x86/kernel/cpu/bugs.c @@ -37,6 +37,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);  /* The base value of the SPEC_CTRL MSR that always has to be preserved. */  u64 x86_spec_ctrl_base; @@ -63,6 +64,13 @@ DEFINE_STATIC_KEY_FALSE(switch_mm_cond_ibpb);  /* Control unconditional IBPB in switch_mm() */  DEFINE_STATIC_KEY_FALSE(switch_mm_always_ibpb); +/* Control MDS CPU buffer clear before returning to user space */ +DEFINE_STATIC_KEY_FALSE(mds_user_clear); +EXPORT_SYMBOL_GPL(mds_user_clear); +/* Control MDS CPU buffer clear before idling (halt, mwait) */ +DEFINE_STATIC_KEY_FALSE(mds_idle_clear); +EXPORT_SYMBOL_GPL(mds_idle_clear); +  void __init check_bugs(void)  {  	identify_boot_cpu(); @@ -101,6 +109,10 @@ void __init check_bugs(void)  	l1tf_select_mitigation(); +	mds_select_mitigation(); + +	arch_smt_update(); +  #ifdef CONFIG_X86_32  	/*  	 * Check whether we are able to run this kernel safely on SMP. @@ -207,6 +219,61 @@ static void x86_amd_ssb_disable(void)  }  #undef pr_fmt +#define pr_fmt(fmt)	"MDS: " fmt + +/* Default mitigation for MDS-affected CPUs */ +static enum mds_mitigations mds_mitigation __ro_after_init = MDS_MITIGATION_FULL; +static bool mds_nosmt __ro_after_init = false; + +static const char * const mds_strings[] = { +	[MDS_MITIGATION_OFF]	= "Vulnerable", +	[MDS_MITIGATION_FULL]	= "Mitigation: Clear CPU buffers", +	[MDS_MITIGATION_VMWERV]	= "Vulnerable: Clear CPU buffers attempted, no microcode", +}; + +static void __init mds_select_mitigation(void) +{ +	if (!boot_cpu_has_bug(X86_BUG_MDS) || cpu_mitigations_off()) { +		mds_mitigation = MDS_MITIGATION_OFF; +		return; +	} + +	if (mds_mitigation == MDS_MITIGATION_FULL) { +		if (!boot_cpu_has(X86_FEATURE_MD_CLEAR)) +			mds_mitigation = MDS_MITIGATION_VMWERV; + +		static_branch_enable(&mds_user_clear); + +		if (!boot_cpu_has(X86_BUG_MSBDS_ONLY) && +		    (mds_nosmt || cpu_mitigations_auto_nosmt())) +			cpu_smt_disable(false); +	} + +	pr_info("%s\n", mds_strings[mds_mitigation]); +} + +static int __init mds_cmdline(char *str) +{ +	if (!boot_cpu_has_bug(X86_BUG_MDS)) +		return 0; + +	if (!str) +		return -EINVAL; + +	if (!strcmp(str, "off")) +		mds_mitigation = MDS_MITIGATION_OFF; +	else if (!strcmp(str, "full")) +		mds_mitigation = MDS_MITIGATION_FULL; +	else if (!strcmp(str, "full,nosmt")) { +		mds_mitigation = MDS_MITIGATION_FULL; +		mds_nosmt = true; +	} + +	return 0; +} +early_param("mds", mds_cmdline); + +#undef pr_fmt  #define pr_fmt(fmt)     "Spectre V2 : " fmt  static enum spectre_v2_mitigation spectre_v2_enabled __ro_after_init = @@ -575,9 +642,6 @@ specv2_set_mode:  	/* Set up IBPB and STIBP depending on the general spectre V2 command */  	spectre_v2_user_select_mitigation(cmd); - -	/* Enable STIBP if appropriate */ -	arch_smt_update();  }  static void update_stibp_msr(void * __unused) @@ -611,6 +675,31 @@ static void update_indir_branch_cond(void)  		static_branch_disable(&switch_to_cond_stibp);  } +#undef pr_fmt +#define pr_fmt(fmt) fmt + +/* Update the static key controlling the MDS CPU buffer clear in idle */ +static void update_mds_branch_idle(void) +{ +	/* +	 * Enable the idle clearing if SMT is active on CPUs which are +	 * affected only by MSBDS and not any other MDS variant. +	 * +	 * The other variants cannot be mitigated when SMT is enabled, so +	 * clearing the buffers on idle just to prevent the Store Buffer +	 * repartitioning leak would be a window dressing exercise. +	 */ +	if (!boot_cpu_has_bug(X86_BUG_MSBDS_ONLY)) +		return; + +	if (sched_smt_active()) +		static_branch_enable(&mds_idle_clear); +	else +		static_branch_disable(&mds_idle_clear); +} + +#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" +  void arch_smt_update(void)  {  	/* Enhanced IBRS implies STIBP. No update required. */ @@ -632,6 +721,17 @@ void arch_smt_update(void)  		break;  	} +	switch (mds_mitigation) { +	case MDS_MITIGATION_FULL: +	case MDS_MITIGATION_VMWERV: +		if (sched_smt_active() && !boot_cpu_has(X86_BUG_MSBDS_ONLY)) +			pr_warn_once(MDS_MSG_SMT); +		update_mds_branch_idle(); +		break; +	case MDS_MITIGATION_OFF: +		break; +	} +  	mutex_unlock(&spec_ctrl_mutex);  } @@ -1043,7 +1143,7 @@ static void __init l1tf_select_mitigation(void)  		pr_info("You may make it effective by booting the kernel with mem=%llu parameter.\n",  				half_pa);  		pr_info("However, doing so will make a part of your RAM unusable.\n"); -		pr_info("Reading https://www.kernel.org/doc/html/latest/admin-guide/l1tf.html might help you decide.\n"); +		pr_info("Reading https://www.kernel.org/doc/html/latest/admin-guide/hw-vuln/l1tf.html might help you decide.\n");  		return;  	} @@ -1076,6 +1176,7 @@ static int __init l1tf_cmdline(char *str)  early_param("l1tf", l1tf_cmdline);  #undef pr_fmt +#define pr_fmt(fmt) fmt  #ifdef CONFIG_SYSFS @@ -1114,6 +1215,23 @@ static ssize_t l1tf_show_state(char *buf)  }  #endif +static ssize_t mds_show_state(char *buf) +{ +	if (!hypervisor_is_type(X86_HYPER_NATIVE)) { +		return sprintf(buf, "%s; SMT Host state unknown\n", +			       mds_strings[mds_mitigation]); +	} + +	if (boot_cpu_has(X86_BUG_MSBDS_ONLY)) { +		return sprintf(buf, "%s; SMT %s\n", mds_strings[mds_mitigation], +			       (mds_mitigation == MDS_MITIGATION_OFF ? "vulnerable" : +			        sched_smt_active() ? "mitigated" : "disabled")); +	} + +	return sprintf(buf, "%s; SMT %s\n", mds_strings[mds_mitigation], +		       sched_smt_active() ? "vulnerable" : "disabled"); +} +  static char *stibp_state(void)  {  	if (spectre_v2_enabled == SPECTRE_V2_IBRS_ENHANCED) @@ -1180,6 +1298,10 @@ static ssize_t cpu_show_common(struct device *dev, struct device_attribute *attr  		if (boot_cpu_has(X86_FEATURE_L1TF_PTEINV))  			return l1tf_show_state(buf);  		break; + +	case X86_BUG_MDS: +		return mds_show_state(buf); +  	default:  		break;  	} @@ -1211,4 +1333,9 @@ ssize_t cpu_show_l1tf(struct device *dev, struct device_attribute *attr, char *b  {  	return cpu_show_common(dev, attr, buf, X86_BUG_L1TF);  } + +ssize_t cpu_show_mds(struct device *dev, struct device_attribute *attr, char *buf) +{ +	return cpu_show_common(dev, attr, buf, X86_BUG_MDS); +}  #endif  |