mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-06 19:08:57 +09:00
KVM: x86/speculation: Disable Fill buffer clear within guests
commit 027bbb884b upstream
The enumeration of MD_CLEAR in CPUID(EAX=7,ECX=0).EDX{bit 10} is not an
accurate indicator on all CPUs of whether the VERW instruction will
overwrite fill buffers. FB_CLEAR enumeration in
IA32_ARCH_CAPABILITIES{bit 17} covers the case of CPUs that are not
vulnerable to MDS/TAA, indicating that microcode does overwrite fill
buffers.
Guests running in VMM environments may not be aware of all the
capabilities/vulnerabilities of the host CPU. Specifically, a guest may
apply MDS/TAA mitigations when a virtual CPU is enumerated as vulnerable
to MDS/TAA even when the physical CPU is not. On CPUs that enumerate
FB_CLEAR_CTRL the VMM may set FB_CLEAR_DIS to skip overwriting of fill
buffers by the VERW instruction. This is done by setting FB_CLEAR_DIS
during VMENTER and resetting on VMEXIT. For guests that enumerate
FB_CLEAR (explicitly asking for fill buffer clear capability) the VMM
will not use FB_CLEAR_DIS.
Irrespective of guest state, host overwrites CPU buffers before VMENTER
to protect itself from an MMIO capable guest, as part of mitigation for
MMIO Stale Data vulnerabilities.
Signed-off-by: Pawan Gupta <pawan.kumar.gupta@linux.intel.com>
Signed-off-by: Borislav Petkov <bp@suse.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
[cascardo: arch/x86/kvm/vmx.c has been split and context adjustment at
vmx_vcpu_run]
[cascardo: moved functions so they are after struct vcpu_vmx definition]
[cascardo: fb_clear is disabled/enabled around __vmx_vcpu_run]
[cascardo: conflict context fixups]
Signed-off-by: Thadeu Lima de Souza Cascardo <cascardo@canonical.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
b7efb3a62f
commit
da06c60d1d
@@ -108,6 +108,11 @@
|
||||
* VERW clears CPU fill buffer
|
||||
* even on MDS_NO CPUs.
|
||||
*/
|
||||
#define ARCH_CAP_FB_CLEAR_CTRL BIT(18) /*
|
||||
* MSR_IA32_MCU_OPT_CTRL[FB_CLEAR_DIS]
|
||||
* bit available to control VERW
|
||||
* behavior.
|
||||
*/
|
||||
|
||||
#define MSR_IA32_FLUSH_CMD 0x0000010b
|
||||
#define L1D_FLUSH BIT(0) /*
|
||||
@@ -125,6 +130,7 @@
|
||||
/* SRBDS support */
|
||||
#define MSR_IA32_MCU_OPT_CTRL 0x00000123
|
||||
#define RNGDS_MITG_DIS BIT(0)
|
||||
#define FB_CLEAR_DIS BIT(3) /* CPU Fill buffer clear disable */
|
||||
|
||||
#define MSR_IA32_SYSENTER_CS 0x00000174
|
||||
#define MSR_IA32_SYSENTER_ESP 0x00000175
|
||||
|
||||
@@ -211,6 +211,9 @@ static const struct {
|
||||
#define L1D_CACHE_ORDER 4
|
||||
static void *vmx_l1d_flush_pages;
|
||||
|
||||
/* Control for disabling CPU Fill buffer clear */
|
||||
static bool __read_mostly vmx_fb_clear_ctrl_available;
|
||||
|
||||
static int vmx_setup_l1d_flush(enum vmx_l1d_flush_state l1tf)
|
||||
{
|
||||
struct page *page;
|
||||
@@ -794,6 +797,8 @@ struct vcpu_vmx {
|
||||
*/
|
||||
u64 msr_ia32_feature_control;
|
||||
u64 msr_ia32_feature_control_valid_bits;
|
||||
u64 msr_ia32_mcu_opt_ctrl;
|
||||
bool disable_fb_clear;
|
||||
};
|
||||
|
||||
enum segment_cache_field {
|
||||
@@ -1573,6 +1578,60 @@ static inline void __invept(unsigned long ext, u64 eptp, gpa_t gpa)
|
||||
: : "a" (&operand), "c" (ext) : "cc", "memory");
|
||||
}
|
||||
|
||||
static void vmx_setup_fb_clear_ctrl(void)
|
||||
{
|
||||
u64 msr;
|
||||
|
||||
if (boot_cpu_has(X86_FEATURE_ARCH_CAPABILITIES) &&
|
||||
!boot_cpu_has_bug(X86_BUG_MDS) &&
|
||||
!boot_cpu_has_bug(X86_BUG_TAA)) {
|
||||
rdmsrl(MSR_IA32_ARCH_CAPABILITIES, msr);
|
||||
if (msr & ARCH_CAP_FB_CLEAR_CTRL)
|
||||
vmx_fb_clear_ctrl_available = true;
|
||||
}
|
||||
}
|
||||
|
||||
static __always_inline void vmx_disable_fb_clear(struct vcpu_vmx *vmx)
|
||||
{
|
||||
u64 msr;
|
||||
|
||||
if (!vmx->disable_fb_clear)
|
||||
return;
|
||||
|
||||
rdmsrl(MSR_IA32_MCU_OPT_CTRL, msr);
|
||||
msr |= FB_CLEAR_DIS;
|
||||
wrmsrl(MSR_IA32_MCU_OPT_CTRL, msr);
|
||||
/* Cache the MSR value to avoid reading it later */
|
||||
vmx->msr_ia32_mcu_opt_ctrl = msr;
|
||||
}
|
||||
|
||||
static __always_inline void vmx_enable_fb_clear(struct vcpu_vmx *vmx)
|
||||
{
|
||||
if (!vmx->disable_fb_clear)
|
||||
return;
|
||||
|
||||
vmx->msr_ia32_mcu_opt_ctrl &= ~FB_CLEAR_DIS;
|
||||
wrmsrl(MSR_IA32_MCU_OPT_CTRL, vmx->msr_ia32_mcu_opt_ctrl);
|
||||
}
|
||||
|
||||
static void vmx_update_fb_clear_dis(struct kvm_vcpu *vcpu, struct vcpu_vmx *vmx)
|
||||
{
|
||||
vmx->disable_fb_clear = vmx_fb_clear_ctrl_available;
|
||||
|
||||
/*
|
||||
* If guest will not execute VERW, there is no need to set FB_CLEAR_DIS
|
||||
* at VMEntry. Skip the MSR read/write when a guest has no use case to
|
||||
* execute VERW.
|
||||
*/
|
||||
if ((vcpu->arch.arch_capabilities & ARCH_CAP_FB_CLEAR) ||
|
||||
((vcpu->arch.arch_capabilities & ARCH_CAP_MDS_NO) &&
|
||||
(vcpu->arch.arch_capabilities & ARCH_CAP_TAA_NO) &&
|
||||
(vcpu->arch.arch_capabilities & ARCH_CAP_PSDP_NO) &&
|
||||
(vcpu->arch.arch_capabilities & ARCH_CAP_FBSDP_NO) &&
|
||||
(vcpu->arch.arch_capabilities & ARCH_CAP_SBDR_SSDP_NO)))
|
||||
vmx->disable_fb_clear = false;
|
||||
}
|
||||
|
||||
static struct shared_msr_entry *find_msr_entry(struct vcpu_vmx *vmx, u32 msr)
|
||||
{
|
||||
int i;
|
||||
@@ -3407,9 +3466,13 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
|
||||
}
|
||||
break;
|
||||
}
|
||||
ret = kvm_set_msr_common(vcpu, msr_info);
|
||||
ret = kvm_set_msr_common(vcpu, msr_info);
|
||||
}
|
||||
|
||||
/* FB_CLEAR may have changed, also update the FB_CLEAR_DIS behavior */
|
||||
if (msr_index == MSR_IA32_ARCH_CAPABILITIES)
|
||||
vmx_update_fb_clear_dis(vcpu, vmx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -5544,6 +5607,8 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
|
||||
update_exception_bitmap(vcpu);
|
||||
|
||||
vpid_sync_context(vmx->vpid);
|
||||
|
||||
vmx_update_fb_clear_dis(vcpu, vmx);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -9181,6 +9246,8 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
|
||||
kvm_arch_has_assigned_device(vcpu->kvm))
|
||||
mds_clear_cpu_buffers();
|
||||
|
||||
vmx_disable_fb_clear(vmx);
|
||||
|
||||
asm(
|
||||
/* Store host registers */
|
||||
"push %%" _ASM_DX "; push %%" _ASM_BP ";"
|
||||
@@ -9298,6 +9365,8 @@ static void __noclone vmx_vcpu_run(struct kvm_vcpu *vcpu)
|
||||
#endif
|
||||
);
|
||||
|
||||
vmx_enable_fb_clear(vmx);
|
||||
|
||||
/*
|
||||
* We do not use IBRS in the kernel. If this vCPU has used the
|
||||
* SPEC_CTRL MSR it may have left it on; save the value and
|
||||
@@ -11882,8 +11951,11 @@ static int __init vmx_init(void)
|
||||
}
|
||||
}
|
||||
|
||||
vmx_setup_fb_clear_ctrl();
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
INIT_LIST_HEAD(&per_cpu(loaded_vmcss_on_cpu, cpu));
|
||||
|
||||
INIT_LIST_HEAD(&per_cpu(blocked_vcpu_on_cpu, cpu));
|
||||
spin_lock_init(&per_cpu(blocked_vcpu_on_cpu_lock, cpu));
|
||||
}
|
||||
|
||||
@@ -1090,6 +1090,10 @@ u64 kvm_get_arch_capabilities(void)
|
||||
|
||||
/* KVM does not emulate MSR_IA32_TSX_CTRL. */
|
||||
data &= ~ARCH_CAP_TSX_CTRL_MSR;
|
||||
|
||||
/* Guests don't need to know "Fill buffer clear control" exists */
|
||||
data &= ~ARCH_CAP_FB_CLEAR_CTRL;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user