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

Commit 4679b61f authored by Paolo Bonzini's avatar Paolo Bonzini
Browse files

KVM: x86: never trap MSR_KERNEL_GS_BASE



KVM has an old optimization whereby accesses to the kernel GS base MSR
are trapped when the guest is in 32-bit and not when it is in 64-bit mode.
The idea is that swapgs is not available in 32-bit mode, thus the
guest has no reason to access the MSR unless in 64-bit mode and
32-bit applications need not pay the price of switching the kernel GS
base between the host and the guest values.

However, this optimization adds complexity to the code for little
benefit (these days most guests are going to be 64-bit anyway) and in fact
broke after commit 678e315e ("KVM: vmx: add dedicated utility to
access guest's kernel_gs_base", 2018-08-06); the guest kernel GS base
can be corrupted across SMIs and UEFI Secure Boot is therefore broken
(a secure boot Linux guest, for example, fails to reach the login prompt
about half the time).  This patch just removes the optimization; the
kernel GS base MSR is now never trapped by KVM, similarly to the FS and
GS base MSRs.

Fixes: 678e315e
Reviewed-by: default avatarSean Christopherson <sean.j.christopherson@intel.com>
Signed-off-by: default avatarPaolo Bonzini <pbonzini@redhat.com>
parent a27fb6d9
Loading
Loading
Loading
Loading
+10 −37
Original line number Diff line number Diff line
@@ -121,7 +121,6 @@ module_param_named(pml, enable_pml, bool, S_IRUGO);

#define MSR_BITMAP_MODE_X2APIC		1
#define MSR_BITMAP_MODE_X2APIC_APICV	2
#define MSR_BITMAP_MODE_LM		4

#define KVM_VMX_TSC_MULTIPLIER_MAX     0xffffffffffffffffULL

@@ -2899,7 +2898,6 @@ static void vmx_prepare_switch_to_guest(struct kvm_vcpu *vcpu)
		vmx->msr_host_kernel_gs_base = read_msr(MSR_KERNEL_GS_BASE);
	}

	if (is_long_mode(&vmx->vcpu))
	wrmsrl(MSR_KERNEL_GS_BASE, vmx->msr_guest_kernel_gs_base);
#else
	savesegment(fs, fs_sel);
@@ -2951,7 +2949,6 @@ static void vmx_prepare_switch_to_host(struct vcpu_vmx *vmx)
	vmx->loaded_cpu_state = NULL;

#ifdef CONFIG_X86_64
	if (is_long_mode(&vmx->vcpu))
	rdmsrl(MSR_KERNEL_GS_BASE, vmx->msr_guest_kernel_gs_base);
#endif
	if (host_state->ldt_sel || (host_state->gs_sel & 7)) {
@@ -2980,24 +2977,19 @@ static void vmx_prepare_switch_to_host(struct vcpu_vmx *vmx)
#ifdef CONFIG_X86_64
static u64 vmx_read_guest_kernel_gs_base(struct vcpu_vmx *vmx)
{
	if (is_long_mode(&vmx->vcpu)) {
	preempt_disable();
	if (vmx->loaded_cpu_state)
			rdmsrl(MSR_KERNEL_GS_BASE,
			       vmx->msr_guest_kernel_gs_base);
		rdmsrl(MSR_KERNEL_GS_BASE, vmx->msr_guest_kernel_gs_base);
	preempt_enable();
	}
	return vmx->msr_guest_kernel_gs_base;
}

static void vmx_write_guest_kernel_gs_base(struct vcpu_vmx *vmx, u64 data)
{
	if (is_long_mode(&vmx->vcpu)) {
	preempt_disable();
	if (vmx->loaded_cpu_state)
		wrmsrl(MSR_KERNEL_GS_BASE, data);
	preempt_enable();
	}
	vmx->msr_guest_kernel_gs_base = data;
}
#endif
@@ -5073,19 +5065,6 @@ static void vmx_set_efer(struct kvm_vcpu *vcpu, u64 efer)
	if (!msr)
		return;

	/*
	 * MSR_KERNEL_GS_BASE is not intercepted when the guest is in
	 * 64-bit mode as a 64-bit kernel may frequently access the
	 * MSR.  This means we need to manually save/restore the MSR
	 * when switching between guest and host state, but only if
	 * the guest is in 64-bit mode.  Sync our cached value if the
	 * guest is transitioning to 32-bit mode and the CPU contains
	 * guest state, i.e. the cache is stale.
	 */
#ifdef CONFIG_X86_64
	if (!(efer & EFER_LMA))
		(void)vmx_read_guest_kernel_gs_base(vmx);
#endif
	vcpu->arch.efer = efer;
	if (efer & EFER_LMA) {
		vm_entry_controls_setbit(to_vmx(vcpu), VM_ENTRY_IA32E_MODE);
@@ -6078,9 +6057,6 @@ static u8 vmx_msr_bitmap_mode(struct kvm_vcpu *vcpu)
			mode |= MSR_BITMAP_MODE_X2APIC_APICV;
	}

	if (is_long_mode(vcpu))
		mode |= MSR_BITMAP_MODE_LM;

	return mode;
}

@@ -6121,9 +6097,6 @@ static void vmx_update_msr_bitmap(struct kvm_vcpu *vcpu)
	if (!changed)
		return;

	vmx_set_intercept_for_msr(msr_bitmap, MSR_KERNEL_GS_BASE, MSR_TYPE_RW,
				  !(mode & MSR_BITMAP_MODE_LM));

	if (changed & (MSR_BITMAP_MODE_X2APIC | MSR_BITMAP_MODE_X2APIC_APICV))
		vmx_update_msr_bitmap_x2apic(msr_bitmap, mode);