Skip to content

Commit 8cb861e

Browse files
pa1guptasuryasaimadhu
authored andcommitted
x86/speculation/mmio: Add mitigation for Processor MMIO Stale Data
Processor MMIO Stale Data is a class of vulnerabilities that may expose data after an MMIO operation. For details please refer to Documentation/admin-guide/hw-vuln/processor_mmio_stale_data.rst. These vulnerabilities are broadly categorized as: Device Register Partial Write (DRPW): Some endpoint MMIO registers incorrectly handle writes that are smaller than the register size. Instead of aborting the write or only copying the correct subset of bytes (for example, 2 bytes for a 2-byte write), more bytes than specified by the write transaction may be written to the register. On some processors, this may expose stale data from the fill buffers of the core that created the write transaction. Shared Buffers Data Sampling (SBDS): After propagators may have moved data around the uncore and copied stale data into client core fill buffers, processors affected by MFBDS can leak data from the fill buffer. Shared Buffers Data Read (SBDR): It is similar to Shared Buffer Data Sampling (SBDS) except that the data is directly read into the architectural software-visible state. An attacker can use these vulnerabilities to extract data from CPU fill buffers using MDS and TAA methods. Mitigate it by clearing the CPU fill buffers using the VERW instruction before returning to a user or a guest. On CPUs not affected by MDS and TAA, user application cannot sample data from CPU fill buffers using MDS or TAA. A guest with MMIO access can still use DRPW or SBDR to extract data architecturally. Mitigate it with VERW instruction to clear fill buffers before VMENTER for MMIO capable guests. Add a kernel parameter mmio_stale_data={off|full|full,nosmt} to control the mitigation. Signed-off-by: Pawan Gupta <pawan.kumar.gupta@linux.intel.com> Signed-off-by: Borislav Petkov <bp@suse.de>
1 parent f52ea6c commit 8cb861e

4 files changed

Lines changed: 148 additions & 4 deletions

File tree

Documentation/admin-guide/kernel-parameters.txt

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3105,6 +3105,7 @@
31053105
kvm.nx_huge_pages=off [X86]
31063106
no_entry_flush [PPC]
31073107
no_uaccess_flush [PPC]
3108+
mmio_stale_data=off [X86]
31083109

31093110
Exceptions:
31103111
This does not have any effect on
@@ -3126,6 +3127,7 @@
31263127
Equivalent to: l1tf=flush,nosmt [X86]
31273128
mds=full,nosmt [X86]
31283129
tsx_async_abort=full,nosmt [X86]
3130+
mmio_stale_data=full,nosmt [X86]
31293131

31303132
mminit_loglevel=
31313133
[KNL] When CONFIG_DEBUG_MEMORY_INIT is set, this
@@ -3135,6 +3137,40 @@
31353137
log everything. Information is printed at KERN_DEBUG
31363138
so loglevel=8 may also need to be specified.
31373139

3140+
mmio_stale_data=
3141+
[X86,INTEL] Control mitigation for the Processor
3142+
MMIO Stale Data vulnerabilities.
3143+
3144+
Processor MMIO Stale Data is a class of
3145+
vulnerabilities that may expose data after an MMIO
3146+
operation. Exposed data could originate or end in
3147+
the same CPU buffers as affected by MDS and TAA.
3148+
Therefore, similar to MDS and TAA, the mitigation
3149+
is to clear the affected CPU buffers.
3150+
3151+
This parameter controls the mitigation. The
3152+
options are:
3153+
3154+
full - Enable mitigation on vulnerable CPUs
3155+
3156+
full,nosmt - Enable mitigation and disable SMT on
3157+
vulnerable CPUs.
3158+
3159+
off - Unconditionally disable mitigation
3160+
3161+
On MDS or TAA affected machines,
3162+
mmio_stale_data=off can be prevented by an active
3163+
MDS or TAA mitigation as these vulnerabilities are
3164+
mitigated with the same mechanism so in order to
3165+
disable this mitigation, you need to specify
3166+
mds=off and tsx_async_abort=off too.
3167+
3168+
Not specifying this option is equivalent to
3169+
mmio_stale_data=full.
3170+
3171+
For details see:
3172+
Documentation/admin-guide/hw-vuln/processor_mmio_stale_data.rst
3173+
31383174
module.sig_enforce
31393175
[KNL] When CONFIG_MODULE_SIG is set, this means that
31403176
modules without (valid) signatures will fail to load.

arch/x86/include/asm/nospec-branch.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,8 @@ DECLARE_STATIC_KEY_FALSE(mds_idle_clear);
269269

270270
DECLARE_STATIC_KEY_FALSE(switch_mm_cond_l1d_flush);
271271

272+
DECLARE_STATIC_KEY_FALSE(mmio_stale_data_clear);
273+
272274
#include <asm/segment.h>
273275

274276
/**

arch/x86/kernel/cpu/bugs.c

Lines changed: 107 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ static void __init l1tf_select_mitigation(void);
4343
static void __init mds_select_mitigation(void);
4444
static void __init md_clear_update_mitigation(void);
4545
static void __init taa_select_mitigation(void);
46+
static void __init mmio_select_mitigation(void);
4647
static void __init srbds_select_mitigation(void);
4748
static void __init l1d_flush_select_mitigation(void);
4849

@@ -85,6 +86,10 @@ EXPORT_SYMBOL_GPL(mds_idle_clear);
8586
*/
8687
DEFINE_STATIC_KEY_FALSE(switch_mm_cond_l1d_flush);
8788

89+
/* Controls CPU Fill buffer clear before KVM guest MMIO accesses */
90+
DEFINE_STATIC_KEY_FALSE(mmio_stale_data_clear);
91+
EXPORT_SYMBOL_GPL(mmio_stale_data_clear);
92+
8893
void __init check_bugs(void)
8994
{
9095
identify_boot_cpu();
@@ -119,12 +124,14 @@ void __init check_bugs(void)
119124
l1tf_select_mitigation();
120125
mds_select_mitigation();
121126
taa_select_mitigation();
127+
mmio_select_mitigation();
122128
srbds_select_mitigation();
123129
l1d_flush_select_mitigation();
124130

125131
/*
126-
* As MDS and TAA mitigations are inter-related, update and print their
127-
* mitigation after TAA mitigation selection is done.
132+
* As MDS, TAA and MMIO Stale Data mitigations are inter-related, update
133+
* and print their mitigation after MDS, TAA and MMIO Stale Data
134+
* mitigation selection is done.
128135
*/
129136
md_clear_update_mitigation();
130137

@@ -390,6 +397,90 @@ static int __init tsx_async_abort_parse_cmdline(char *str)
390397
}
391398
early_param("tsx_async_abort", tsx_async_abort_parse_cmdline);
392399

400+
#undef pr_fmt
401+
#define pr_fmt(fmt) "MMIO Stale Data: " fmt
402+
403+
enum mmio_mitigations {
404+
MMIO_MITIGATION_OFF,
405+
MMIO_MITIGATION_UCODE_NEEDED,
406+
MMIO_MITIGATION_VERW,
407+
};
408+
409+
/* Default mitigation for Processor MMIO Stale Data vulnerabilities */
410+
static enum mmio_mitigations mmio_mitigation __ro_after_init = MMIO_MITIGATION_VERW;
411+
static bool mmio_nosmt __ro_after_init = false;
412+
413+
static const char * const mmio_strings[] = {
414+
[MMIO_MITIGATION_OFF] = "Vulnerable",
415+
[MMIO_MITIGATION_UCODE_NEEDED] = "Vulnerable: Clear CPU buffers attempted, no microcode",
416+
[MMIO_MITIGATION_VERW] = "Mitigation: Clear CPU buffers",
417+
};
418+
419+
static void __init mmio_select_mitigation(void)
420+
{
421+
u64 ia32_cap;
422+
423+
if (!boot_cpu_has_bug(X86_BUG_MMIO_STALE_DATA) ||
424+
cpu_mitigations_off()) {
425+
mmio_mitigation = MMIO_MITIGATION_OFF;
426+
return;
427+
}
428+
429+
if (mmio_mitigation == MMIO_MITIGATION_OFF)
430+
return;
431+
432+
ia32_cap = x86_read_arch_cap_msr();
433+
434+
/*
435+
* Enable CPU buffer clear mitigation for host and VMM, if also affected
436+
* by MDS or TAA. Otherwise, enable mitigation for VMM only.
437+
*/
438+
if (boot_cpu_has_bug(X86_BUG_MDS) || (boot_cpu_has_bug(X86_BUG_TAA) &&
439+
boot_cpu_has(X86_FEATURE_RTM)))
440+
static_branch_enable(&mds_user_clear);
441+
else
442+
static_branch_enable(&mmio_stale_data_clear);
443+
444+
/*
445+
* Check if the system has the right microcode.
446+
*
447+
* CPU Fill buffer clear mitigation is enumerated by either an explicit
448+
* FB_CLEAR or by the presence of both MD_CLEAR and L1D_FLUSH on MDS
449+
* affected systems.
450+
*/
451+
if ((ia32_cap & ARCH_CAP_FB_CLEAR) ||
452+
(boot_cpu_has(X86_FEATURE_MD_CLEAR) &&
453+
boot_cpu_has(X86_FEATURE_FLUSH_L1D) &&
454+
!(ia32_cap & ARCH_CAP_MDS_NO)))
455+
mmio_mitigation = MMIO_MITIGATION_VERW;
456+
else
457+
mmio_mitigation = MMIO_MITIGATION_UCODE_NEEDED;
458+
459+
if (mmio_nosmt || cpu_mitigations_auto_nosmt())
460+
cpu_smt_disable(false);
461+
}
462+
463+
static int __init mmio_stale_data_parse_cmdline(char *str)
464+
{
465+
if (!boot_cpu_has_bug(X86_BUG_MMIO_STALE_DATA))
466+
return 0;
467+
468+
if (!str)
469+
return -EINVAL;
470+
471+
if (!strcmp(str, "off")) {
472+
mmio_mitigation = MMIO_MITIGATION_OFF;
473+
} else if (!strcmp(str, "full")) {
474+
mmio_mitigation = MMIO_MITIGATION_VERW;
475+
} else if (!strcmp(str, "full,nosmt")) {
476+
mmio_mitigation = MMIO_MITIGATION_VERW;
477+
mmio_nosmt = true;
478+
}
479+
480+
return 0;
481+
}
482+
early_param("mmio_stale_data", mmio_stale_data_parse_cmdline);
483+
393484
#undef pr_fmt
394485
#define pr_fmt(fmt) "" fmt
395486

@@ -402,19 +493,31 @@ static void __init md_clear_update_mitigation(void)
402493
goto out;
403494

404495
/*
405-
* mds_user_clear is now enabled. Update MDS mitigation, if
406-
* necessary.
496+
* mds_user_clear is now enabled. Update MDS, TAA and MMIO Stale Data
497+
* mitigation, if necessary.
407498
*/
408499
if (mds_mitigation == MDS_MITIGATION_OFF &&
409500
boot_cpu_has_bug(X86_BUG_MDS)) {
410501
mds_mitigation = MDS_MITIGATION_FULL;
411502
mds_select_mitigation();
412503
}
504+
if (taa_mitigation == TAA_MITIGATION_OFF &&
505+
boot_cpu_has_bug(X86_BUG_TAA)) {
506+
taa_mitigation = TAA_MITIGATION_VERW;
507+
taa_select_mitigation();
508+
}
509+
if (mmio_mitigation == MMIO_MITIGATION_OFF &&
510+
boot_cpu_has_bug(X86_BUG_MMIO_STALE_DATA)) {
511+
mmio_mitigation = MMIO_MITIGATION_VERW;
512+
mmio_select_mitigation();
513+
}
413514
out:
414515
if (boot_cpu_has_bug(X86_BUG_MDS))
415516
pr_info("MDS: %s\n", mds_strings[mds_mitigation]);
416517
if (boot_cpu_has_bug(X86_BUG_TAA))
417518
pr_info("TAA: %s\n", taa_strings[taa_mitigation]);
519+
if (boot_cpu_has_bug(X86_BUG_MMIO_STALE_DATA))
520+
pr_info("MMIO Stale Data: %s\n", mmio_strings[mmio_mitigation]);
418521
}
419522

420523
#undef pr_fmt

arch/x86/kvm/vmx/vmx.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6773,6 +6773,9 @@ static noinstr void vmx_vcpu_enter_exit(struct kvm_vcpu *vcpu,
67736773
vmx_l1d_flush(vcpu);
67746774
else if (static_branch_unlikely(&mds_user_clear))
67756775
mds_clear_cpu_buffers();
6776+
else if (static_branch_unlikely(&mmio_stale_data_clear) &&
6777+
kvm_arch_has_assigned_device(vcpu->kvm))
6778+
mds_clear_cpu_buffers();
67766779

67776780
if (vcpu->arch.cr2 != native_read_cr2())
67786781
native_write_cr2(vcpu->arch.cr2);

0 commit comments

Comments
 (0)