]> xenbits.xensource.com Git - xen.git/commitdiff
xen/page_alloc: Harden assign_pages()
authorJulien Grall <jgrall@amazon.com>
Tue, 23 Nov 2021 12:35:03 +0000 (13:35 +0100)
committerJan Beulich <jbeulich@suse.com>
Tue, 23 Nov 2021 12:35:03 +0000 (13:35 +0100)
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 / part of XSA-385.

Signed-off-by: Julien Grall <jgrall@amazon.com>
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
master commit: 143501861d48e1bfef495849fd68584baac05849
master date: 2021-11-22 11:11:05 +0000

xen/common/grant_table.c
xen/common/page_alloc.c

index 2bc00f30a3882310c23338817008804d177ad8ba..ee5748e74eb98845adda0a0f05460d92ebf7c38a 100644 (file)
@@ -2239,7 +2239,8 @@ gnttab_transfer(
          * pages when it is dying.
          */
         if ( unlikely(e->is_dying) ||
-             unlikely(e->tot_pages >= e->max_pages) )
+             unlikely(e->tot_pages >= e->max_pages) ||
+             unlikely(!(e->tot_pages + 1)) )
         {
             spin_unlock(&e->page_alloc_lock);
 
@@ -2248,8 +2249,8 @@ gnttab_transfer(
                          e->domain_id);
             else
                 gdprintk(XENLOG_INFO,
-                         "Transferee d%d has no headroom (tot %u, max %u)\n",
-                         e->domain_id, e->tot_pages, e->max_pages);
+                         "Transferee %pd has no headroom (tot %u, max %u)\n",
+                         e, e->tot_pages, e->max_pages);
 
             gop.status = GNTST_general_error;
             goto unlock_and_copyback;
index 1dee9a05d4d896db5795b8a65684aa32eb666bc6..3ab90aca3237a41cbbb4f6db41d51c7d8a3cf782 100644 (file)
@@ -2278,17 +2278,26 @@ int assign_pages(
 
     if ( !(memflags & MEMF_no_refcount) )
     {
-        if ( unlikely((d->tot_pages + (1 << order)) > d->max_pages) )
+        unsigned int nr = 1u << order;
+
+        if ( unlikely(d->tot_pages > d->max_pages) )
+        {
+            gprintk(XENLOG_INFO, "Inconsistent allocation for %pd: %u > %u\n",
+                    d, d->tot_pages, d->max_pages);
+            rc = -EPERM;
+            goto out;
+        }
+
+        if ( unlikely(nr > d->max_pages - d->tot_pages) )
         {
             if ( !tmem_enabled() || order != 0 || d->tot_pages != d->max_pages )
-                gprintk(XENLOG_INFO, "Over-allocation for domain %u: "
-                        "%u > %u\n", d->domain_id,
-                        d->tot_pages + (1 << order), d->max_pages);
+                gprintk(XENLOG_INFO, "Over-allocation for %pd: %Lu > %u\n",
+                        d, d->tot_pages + 0ull + nr, d->max_pages);
             rc = -E2BIG;
             goto out;
         }
 
-        if ( unlikely(domain_adjust_tot_pages(d, 1 << order) == (1 << order)) )
+        if ( unlikely(domain_adjust_tot_pages(d, nr) == nr) )
             get_knownalive_domain(d);
     }