OSDN Git Service

KVM: nVMX: Verify VMCS shadowing VMCS link pointer
authorLiran Alon <liran.alon@oracle.com>
Fri, 22 Jun 2018 23:35:07 +0000 (02:35 +0300)
committerPaolo Bonzini <pbonzini@redhat.com>
Mon, 6 Aug 2018 15:58:41 +0000 (17:58 +0200)
Intel SDM considers these checks to be part of
"Checks on Guest Non-Register State".

Note that it is legal for vmcs->vmcs_link_pointer to be -1ull
when VMCS shadowing is enabled. In this case, any VMREAD/VMWRITE to
shadowed-field sets the ALU flags for VMfailInvalid (i.e. CF=1).

Signed-off-by: Liran Alon <liran.alon@oracle.com>
Signed-off-by: Jim Mattson <jmattson@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/kvm/vmx.c

index e762222..f8ad42b 100644 (file)
@@ -11755,6 +11755,33 @@ static int check_vmentry_prereqs(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12)
        return 0;
 }
 
+static int nested_vmx_check_vmcs_link_ptr(struct kvm_vcpu *vcpu,
+                                         struct vmcs12 *vmcs12)
+{
+       int r;
+       struct page *page;
+       struct vmcs12 *shadow;
+
+       if (vmcs12->vmcs_link_pointer == -1ull)
+               return 0;
+
+       if (!page_address_valid(vcpu, vmcs12->vmcs_link_pointer))
+               return -EINVAL;
+
+       page = kvm_vcpu_gpa_to_page(vcpu, vmcs12->vmcs_link_pointer);
+       if (is_error_page(page))
+               return -EINVAL;
+
+       r = 0;
+       shadow = kmap(page);
+       if (shadow->hdr.revision_id != VMCS12_REVISION ||
+           shadow->hdr.shadow_vmcs != nested_cpu_has_shadow_vmcs(vmcs12))
+               r = -EINVAL;
+       kunmap(page);
+       kvm_release_page_clean(page);
+       return r;
+}
+
 static int check_vmentry_postreqs(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
                                  u32 *exit_qual)
 {
@@ -11766,8 +11793,7 @@ static int check_vmentry_postreqs(struct kvm_vcpu *vcpu, struct vmcs12 *vmcs12,
            !nested_guest_cr4_valid(vcpu, vmcs12->guest_cr4))
                return 1;
 
-       if (!nested_cpu_has_shadow_vmcs(vmcs12) &&
-           vmcs12->vmcs_link_pointer != -1ull) {
+       if (nested_vmx_check_vmcs_link_ptr(vcpu, vmcs12)) {
                *exit_qual = ENTRY_FAIL_VMCS_LINK_PTR;
                return 1;
        }