aboutsummaryrefslogtreecommitdiff
path: root/system/xen/xsa/xsa385-4.15.patch
diff options
context:
space:
mode:
Diffstat (limited to 'system/xen/xsa/xsa385-4.15.patch')
-rw-r--r--system/xen/xsa/xsa385-4.15.patch96
1 files changed, 96 insertions, 0 deletions
diff --git a/system/xen/xsa/xsa385-4.15.patch b/system/xen/xsa/xsa385-4.15.patch
new file mode 100644
index 0000000000000..69b97049b5f45
--- /dev/null
+++ b/system/xen/xsa/xsa385-4.15.patch
@@ -0,0 +1,96 @@
+From: Julien Grall <jgrall@amazon.com>
+Subject: xen/page_alloc: Harden assign_pages()
+
+domain_tot_pages() and d->max_pages are 32-bit values. While the order
+should always be quite small, it would still be possible to overflow
+if domain_tot_pages() is near to (2^32 - 1).
+
+As this code may be called by a guest via XENMEM_increase_reservation
+and XENMEM_populate_physmap, we want to make sure the guest is not going
+to be able to allocate more than it is allowed.
+
+Rework the allocation check to avoid any possible overflow. While the
+check domain_tot_pages() < d->max_pages should technically not be
+necessary, it is probably best to have it to catch any possible
+inconsistencies in the future.
+
+This is CVE-2021-28706 / XSA-385.
+
+Signed-off-by: Julien Grall <jgrall@amazon.com>
+Signed-off-by: Jan Beulich <jbeulich@suse.com>
+
+--- a/xen/common/grant_table.c
++++ b/xen/common/grant_table.c
+@@ -2336,7 +2336,8 @@ gnttab_transfer(
+ * pages when it is dying.
+ */
+ if ( unlikely(e->is_dying) ||
+- unlikely(domain_tot_pages(e) >= e->max_pages) )
++ unlikely(domain_tot_pages(e) >= e->max_pages) ||
++ unlikely(!(e->tot_pages + 1)) )
+ {
+ spin_unlock(&e->page_alloc_lock);
+
+@@ -2345,8 +2346,8 @@ gnttab_transfer(
+ e->domain_id);
+ else
+ gdprintk(XENLOG_INFO,
+- "Transferee d%d has no headroom (tot %u, max %u)\n",
+- e->domain_id, domain_tot_pages(e), e->max_pages);
++ "Transferee %pd has no headroom (tot %u, max %u, ex %u)\n",
++ e, domain_tot_pages(e), e->max_pages, e->extra_pages);
+
+ gop.status = GNTST_general_error;
+ goto unlock_and_copyback;
+--- a/xen/common/page_alloc.c
++++ b/xen/common/page_alloc.c
+@@ -2298,20 +2298,43 @@ int assign_pages(
+ }
+ else if ( !(memflags & MEMF_no_refcount) )
+ {
+- unsigned int tot_pages = domain_tot_pages(d) + (1 << order);
++ unsigned int tot_pages = domain_tot_pages(d), nr = 1u << order;
+
+ if ( unlikely(tot_pages > d->max_pages) )
+ {
+- gprintk(XENLOG_INFO, "Over-allocation for domain %u: "
+- "%u > %u\n", d->domain_id, tot_pages, d->max_pages);
++ gprintk(XENLOG_INFO, "Inconsistent allocation for %pd: %u > %u\n",
++ d, tot_pages, d->max_pages);
++ rc = -EPERM;
++ goto out;
++ }
++
++ if ( unlikely(nr > d->max_pages - tot_pages) )
++ {
++ gprintk(XENLOG_INFO, "Over-allocation for %pd: %Lu > %u\n",
++ d, tot_pages + 0ull + nr, d->max_pages);
+ rc = -E2BIG;
+ goto out;
+ }
+ }
+
+- if ( !(memflags & MEMF_no_refcount) &&
+- unlikely(domain_adjust_tot_pages(d, 1 << order) == (1 << order)) )
+- get_knownalive_domain(d);
++ if ( !(memflags & MEMF_no_refcount) )
++ {
++ unsigned int nr = 1u << order;
++
++ if ( unlikely(d->tot_pages + nr < nr) )
++ {
++ gprintk(XENLOG_INFO,
++ "Excess allocation for %pd: %Lu (%u extra)\n",
++ d, d->tot_pages + 0ull + nr, d->extra_pages);
++ if ( pg[0].count_info & PGC_extra )
++ d->extra_pages -= nr;
++ rc = -E2BIG;
++ goto out;
++ }
++
++ if ( unlikely(domain_adjust_tot_pages(d, nr) == nr) )
++ get_knownalive_domain(d);
++ }
+
+ for ( i = 0; i < (1 << order); i++ )
+ {