[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[xen stable-4.15] xen/page_alloc: Harden assign_pages()



commit d02631a21530918501f7e11320667dde7829cbb5
Author:     Julien Grall <jgrall@xxxxxxxxxx>
AuthorDate: Tue Nov 23 13:25:50 2021 +0100
Commit:     Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Tue Nov 23 13:25:50 2021 +0100

    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 / part of XSA-385.
    
    Signed-off-by: Julien Grall <jgrall@xxxxxxxxxx>
    Signed-off-by: Jan Beulich <jbeulich@xxxxxxxx>
    Reviewed-by: Roger Pau Monné <roger.pau@xxxxxxxxxx>
    master commit: 143501861d48e1bfef495849fd68584baac05849
    master date: 2021-11-22 11:11:05 +0000
---
 xen/common/grant_table.c |  7 ++++---
 xen/common/page_alloc.c  | 35 +++++++++++++++++++++++++++++------
 2 files changed, 33 insertions(+), 9 deletions(-)

diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c
index 6f50e9de51..e2fcb07e27 100644
--- 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;
diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c
index 1744e6faa5..91cde4b775 100644
--- 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++ )
     {
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.15



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.