[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH 4/6] VMX: correct PDPTE load checks



Checking the low 5 bits of CR3 is not the job of vmx_load_pdptrs().
Instead it should #GP upon bad PDPTE values, rather than causing a VM
entry failure.

Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>

--- a/xen/arch/x86/hvm/vmx/vmx.c
+++ b/xen/arch/x86/hvm/vmx/vmx.c
@@ -1361,20 +1361,18 @@ static void vmx_set_interrupt_shadow(str
     __vmwrite(GUEST_INTERRUPTIBILITY_INFO, intr_shadow);
 }
 
-static void vmx_load_pdptrs(struct vcpu *v)
+static bool vmx_load_pdptrs(struct vcpu *v)
 {
     unsigned long cr3 = v->arch.hvm_vcpu.guest_cr[3];
-    uint64_t *guest_pdptes;
+    uint64_t *guest_pdptes, valid_mask;
     struct page_info *page;
     p2m_type_t p2mt;
     char *p;
+    unsigned int i;
 
     /* EPT needs to load PDPTRS into VMCS for PAE. */
     if ( !hvm_pae_enabled(v) || (v->arch.hvm_vcpu.guest_efer & EFER_LMA) )
-        return;
-
-    if ( (cr3 & 0x1fUL) && !hvm_pcid_enabled(v) )
-        goto crash;
+        return true;
 
     page = get_page_from_gfn(v->domain, cr3 >> PAGE_SHIFT, &p2mt, P2M_UNSHARE);
     if ( !page )
@@ -1385,34 +1383,47 @@ static void vmx_load_pdptrs(struct vcpu
         gdprintk(XENLOG_ERR,
                  "Bad cr3 on load pdptrs gfn %lx type %d\n",
                  cr3 >> PAGE_SHIFT, (int) p2mt);
-        goto crash;
+        domain_crash(v->domain);
+        return false;
     }
 
     p = __map_domain_page(page);
 
-    guest_pdptes = (uint64_t *)(p + (cr3 & ~PAGE_MASK));
+    guest_pdptes = (uint64_t *)(p + (cr3 & 0xfe0));
 
-    /*
-     * We do not check the PDPTRs for validity. The CPU will do this during
-     * vm entry, and we can handle the failure there and crash the guest.
-     * The only thing we could do better here is #GP instead.
-     */
+    valid_mask = ((1ULL << v->domain->arch.cpuid->extd.maxphysaddr) - 1) &
+                 (PAGE_MASK | _PAGE_AVAIL | _PAGE_PRESENT);
+    for ( i = 0; i < 4; ++i )
+        if ( (guest_pdptes[i] & _PAGE_PRESENT) &&
+             (guest_pdptes[i] & ~valid_mask) )
+        {
+            if ( v == current )
+                hvm_inject_hw_exception(TRAP_gp_fault, 0);
+            else
+            {
+                printk(XENLOG_G_ERR "%pv: bad PDPTE%u: %"PRIx64"\n",
+                       v, i, guest_pdptes[i]);
+                domain_crash(v->domain);
+            }
+            break;
+        }
 
-    vmx_vmcs_enter(v);
+    if ( i == 4 )
+    {
+        vmx_vmcs_enter(v);
 
-    __vmwrite(GUEST_PDPTE(0), guest_pdptes[0]);
-    __vmwrite(GUEST_PDPTE(1), guest_pdptes[1]);
-    __vmwrite(GUEST_PDPTE(2), guest_pdptes[2]);
-    __vmwrite(GUEST_PDPTE(3), guest_pdptes[3]);
+        __vmwrite(GUEST_PDPTE(0), guest_pdptes[0]);
+        __vmwrite(GUEST_PDPTE(1), guest_pdptes[1]);
+        __vmwrite(GUEST_PDPTE(2), guest_pdptes[2]);
+        __vmwrite(GUEST_PDPTE(3), guest_pdptes[3]);
 
-    vmx_vmcs_exit(v);
+        vmx_vmcs_exit(v);
+    }
 
     unmap_domain_page(p);
     put_page(page);
-    return;
 
- crash:
-    domain_crash(v->domain);
+    return i == 4;
 }
 
 static void vmx_update_host_cr3(struct vcpu *v)
@@ -1621,7 +1632,8 @@ static void vmx_update_guest_cr(struct v
             if ( !hvm_paging_enabled(v) && !vmx_unrestricted_guest(v) )
                 v->arch.hvm_vcpu.hw_cr[3] =
                     v->domain->arch.hvm_domain.params[HVM_PARAM_IDENT_PT];
-            vmx_load_pdptrs(v);
+            if ( !vmx_load_pdptrs(v) )
+                break;
         }
 
         __vmwrite(GUEST_CR3, v->arch.hvm_vcpu.hw_cr[3]);





_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.