Skip to content

Commit c4abd73

Browse files
sean-jcbonzini
authored andcommitted
KVM: VMX: Don't fudge CR0 and CR4 for restricted L2 guest
Stuff CR0 and/or CR4 to be compliant with a restricted guest if and only if KVM itself is not configured to utilize unrestricted guests, i.e. don't stuff CR0/CR4 for a restricted L2 that is running as the guest of an unrestricted L1. Any attempt to VM-Enter a restricted guest with invalid CR0/CR4 values should fail, i.e. in a nested scenario, KVM (as L0) should never observe a restricted L2 with incompatible CR0/CR4, since nested VM-Enter from L1 should have failed. And if KVM does observe an active, restricted L2 with incompatible state, e.g. due to a KVM bug, fudging CR0/CR4 instead of letting VM-Enter fail does more harm than good, as KVM will often neglect to undo the side effects, e.g. won't clear rmode.vm86_active on nested VM-Exit, and thus the damage can easily spill over to L1. On the other hand, letting VM-Enter fail due to bad guest state is more likely to contain the damage to L2 as KVM relies on hardware to perform most guest state consistency checks, i.e. KVM needs to be able to reflect a failed nested VM-Enter into L1 irrespective of (un)restricted guest behavior. Cc: Jim Mattson <jmattson@google.com> Cc: stable@vger.kernel.org Fixes: bddd82d ("KVM: nVMX: KVM needs to unset "unrestricted guest" VM-execution control in vmcs02 if vmcs12 doesn't set it") Signed-off-by: Sean Christopherson <seanjc@google.com> Message-Id: <20230613203037.1968489-3-seanjc@google.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
1 parent 26a0652 commit c4abd73

File tree

1 file changed

+9
-4
lines changed

1 file changed

+9
-4
lines changed

arch/x86/kvm/vmx/vmx.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1513,6 +1513,11 @@ void vmx_set_rflags(struct kvm_vcpu *vcpu, unsigned long rflags)
15131513
struct vcpu_vmx *vmx = to_vmx(vcpu);
15141514
unsigned long old_rflags;
15151515

1516+
/*
1517+
* Unlike CR0 and CR4, RFLAGS handling requires checking if the vCPU
1518+
* is an unrestricted guest in order to mark L2 as needing emulation
1519+
* if L1 runs L2 as a restricted guest.
1520+
*/
15161521
if (is_unrestricted_guest(vcpu)) {
15171522
kvm_register_mark_available(vcpu, VCPU_EXREG_RFLAGS);
15181523
vmx->rflags = rflags;
@@ -3265,7 +3270,7 @@ void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
32653270
old_cr0_pg = kvm_read_cr0_bits(vcpu, X86_CR0_PG);
32663271

32673272
hw_cr0 = (cr0 & ~KVM_VM_CR0_ALWAYS_OFF);
3268-
if (is_unrestricted_guest(vcpu))
3273+
if (enable_unrestricted_guest)
32693274
hw_cr0 |= KVM_VM_CR0_ALWAYS_ON_UNRESTRICTED_GUEST;
32703275
else {
32713276
hw_cr0 |= KVM_VM_CR0_ALWAYS_ON;
@@ -3293,7 +3298,7 @@ void vmx_set_cr0(struct kvm_vcpu *vcpu, unsigned long cr0)
32933298
}
32943299
#endif
32953300

3296-
if (enable_ept && !is_unrestricted_guest(vcpu)) {
3301+
if (enable_ept && !enable_unrestricted_guest) {
32973302
/*
32983303
* Ensure KVM has an up-to-date snapshot of the guest's CR3. If
32993304
* the below code _enables_ CR3 exiting, vmx_cache_reg() will
@@ -3424,7 +3429,7 @@ void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
34243429
* this bit, even if host CR4.MCE == 0.
34253430
*/
34263431
hw_cr4 = (cr4_read_shadow() & X86_CR4_MCE) | (cr4 & ~X86_CR4_MCE);
3427-
if (is_unrestricted_guest(vcpu))
3432+
if (enable_unrestricted_guest)
34283433
hw_cr4 |= KVM_VM_CR4_ALWAYS_ON_UNRESTRICTED_GUEST;
34293434
else if (vmx->rmode.vm86_active)
34303435
hw_cr4 |= KVM_RMODE_VM_CR4_ALWAYS_ON;
@@ -3444,7 +3449,7 @@ void vmx_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4)
34443449
vcpu->arch.cr4 = cr4;
34453450
kvm_register_mark_available(vcpu, VCPU_EXREG_CR4);
34463451

3447-
if (!is_unrestricted_guest(vcpu)) {
3452+
if (!enable_unrestricted_guest) {
34483453
if (enable_ept) {
34493454
if (!is_paging(vcpu)) {
34503455
hw_cr4 &= ~X86_CR4_PAE;

0 commit comments

Comments
 (0)