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

[Xen-changelog] [xen-unstable] [XEN] Remove write access to new PT before discarding old shadow.



# HG changeset patch
# User Tim Deegan <Tim.Deegan@xxxxxxxxxxxxx>
# Node ID 0bbc1e003ef22399d24eb918507c7f5abe5b0bef
# Parent  f0ba459065d32b61c9d04ccde5787e48e23be782
[XEN] Remove write access to new PT before discarding old shadow.
This allows us to use the old pagetables's linear maps in our
remove-writeable-mappings heuristics, fixing the same crash that
cset 12339 did, but still letting us do fast revoke of writeable
mappings of toplevel pagetables.
Signed-off-by: Tim Deegan <Tim.Deegan@xxxxxxxxxxxxx>
---
 xen/arch/x86/mm/shadow/multi.c |   87 ++++++++++++++++++++++++++++++-----------
 1 files changed, 64 insertions(+), 23 deletions(-)

diff -r f0ba459065d3 -r 0bbc1e003ef2 xen/arch/x86/mm/shadow/multi.c
--- a/xen/arch/x86/mm/shadow/multi.c    Thu Nov 16 18:47:28 2006 -0800
+++ b/xen/arch/x86/mm/shadow/multi.c    Mon Nov 20 12:03:51 2006 +0000
@@ -3262,9 +3262,25 @@ sh_set_toplevel_shadow(struct vcpu *v,
                        mfn_t gmfn, 
                        unsigned int root_type) 
 {
-    mfn_t smfn = get_shadow_status(v, gmfn, root_type);
+    mfn_t smfn;
     struct domain *d = v->domain;
-    ASSERT(pagetable_is_null(v->arch.shadow_table[slot]));
+    
+    /* Decrement the refcount of the old contents of this slot */
+    smfn = pagetable_get_mfn(v->arch.shadow_table[slot]);
+    if ( mfn_x(smfn) )
+        sh_put_ref(v, smfn, 0);
+
+    /* Now figure out the new contents: is this a valid guest MFN? */
+    if ( !valid_mfn(gmfn) )
+    {
+        SHADOW_PRINTK("%u/%u [%u] invalid gmfn\n",
+                      GUEST_PAGING_LEVELS, SHADOW_PAGING_LEVELS, slot);
+        v->arch.shadow_table[slot] = pagetable_null();
+        return;
+    }
+
+    /* Guest mfn is valid: shadow it and install the shadow */
+    smfn = get_shadow_status(v, gmfn, root_type);
     if ( valid_mfn(smfn) )
     {
         /* Pull this root shadow to the front of the list of roots. */
@@ -3273,10 +3289,6 @@ sh_set_toplevel_shadow(struct vcpu *v,
     }
     else
     {
-        /* This guest MFN is a pagetable.  Must revoke write access 
-         * (and can't use heuristics because we have no linear map here). */
-        if ( shadow_remove_write_access(v, gmfn, 0, 0) != 0 )
-            flush_tlb_mask(v->domain->domain_dirty_cpumask); 
         /* Make sure there's enough free shadow memory. */
         shadow_prealloc(d, SHADOW_MAX_ORDER); 
         /* Shadow the page. */
@@ -3291,7 +3303,8 @@ sh_set_toplevel_shadow(struct vcpu *v,
     mfn_to_page(gmfn)->shadow_flags &= ~SHF_unhooked_mappings;
 #endif
 
-    /* Take a ref to this page: it will be released in sh_detach_old_tables. */
+    /* Take a ref to this page: it will be released in sh_detach_old_tables()
+     * or in the next call to sh_set_toplevel_shadow(). */
     sh_get_ref(smfn, 0);
     sh_pin(smfn);
 
@@ -3363,8 +3376,6 @@ sh_update_cr3(struct vcpu *v)
 #endif
         gmfn = pagetable_get_mfn(v->arch.guest_table);
 
-    sh_detach_old_tables(v);
-
     if ( !is_hvm_domain(d) && !test_bit(_VCPUF_initialised, &v->vcpu_flags) )
     {
         ASSERT(v->arch.cr3 == 0);
@@ -3376,10 +3387,16 @@ sh_update_cr3(struct vcpu *v)
     ////
 #if GUEST_PAGING_LEVELS == 4
     if ( shadow_mode_external(d) || shadow_mode_translate(d) )
+    {
+        if ( v->arch.guest_vtable )
+            sh_unmap_domain_page_global(v->arch.guest_vtable);
         v->arch.guest_vtable = sh_map_domain_page_global(gmfn);
+    }
     else
         v->arch.guest_vtable = __linear_l4_table;
 #elif GUEST_PAGING_LEVELS == 3
+    if ( v->arch.guest_vtable )
+        sh_unmap_domain_page_global(v->arch.guest_vtable);
     if ( shadow_mode_external(d) )
     {
         if ( shadow_vcpu_mode_translate(v) ) 
@@ -3401,7 +3418,11 @@ sh_update_cr3(struct vcpu *v)
         v->arch.guest_vtable = sh_map_domain_page_global(gmfn);
 #elif GUEST_PAGING_LEVELS == 2
     if ( shadow_mode_external(d) || shadow_mode_translate(d) )
+    {
+        if ( v->arch.guest_vtable )
+            sh_unmap_domain_page_global(v->arch.guest_vtable);
         v->arch.guest_vtable = sh_map_domain_page_global(gmfn);
+    }
     else
         v->arch.guest_vtable = __linear_l2_table;
 #else
@@ -3417,29 +3438,49 @@ sh_update_cr3(struct vcpu *v)
     //// vcpu->arch.shadow_table[]
     ////
 
+    /* We revoke write access to the new guest toplevel page(s) before we
+     * replace the old shadow pagetable(s), so that we can safely use the 
+     * (old) shadow linear maps in the writeable mapping heuristics. */
 #if GUEST_PAGING_LEVELS == 2
+    if ( shadow_remove_write_access(v, gmfn, 2, 0) != 0 )
+        flush_tlb_mask(v->domain->domain_dirty_cpumask); 
     sh_set_toplevel_shadow(v, 0, gmfn, PGC_SH_l2_shadow);
 #elif GUEST_PAGING_LEVELS == 3
     /* PAE guests have four shadow_table entries, based on the 
      * current values of the guest's four l3es. */
     {
-        int i;
+        int i, flush = 0;
+        gfn_t gl2gfn;
+        mfn_t gl2mfn;
         guest_l3e_t *gl3e = (guest_l3e_t*)v->arch.guest_vtable;
-        for ( i = 0; i < 4; i++ ) 
-        {
-            ASSERT(pagetable_is_null(v->arch.shadow_table[i]));
+        /* First, make all four entries read-only. */
+        for ( i = 0; i < 4; i++ )
+        {
             if ( guest_l3e_get_flags(gl3e[i]) & _PAGE_PRESENT )
             {
-                gfn_t gl2gfn = guest_l3e_get_gfn(gl3e[i]);
-                mfn_t gl2mfn = vcpu_gfn_to_mfn(v, gl2gfn);
-                if ( valid_mfn(gl2mfn) )                
-                    sh_set_toplevel_shadow(v, i, gl2mfn, (i == 3) 
-                                           ? PGC_SH_l2h_shadow 
-                                           : PGC_SH_l2_shadow);
+                gl2gfn = guest_l3e_get_gfn(gl3e[i]);
+                gl2mfn = vcpu_gfn_to_mfn(v, gl2gfn);
+                flush |= shadow_remove_write_access(v, gl2mfn, 2, 0); 
             }
         }
+        if ( flush ) 
+            flush_tlb_mask(v->domain->domain_dirty_cpumask);
+        /* Now install the new shadows. */
+        for ( i = 0; i < 4; i++ ) 
+        {
+            if ( guest_l3e_get_flags(gl3e[i]) & _PAGE_PRESENT )
+            {
+                gl2gfn = guest_l3e_get_gfn(gl3e[i]);
+                gl2mfn = vcpu_gfn_to_mfn(v, gl2gfn);
+                sh_set_toplevel_shadow(v, i, gl2mfn, (i == 3) 
+                                       ? PGC_SH_l2h_shadow 
+                                       : PGC_SH_l2_shadow);
+            }
+        }
     }
 #elif GUEST_PAGING_LEVELS == 4
+    if ( shadow_remove_write_access(v, gmfn, 4, 0) != 0 )
+        flush_tlb_mask(v->domain->domain_dirty_cpumask);
     sh_set_toplevel_shadow(v, 0, gmfn, PGC_SH_l4_shadow);
 #else
 #error This should never happen 
@@ -3527,9 +3568,9 @@ static int sh_guess_wrmap(struct vcpu *v
 {
     shadow_l1e_t sl1e, *sl1p;
     shadow_l2e_t *sl2p;
-#if GUEST_PAGING_LEVELS >= 3
+#if SHADOW_PAGING_LEVELS >= 3
     shadow_l3e_t *sl3p;
-#if GUEST_PAGING_LEVELS >= 4
+#if SHADOW_PAGING_LEVELS >= 4
     shadow_l4e_t *sl4p;
 #endif
 #endif
@@ -3537,14 +3578,14 @@ static int sh_guess_wrmap(struct vcpu *v
 
 
     /* Carefully look in the shadow linear map for the l1e we expect */
-#if GUEST_PAGING_LEVELS >= 4
+#if SHADOW_PAGING_LEVELS >= 4
     sl4p = sh_linear_l4_table(v) + shadow_l4_linear_offset(vaddr);
     if ( !(shadow_l4e_get_flags(*sl4p) & _PAGE_PRESENT) )
         return 0;
     sl3p = sh_linear_l3_table(v) + shadow_l3_linear_offset(vaddr);
     if ( !(shadow_l3e_get_flags(*sl3p) & _PAGE_PRESENT) )
         return 0;
-#elif GUEST_PAGING_LEVELS == 3
+#elif SHADOW_PAGING_LEVELS == 3
     sl3p = ((shadow_l3e_t *) v->arch.shadow.l3table) 
         + shadow_l3_linear_offset(vaddr);
     if ( !(shadow_l3e_get_flags(*sl3p) & _PAGE_PRESENT) )

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

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