KVM: nVMX: Check GUEST_DR7 on vmentry of nested guests
authorKrish Sadhukhan <krish.sadhukhan@oracle.com>
Thu, 16 Jan 2020 00:54:32 +0000 (19:54 -0500)
committerPaolo Bonzini <pbonzini@redhat.com>
Mon, 27 Jan 2020 18:59:55 +0000 (19:59 +0100)
According to section "Checks on Guest Control Registers, Debug Registers, and
and MSRs" in Intel SDM vol 3C, the following checks are performed on vmentry
of nested guests:

    If the "load debug controls" VM-entry control is 1, bits 63:32 in the DR7
    field must be 0.

In KVM, GUEST_DR7 is set prior to the vmcs02 VM-entry by kvm_set_dr() and the
latter synthesizes a #GP if any bit in the high dword in the former is set.
Hence this field needs to be checked in software.

Signed-off-by: Krish Sadhukhan <krish.sadhukhan@oracle.com>
Reviewed-by: Karl Heubaum <karl.heubaum@oracle.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/kvm/vmx/nested.c
arch/x86/kvm/x86.c
arch/x86/kvm/x86.h

index 53ea650..95b3f43 100644 (file)
@@ -2887,6 +2887,10 @@ static int nested_vmx_check_guest_state(struct kvm_vcpu *vcpu,
            CC(!nested_guest_cr4_valid(vcpu, vmcs12->guest_cr4)))
                return -EINVAL;
 
+       if ((vmcs12->vm_entry_controls & VM_ENTRY_LOAD_DEBUG_CONTROLS) &&
+           CC(!kvm_dr7_valid(vmcs12->guest_dr7)))
+               return -EINVAL;
+
        if ((vmcs12->vm_entry_controls & VM_ENTRY_LOAD_IA32_PAT) &&
            CC(!kvm_pat_valid(vmcs12->guest_ia32_pat)))
                return -EINVAL;
index 48cd4e1..baf89d4 100644 (file)
@@ -1082,7 +1082,7 @@ static int __kvm_set_dr(struct kvm_vcpu *vcpu, int dr, unsigned long val)
        case 5:
                /* fall through */
        default: /* 7 */
-               if (val & 0xffffffff00000000ULL)
+               if (!kvm_dr7_valid(val))
                        return -1; /* #GP */
                vcpu->arch.dr7 = (val & DR7_VOLATILE) | DR7_FIXED_1;
                kvm_update_dr7(vcpu);
index e007b61..2d2ff85 100644 (file)
@@ -357,6 +357,12 @@ static inline bool kvm_pat_valid(u64 data)
        return (data | ((data & 0x0202020202020202ull) << 1)) == data;
 }
 
+static inline bool kvm_dr7_valid(unsigned long data)
+{
+       /* Bits [63:32] are reserved */
+       return !(data >> 32);
+}
+
 void kvm_load_guest_xsave_state(struct kvm_vcpu *vcpu);
 void kvm_load_host_xsave_state(struct kvm_vcpu *vcpu);
 u64 kvm_spec_ctrl_valid_bits(struct kvm_vcpu *vcpu);