summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '0003-xen-arm-p2m-Handle-preemption-when-freeing-intermedi.patch')
-rw-r--r--0003-xen-arm-p2m-Handle-preemption-when-freeing-intermedi.patch167
1 files changed, 0 insertions, 167 deletions
diff --git a/0003-xen-arm-p2m-Handle-preemption-when-freeing-intermedi.patch b/0003-xen-arm-p2m-Handle-preemption-when-freeing-intermedi.patch
deleted file mode 100644
index 0b33b0a..0000000
--- a/0003-xen-arm-p2m-Handle-preemption-when-freeing-intermedi.patch
+++ /dev/null
@@ -1,167 +0,0 @@
-From 937fdbad5180440888f1fcee46299103327efa90 Mon Sep 17 00:00:00 2001
-From: Julien Grall <jgrall@amazon.com>
-Date: Tue, 11 Oct 2022 14:52:27 +0200
-Subject: [PATCH 03/87] xen/arm: p2m: Handle preemption when freeing
- intermediate page tables
-
-At the moment the P2M page tables will be freed when the domain structure
-is freed without any preemption. As the P2M is quite large, iterating
-through this may take more time than it is reasonable without intermediate
-preemption (to run softirqs and perhaps scheduler).
-
-Split p2m_teardown() in two parts: one preemptible and called when
-relinquishing the resources, the other one non-preemptible and called
-when freeing the domain structure.
-
-As we are now freeing the P2M pages early, we also need to prevent
-further allocation if someone call p2m_set_entry() past p2m_teardown()
-(I wasn't able to prove this will never happen). This is done by
-the checking domain->is_dying from previous patch in p2m_set_entry().
-
-Similarly, we want to make sure that no-one can accessed the free
-pages. Therefore the root is cleared before freeing pages.
-
-This is part of CVE-2022-33746 / XSA-410.
-
-Signed-off-by: Julien Grall <jgrall@amazon.com>
-Signed-off-by: Henry Wang <Henry.Wang@arm.com>
-Tested-by: Henry Wang <Henry.Wang@arm.com>
-Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>
-master commit: 3202084566bba0ef0c45caf8c24302f83d92f9c8
-master date: 2022-10-11 14:20:56 +0200
----
- xen/arch/arm/domain.c | 10 +++++++--
- xen/arch/arm/p2m.c | 47 ++++++++++++++++++++++++++++++++++++---
- xen/include/asm-arm/p2m.h | 13 +++++++++--
- 3 files changed, 63 insertions(+), 7 deletions(-)
-
-diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
-index 96e1b235501d..2694c39127c5 100644
---- a/xen/arch/arm/domain.c
-+++ b/xen/arch/arm/domain.c
-@@ -789,10 +789,10 @@ fail:
- void arch_domain_destroy(struct domain *d)
- {
- /* IOMMU page table is shared with P2M, always call
-- * iommu_domain_destroy() before p2m_teardown().
-+ * iommu_domain_destroy() before p2m_final_teardown().
- */
- iommu_domain_destroy(d);
-- p2m_teardown(d);
-+ p2m_final_teardown(d);
- domain_vgic_free(d);
- domain_vuart_free(d);
- free_xenheap_page(d->shared_info);
-@@ -996,6 +996,7 @@ enum {
- PROG_xen,
- PROG_page,
- PROG_mapping,
-+ PROG_p2m,
- PROG_done,
- };
-
-@@ -1056,6 +1057,11 @@ int domain_relinquish_resources(struct domain *d)
- if ( ret )
- return ret;
-
-+ PROGRESS(p2m):
-+ ret = p2m_teardown(d);
-+ if ( ret )
-+ return ret;
-+
- PROGRESS(done):
- break;
-
-diff --git a/xen/arch/arm/p2m.c b/xen/arch/arm/p2m.c
-index 1affdafadbeb..27418ee5ee98 100644
---- a/xen/arch/arm/p2m.c
-+++ b/xen/arch/arm/p2m.c
-@@ -1527,17 +1527,58 @@ static void p2m_free_vmid(struct domain *d)
- spin_unlock(&vmid_alloc_lock);
- }
-
--void p2m_teardown(struct domain *d)
-+int p2m_teardown(struct domain *d)
- {
- struct p2m_domain *p2m = p2m_get_hostp2m(d);
-+ unsigned long count = 0;
- struct page_info *pg;
-+ unsigned int i;
-+ int rc = 0;
-+
-+ p2m_write_lock(p2m);
-+
-+ /*
-+ * We are about to free the intermediate page-tables, so clear the
-+ * root to prevent any walk to use them.
-+ */
-+ for ( i = 0; i < P2M_ROOT_PAGES; i++ )
-+ clear_and_clean_page(p2m->root + i);
-+
-+ /*
-+ * The domain will not be scheduled anymore, so in theory we should
-+ * not need to flush the TLBs. Do it for safety purpose.
-+ *
-+ * Note that all the devices have already been de-assigned. So we don't
-+ * need to flush the IOMMU TLB here.
-+ */
-+ p2m_force_tlb_flush_sync(p2m);
-+
-+ while ( (pg = page_list_remove_head(&p2m->pages)) )
-+ {
-+ free_domheap_page(pg);
-+ count++;
-+ /* Arbitrarily preempt every 512 iterations */
-+ if ( !(count % 512) && hypercall_preempt_check() )
-+ {
-+ rc = -ERESTART;
-+ break;
-+ }
-+ }
-+
-+ p2m_write_unlock(p2m);
-+
-+ return rc;
-+}
-+
-+void p2m_final_teardown(struct domain *d)
-+{
-+ struct p2m_domain *p2m = p2m_get_hostp2m(d);
-
- /* p2m not actually initialized */
- if ( !p2m->domain )
- return;
-
-- while ( (pg = page_list_remove_head(&p2m->pages)) )
-- free_domheap_page(pg);
-+ ASSERT(page_list_empty(&p2m->pages));
-
- if ( p2m->root )
- free_domheap_pages(p2m->root, P2M_ROOT_ORDER);
-diff --git a/xen/include/asm-arm/p2m.h b/xen/include/asm-arm/p2m.h
-index 8f11d9c97b5d..b3ba83283e11 100644
---- a/xen/include/asm-arm/p2m.h
-+++ b/xen/include/asm-arm/p2m.h
-@@ -192,8 +192,17 @@ void setup_virt_paging(void);
- /* Init the datastructures for later use by the p2m code */
- int p2m_init(struct domain *d);
-
--/* Return all the p2m resources to Xen. */
--void p2m_teardown(struct domain *d);
-+/*
-+ * The P2M resources are freed in two parts:
-+ * - p2m_teardown() will be called when relinquish the resources. It
-+ * will free large resources (e.g. intermediate page-tables) that
-+ * requires preemption.
-+ * - p2m_final_teardown() will be called when domain struct is been
-+ * freed. This *cannot* be preempted and therefore one small
-+ * resources should be freed here.
-+ */
-+int p2m_teardown(struct domain *d);
-+void p2m_final_teardown(struct domain *d);
-
- /*
- * Remove mapping refcount on each mapping page in the p2m
---
-2.37.4
-