KVM: nVMX: add missing consistency checks for CR0 and CR4
authorPaolo Bonzini <pbonzini@redhat.com>
Fri, 10 Mar 2023 16:10:56 +0000 (11:10 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 22 Mar 2023 12:33:59 +0000 (13:33 +0100)
commit 112e66017bff7f2837030f34c2bc19501e9212d5 upstream.

The effective values of the guest CR0 and CR4 registers may differ from
those included in the VMCS12.  In particular, disabling EPT forces
CR4.PAE=1 and disabling unrestricted guest mode forces CR0.PG=CR0.PE=1.

Therefore, checks on these bits cannot be delegated to the processor
and must be performed by KVM.

Reported-by: Reima ISHII <ishiir@g.ecc.u-tokyo.ac.jp>
Cc: stable@vger.kernel.org
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/x86/kvm/vmx/nested.c

index df89959..1d00f78 100644 (file)
@@ -2999,7 +2999,7 @@ static int nested_vmx_check_guest_state(struct kvm_vcpu *vcpu,
                                        struct vmcs12 *vmcs12,
                                        enum vm_entry_failure_code *entry_failure_code)
 {
-       bool ia32e;
+       bool ia32e = !!(vmcs12->vm_entry_controls & VM_ENTRY_IA32E_MODE);
 
        *entry_failure_code = ENTRY_FAIL_DEFAULT;
 
@@ -3025,6 +3025,13 @@ static int nested_vmx_check_guest_state(struct kvm_vcpu *vcpu,
                                           vmcs12->guest_ia32_perf_global_ctrl)))
                return -EINVAL;
 
+       if (CC((vmcs12->guest_cr0 & (X86_CR0_PG | X86_CR0_PE)) == X86_CR0_PG))
+               return -EINVAL;
+
+       if (CC(ia32e && !(vmcs12->guest_cr4 & X86_CR4_PAE)) ||
+           CC(ia32e && !(vmcs12->guest_cr0 & X86_CR0_PG)))
+               return -EINVAL;
+
        /*
         * If the load IA32_EFER VM-entry control is 1, the following checks
         * are performed on the field for the IA32_EFER MSR:
@@ -3036,7 +3043,6 @@ static int nested_vmx_check_guest_state(struct kvm_vcpu *vcpu,
         */
        if (to_vmx(vcpu)->nested.nested_run_pending &&
            (vmcs12->vm_entry_controls & VM_ENTRY_LOAD_IA32_EFER)) {
-               ia32e = (vmcs12->vm_entry_controls & VM_ENTRY_IA32E_MODE) != 0;
                if (CC(!kvm_valid_efer(vcpu, vmcs12->guest_ia32_efer)) ||
                    CC(ia32e != !!(vmcs12->guest_ia32_efer & EFER_LMA)) ||
                    CC(((vmcs12->guest_cr0 & X86_CR0_PG) &&