x86/p2m: add option to skip root pagetable removal in p2m_teardown()
authorRoger Pau Monné <roger.pau@citrix.com>
Tue, 11 Oct 2022 12:21:23 +0000 (14:21 +0200)
committerJan Beulich <jbeulich@suse.com>
Tue, 11 Oct 2022 12:21:23 +0000 (14:21 +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>
xen/arch/x86/include/asm/p2m.h
xen/arch/x86/mm/hap/hap.c
xen/arch/x86/mm/p2m-basic.c
xen/arch/x86/mm/shadow/common.c

index 0a0f7114f318c2f065bc69cc2914f3c4356e919e..bafbd96052a9c49f250c291bc1634d5684f9ed30 100644 (file)
@@ -600,7 +600,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/remove a page to/from a domain's p2m table. */
index 79929774e8c5fe71981cd6db89def7ec2ac2ee5b..9e0b725c59bcd08a05d1533b31d1d363691c45f7 100644 (file)
@@ -541,18 +541,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 9130fc2a70dac7a483849709341722b210b92ce9..3231aaa9ba07f378590ef5ccc126a2c0dc276d87 100644 (file)
@@ -154,10 +154,10 @@ int p2m_init(struct domain *d)
  * 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)
 {
 #ifdef CONFIG_HVM
-    struct page_info *pg;
+    struct page_info *pg, *root_pg = NULL;
     struct domain *d;
 
     if ( !p2m )
@@ -171,10 +171,20 @@ void p2m_teardown(struct p2m_domain *p2m)
     ASSERT(atomic_read(&d->shr_pages) == 0);
 #endif
 
-    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);
 #endif
index 0247f0c84ea01684c012a853db238859ed25a14b..3e1e43a3892a802c4e6dcd3169559c1331bbc6e4 100644 (file)
@@ -2707,7 +2707,7 @@ int shadow_enable(struct domain *d, u32 mode)
  out_unlocked:
 #ifdef CONFIG_HVM
     if ( rv != 0 && !pagetable_is_null(p2m_get_pagetable(p2m)) )
-        p2m_teardown(p2m);
+        p2m_teardown(p2m, true);
 #endif
     if ( rv != 0 && pg != NULL )
     {
@@ -2873,7 +2873,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);