Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d49c2209 authored by Pawan Gupta's avatar Pawan Gupta Committed by Greg Kroah-Hartman
Browse files

KVM: x86/speculation: Disable Fill buffer clear within guests



commit 027bbb884be006b05d9c577d6401686053aa789e 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: default avatarPawan Gupta <pawan.kumar.gupta@linux.intel.com>
Signed-off-by: default avatarBorislav Petkov <bp@suse.de>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent d9615926
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -124,6 +124,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)	/*
@@ -141,6 +146,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
+71 −1
Original line number Diff line number Diff line
@@ -204,6 +204,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;
@@ -335,6 +338,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);
}

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 = {
	.set = vmentry_l1d_flush_set,
	.get = vmentry_l1d_flush_get,
@@ -2170,6 +2227,10 @@ static int vmx_set_msr(struct kvm_vcpu *vcpu, struct msr_data *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;
}

@@ -4362,6 +4423,8 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
	vpid_sync_context(vmx->vpid);
	if (init_event)
		vmx_clear_hlt(vcpu);

	vmx_update_fb_clear_dis(vcpu, vmx);
}

static void enable_irq_window(struct kvm_vcpu *vcpu)
@@ -6559,6 +6622,8 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu)
		 kvm_arch_has_assigned_device(vcpu->kvm))
		mds_clear_cpu_buffers();

	vmx_disable_fb_clear(vmx);

	if (vcpu->arch.cr2 != read_cr2())
		write_cr2(vcpu->arch.cr2);

@@ -6567,6 +6632,8 @@ static void vmx_vcpu_run(struct kvm_vcpu *vcpu)

	vcpu->arch.cr2 = read_cr2();

	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
@@ -8041,8 +8108,11 @@ static int __init vmx_init(void)
		return r;
	}

	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));
	}
+3 −0
Original line number Diff line number Diff line
@@ -280,8 +280,11 @@ struct vcpu_vmx {
	u64 msr_ia32_feature_control;
	u64 msr_ia32_feature_control_valid_bits;
	u64 ept_pointer;
	u64 msr_ia32_mcu_opt_ctrl;
	bool disable_fb_clear;

	struct pt_desc pt_desc;

};

enum ept_pointers_status {
+4 −0
Original line number Diff line number Diff line
@@ -1403,6 +1403,10 @@ static 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;
}