]> xenbits.xensource.com Git - xen.git/commitdiff
x86/p2m: add option to skip root pagetable removal in p2m_teardown()
authorRoger Pau Monné <roger.pau@citrix.com>
Tue, 11 Oct 2022 13:34:41 +0000 (15:34 +0200)
committerJan Beulich <jbeulich@suse.com>
Tue, 11 Oct 2022 13:34:41 +0000 (15:34 +0200)
Add a new parameter to p2m_teardown() in order to select whether the
root page table should also be freed.  Note that all users are
adjusted to pass the parameter to remove the root page tables, so
behavior is not modified.

No functional change intended.

This is part of CVE-2022-33746 / XSA-410.

Suggested-by: Julien Grall <julien@xen.org>
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Tim Deegan <tim@xen.org>
master commit: 1df52a270225527ae27bfa2fc40347bf93b78357
master date: 2022-10-11 14:21:23 +0200

xen/arch/x86/mm/hap/hap.c
xen/arch/x86/mm/p2m.c
xen/arch/x86/mm/shadow/common.c
xen/include/asm-x86/p2m.h

index 1349de01d49a8c9ce86558007b3feca96e568013..395fd32559aeceb42fb9c01da7a7a06898005d41 100644 (file)
@@ -540,18 +540,18 @@ void hap_final_teardown(struct domain *d)
         }
 
         for ( i = 0; i < MAX_ALTP2M; i++ )
-            p2m_teardown(d->arch.altp2m_p2m[i]);
+            p2m_teardown(d->arch.altp2m_p2m[i], true);
     }
 
     /* Destroy nestedp2m's first */
     for (i = 0; i < MAX_NESTEDP2M; i++) {
-        p2m_teardown(d->arch.nested_p2m[i]);
+        p2m_teardown(d->arch.nested_p2m[i], true);
     }
 
     if ( d->arch.paging.hap.total_pages != 0 )
         hap_teardown(d, NULL);
 
-    p2m_teardown(p2m_get_hostp2m(d));
+    p2m_teardown(p2m_get_hostp2m(d), true);
     /* Free any memory that the p2m teardown released */
     paging_lock(d);
     hap_set_allocation(d, 0, NULL);
index be5e9c031a3a2ed332b88a65f43bf8c4cc766b80..7ec6466922491db2ee1bdd4e4f2cbc6c1fcde142 100644 (file)
@@ -737,11 +737,11 @@ int p2m_alloc_table(struct p2m_domain *p2m)
  * hvm fixme: when adding support for pvh non-hardware domains, this path must
  * cleanup any foreign p2m types (release refcnts on them).
  */
-void p2m_teardown(struct p2m_domain *p2m)
+void p2m_teardown(struct p2m_domain *p2m, bool remove_root)
 /* Return all the p2m pages to Xen.
  * We know we don't have any extra mappings to these pages */
 {
-    struct page_info *pg;
+    struct page_info *pg, *root_pg = NULL;
     struct domain *d;
 
     if (p2m == NULL)
@@ -751,10 +751,22 @@ void p2m_teardown(struct p2m_domain *p2m)
 
     p2m_lock(p2m);
     ASSERT(atomic_read(&d->shr_pages) == 0);
-    p2m->phys_table = pagetable_null();
+
+    if ( remove_root )
+        p2m->phys_table = pagetable_null();
+    else if ( !pagetable_is_null(p2m->phys_table) )
+    {
+        root_pg = pagetable_get_page(p2m->phys_table);
+        clear_domain_page(pagetable_get_mfn(p2m->phys_table));
+    }
 
     while ( (pg = page_list_remove_head(&p2m->pages)) )
-        d->arch.paging.free_page(d, pg);
+        if ( pg != root_pg )
+            d->arch.paging.free_page(d, pg);
+
+    if ( root_pg )
+        page_list_add(root_pg, &p2m->pages);
+
     p2m_unlock(p2m);
 }
 
index 773777321f4d8ec1ccb04d739c3fe87924812e39..4436ea2c51f68056f56d2a86fc7d6d1670ca585f 100644 (file)
@@ -2686,7 +2686,7 @@ int shadow_enable(struct domain *d, u32 mode)
     paging_unlock(d);
  out_unlocked:
     if ( rv != 0 && !pagetable_is_null(p2m_get_pagetable(p2m)) )
-        p2m_teardown(p2m);
+        p2m_teardown(p2m, true);
     if ( rv != 0 && pg != NULL )
     {
         pg->count_info &= ~PGC_count_mask;
@@ -2839,7 +2839,7 @@ void shadow_final_teardown(struct domain *d)
         shadow_teardown(d, NULL);
 
     /* It is now safe to pull down the p2m map. */
-    p2m_teardown(p2m_get_hostp2m(d));
+    p2m_teardown(p2m_get_hostp2m(d), true);
     /* Free any shadow memory that the p2m teardown released */
     paging_lock(d);
     shadow_set_allocation(d, 0, NULL);
index 9be4a9c58ec9e54763c7d216e09e7bf5d6fc4f09..cfe2e55fcfa60cfb9228c85f486d474cc5244988 100644 (file)
@@ -595,7 +595,7 @@ int p2m_init(struct domain *d);
 int p2m_alloc_table(struct p2m_domain *p2m);
 
 /* Return all the p2m resources to Xen. */
-void p2m_teardown(struct p2m_domain *p2m);
+void p2m_teardown(struct p2m_domain *p2m, bool remove_root);
 void p2m_final_teardown(struct domain *d);
 
 /* Add a page to a domain's p2m table */