]> xenbits.xensource.com Git - people/julieng/xen-unstable.git/commitdiff
memory: fix XENMEM_exchange error handling
authorJan Beulich <jbeulich@suse.com>
Tue, 8 Dec 2015 13:01:43 +0000 (14:01 +0100)
committerJan Beulich <jbeulich@suse.com>
Tue, 8 Dec 2015 13:01:43 +0000 (14:01 +0100)
assign_pages() can fail due to the domain getting killed in parallel,
which should not result in a hypervisor crash.

Reported-by: Julien Grall <julien.grall@citrix.com>
Also delete a redundant put_gfn() - all relevant paths leading to the
"fail" label already do this (and there are also paths where it was
plain wrong). All of the put_gfn()-s got introduced by 51032ca058
("Modify naming of queries into the p2m"), including the otherwise
unneeded initializer for k (with even a kind of misleading comment -
the compiler warning could actually have served as a hint that the use
is wrong).

This is CVE-2015-8339 + CVE-2015-8340 / XSA-159.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Ian Campbell <ian.campbell@citrix.com>
xen/common/memory.c

index e00a0b2797c8d9b418a8f11f72a45f4ac1db12d7..b6bf543fe906c879af58e62045b7ad90593f0a80 100644 (file)
@@ -378,7 +378,7 @@ static long memory_exchange(XEN_GUEST_HANDLE_PARAM(xen_memory_exchange_t) arg)
     PAGE_LIST_HEAD(out_chunk_list);
     unsigned long in_chunk_order, out_chunk_order;
     xen_pfn_t     gpfn, gmfn, mfn;
-    unsigned long i, j, k = 0; /* gcc ... */
+    unsigned long i, j, k;
     unsigned int  memflags = 0;
     long          rc = 0;
     struct domain *d;
@@ -610,11 +610,12 @@ static long memory_exchange(XEN_GUEST_HANDLE_PARAM(xen_memory_exchange_t) arg)
  fail:
     /* Reassign any input pages we managed to steal. */
     while ( (page = page_list_remove_head(&in_chunk_list)) )
-    {
-        put_gfn(d, gmfn + k--);
         if ( assign_pages(d, page, 0, MEMF_no_refcount) )
-            BUG();
-    }
+        {
+            BUG_ON(!d->is_dying);
+            if ( test_and_clear_bit(_PGC_allocated, &page->count_info) )
+                put_page(page);
+        }
 
  dying:
     rcu_unlock_domain(d);