Skip to content

Commit c4d2188

Browse files
huangweirkrcmar
authored andcommitted
KVM: x86: Update cpuid properly when CR4.OSXAVE or CR4.PKE is changed
The CPUID bits of OSXSAVE (function=0x1) and OSPKE (func=0x7, leaf=0x0) allows user apps to detect if OS has set CR4.OSXSAVE or CR4.PKE. KVM is supposed to update these CPUID bits when CR4 is updated. Current KVM code doesn't handle some special cases when updates come from emulator. Here is one example: Step 1: guest boots Step 2: guest OS enables XSAVE ==> CR4.OSXSAVE=1 and CPUID.OSXSAVE=1 Step 3: guest hot reboot ==> QEMU reset CR4 to 0, but CPUID.OSXAVE==1 Step 4: guest os checks CPUID.OSXAVE, detects 1, then executes xgetbv Step 4 above will cause an #UD and guest crash because guest OS hasn't turned on OSXAVE yet. This patch solves the problem by comparing the the old_cr4 with cr4. If the related bits have been changed, kvm_update_cpuid() needs to be called. Signed-off-by: Wei Huang <wei@redhat.com> Reviewed-by: Bandan Das <bsd@redhat.com> Cc: stable@vger.kernel.org Signed-off-by: Radim Krčmář <rkrcmar@redhat.com>
1 parent d8f2f49 commit c4d2188

File tree

1 file changed

+4
-1
lines changed

1 file changed

+4
-1
lines changed

arch/x86/kvm/x86.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7985,6 +7985,7 @@ static int __set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
79857985
{
79867986
struct msr_data apic_base_msr;
79877987
int mmu_reset_needed = 0;
7988+
int cpuid_update_needed = 0;
79887989
int pending_vec, max_bits, idx;
79897990
struct desc_ptr dt;
79907991
int ret = -EINVAL;
@@ -8023,8 +8024,10 @@ static int __set_sregs(struct kvm_vcpu *vcpu, struct kvm_sregs *sregs)
80238024
vcpu->arch.cr0 = sregs->cr0;
80248025

80258026
mmu_reset_needed |= kvm_read_cr4(vcpu) != sregs->cr4;
8027+
cpuid_update_needed |= ((kvm_read_cr4(vcpu) ^ sregs->cr4) &
8028+
(X86_CR4_OSXSAVE | X86_CR4_PKE));
80268029
kvm_x86_ops->set_cr4(vcpu, sregs->cr4);
8027-
if (sregs->cr4 & (X86_CR4_OSXSAVE | X86_CR4_PKE))
8030+
if (cpuid_update_needed)
80288031
kvm_update_cpuid(vcpu);
80298032

80308033
idx = srcu_read_lock(&vcpu->kvm->srcu);

0 commit comments

Comments
 (0)