KVM: x86/speculation: Disable Fill buffer clear within guests
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>
This commit is contained in:
parent
a992b8a468
commit
027bbb884b
@ -133,6 +133,11 @@
|
|||||||
* VERW clears CPU fill buffer
|
* VERW clears CPU fill buffer
|
||||||
* even on MDS_NO CPUs.
|
* 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 MSR_IA32_FLUSH_CMD 0x0000010b
|
||||||
#define L1D_FLUSH BIT(0) /*
|
#define L1D_FLUSH BIT(0) /*
|
||||||
@ -150,6 +155,7 @@
|
|||||||
#define MSR_IA32_MCU_OPT_CTRL 0x00000123
|
#define MSR_IA32_MCU_OPT_CTRL 0x00000123
|
||||||
#define RNGDS_MITG_DIS BIT(0) /* SRBDS support */
|
#define RNGDS_MITG_DIS BIT(0) /* SRBDS support */
|
||||||
#define RTM_ALLOW BIT(1) /* TSX development mode */
|
#define RTM_ALLOW BIT(1) /* TSX development mode */
|
||||||
|
#define FB_CLEAR_DIS BIT(3) /* CPU Fill buffer clear disable */
|
||||||
|
|
||||||
#define MSR_IA32_SYSENTER_CS 0x00000174
|
#define MSR_IA32_SYSENTER_CS 0x00000174
|
||||||
#define MSR_IA32_SYSENTER_ESP 0x00000175
|
#define MSR_IA32_SYSENTER_ESP 0x00000175
|
||||||
|
@ -229,6 +229,9 @@ static const struct {
|
|||||||
#define L1D_CACHE_ORDER 4
|
#define L1D_CACHE_ORDER 4
|
||||||
static void *vmx_l1d_flush_pages;
|
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)
|
static int vmx_setup_l1d_flush(enum vmx_l1d_flush_state l1tf)
|
||||||
{
|
{
|
||||||
struct page *page;
|
struct page *page;
|
||||||
@ -360,6 +363,60 @@ static int vmentry_l1d_flush_get(char *s, const struct kernel_param *kp)
|
|||||||
return sprintf(s, "%s\n", vmentry_l1d_param[l1tf_vmx_mitigation].option);
|
return sprintf(s, "%s\n", vmentry_l1d_param[l1tf_vmx_mitigation].option);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 const struct kernel_param_ops vmentry_l1d_flush_ops = {
|
static const struct kernel_param_ops vmentry_l1d_flush_ops = {
|
||||||
.set = vmentry_l1d_flush_set,
|
.set = vmentry_l1d_flush_set,
|
||||||
.get = vmentry_l1d_flush_get,
|
.get = vmentry_l1d_flush_get,
|
||||||
@ -2252,6 +2309,10 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
|
|||||||
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4553,6 +4614,8 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
|
|||||||
kvm_make_request(KVM_REQ_APIC_PAGE_RELOAD, vcpu);
|
kvm_make_request(KVM_REQ_APIC_PAGE_RELOAD, vcpu);
|
||||||
|
|
||||||
vpid_sync_context(vmx->vpid);
|
vpid_sync_context(vmx->vpid);
|
||||||
|
|
||||||
|
vmx_update_fb_clear_dis(vcpu, vmx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vmx_enable_irq_window(struct kvm_vcpu *vcpu)
|
static void vmx_enable_irq_window(struct kvm_vcpu *vcpu)
|
||||||
@ -6777,6 +6840,8 @@ static noinstr void vmx_vcpu_enter_exit(struct kvm_vcpu *vcpu,
|
|||||||
kvm_arch_has_assigned_device(vcpu->kvm))
|
kvm_arch_has_assigned_device(vcpu->kvm))
|
||||||
mds_clear_cpu_buffers();
|
mds_clear_cpu_buffers();
|
||||||
|
|
||||||
|
vmx_disable_fb_clear(vmx);
|
||||||
|
|
||||||
if (vcpu->arch.cr2 != native_read_cr2())
|
if (vcpu->arch.cr2 != native_read_cr2())
|
||||||
native_write_cr2(vcpu->arch.cr2);
|
native_write_cr2(vcpu->arch.cr2);
|
||||||
|
|
||||||
@ -6785,6 +6850,8 @@ static noinstr void vmx_vcpu_enter_exit(struct kvm_vcpu *vcpu,
|
|||||||
|
|
||||||
vcpu->arch.cr2 = native_read_cr2();
|
vcpu->arch.cr2 = native_read_cr2();
|
||||||
|
|
||||||
|
vmx_enable_fb_clear(vmx);
|
||||||
|
|
||||||
guest_state_exit_irqoff();
|
guest_state_exit_irqoff();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -8185,6 +8252,8 @@ static int __init vmx_init(void)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vmx_setup_fb_clear_ctrl();
|
||||||
|
|
||||||
for_each_possible_cpu(cpu) {
|
for_each_possible_cpu(cpu) {
|
||||||
INIT_LIST_HEAD(&per_cpu(loaded_vmcss_on_cpu, cpu));
|
INIT_LIST_HEAD(&per_cpu(loaded_vmcss_on_cpu, cpu));
|
||||||
|
|
||||||
|
@ -348,6 +348,8 @@ struct vcpu_vmx {
|
|||||||
u64 msr_ia32_feature_control_valid_bits;
|
u64 msr_ia32_feature_control_valid_bits;
|
||||||
/* SGX Launch Control public key hash */
|
/* SGX Launch Control public key hash */
|
||||||
u64 msr_ia32_sgxlepubkeyhash[4];
|
u64 msr_ia32_sgxlepubkeyhash[4];
|
||||||
|
u64 msr_ia32_mcu_opt_ctrl;
|
||||||
|
bool disable_fb_clear;
|
||||||
|
|
||||||
struct pt_desc pt_desc;
|
struct pt_desc pt_desc;
|
||||||
struct lbr_desc lbr_desc;
|
struct lbr_desc lbr_desc;
|
||||||
|
@ -1587,6 +1587,9 @@ static u64 kvm_get_arch_capabilities(void)
|
|||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Guests don't need to know "Fill buffer clear control" exists */
|
||||||
|
data &= ~ARCH_CAP_FB_CLEAR_CTRL;
|
||||||
|
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,6 +133,11 @@
|
|||||||
* VERW clears CPU fill buffer
|
* VERW clears CPU fill buffer
|
||||||
* even on MDS_NO CPUs.
|
* 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 MSR_IA32_FLUSH_CMD 0x0000010b
|
||||||
#define L1D_FLUSH BIT(0) /*
|
#define L1D_FLUSH BIT(0) /*
|
||||||
@ -150,6 +155,7 @@
|
|||||||
#define MSR_IA32_MCU_OPT_CTRL 0x00000123
|
#define MSR_IA32_MCU_OPT_CTRL 0x00000123
|
||||||
#define RNGDS_MITG_DIS BIT(0) /* SRBDS support */
|
#define RNGDS_MITG_DIS BIT(0) /* SRBDS support */
|
||||||
#define RTM_ALLOW BIT(1) /* TSX development mode */
|
#define RTM_ALLOW BIT(1) /* TSX development mode */
|
||||||
|
#define FB_CLEAR_DIS BIT(3) /* CPU Fill buffer clear disable */
|
||||||
|
|
||||||
#define MSR_IA32_SYSENTER_CS 0x00000174
|
#define MSR_IA32_SYSENTER_CS 0x00000174
|
||||||
#define MSR_IA32_SYSENTER_ESP 0x00000175
|
#define MSR_IA32_SYSENTER_ESP 0x00000175
|
||||||
|
Loading…
Reference in New Issue
Block a user