mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	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
					
				
					 5 changed files with 86 additions and 0 deletions
				
			
		| 
						 | 
					@ -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 a new issue