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

[Xen-changelog] [xen stable-4.9] x86/mm: relinquish_memory: Grab an extra type ref when setting PGT_partial



commit 55bd90db577c9e0d2248fc654274d8a2c207ccf0
Author:     George Dunlap <george.dunlap@xxxxxxxxxx>
AuthorDate: Wed Dec 11 15:53:39 2019 +0100
Commit:     Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Wed Dec 11 15:53:39 2019 +0100

    x86/mm: relinquish_memory: Grab an extra type ref when setting PGT_partial
    
    The PGT_partial bit in page->type_info holds both a type count and a
    general ref count.  During domain tear-down, when free_page_type()
    returns -ERESTART, relinquish_memory() correctly handles the general
    ref count, but fails to grab an extra type count when setting
    PGT_partial.  When this bit is eventually cleared, type_count underflows
    and triggers the following BUG in page_alloc.c:free_domheap_pages():
    
        BUG_ON((pg[i].u.inuse.type_info & PGT_count_mask) != 0);
    
    As far as we can tell, this page underflow cannot be exploited any any
    other way: The page can't be used as a pagetable by the dying domain
    because it's dying; it can't be used as a pagetable by any other
    domain since it belongs to the dying domain; and ownership can't
    transfer to any other domain without hitting the BUG_ON() in
    free_domheap_pages().
    
    (steal_page() won't work on a page in this state, since it requires
    PGC_allocated to be set, and PGC_allocated will already have been
    cleared.)
    
    Fix this by grabbing an extra type ref if setting PGT_partial in
    relinquish_memory.
    
    This is part of XSA-310.
    
    Signed-off-by: George Dunlap <george.dunlap@xxxxxxxxxx>
    Acked-by: Jan Beulich <jbeulich@xxxxxxxx>
    master commit: 66bdc16aeed8ddb2ae724adc5ea6bde0dea78c3d
    master date: 2019-12-11 14:55:08 +0100
---
 xen/arch/x86/domain.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/xen/arch/x86/domain.c b/xen/arch/x86/domain.c
index 2b0a01d24a..0114380b8e 100644
--- a/xen/arch/x86/domain.c
+++ b/xen/arch/x86/domain.c
@@ -2485,6 +2485,25 @@ static int relinquish_memory(
                     goto out;
                 case -ERESTART:
                     page_list_add(page, list);
+                    /*
+                     * PGT_partial holds a type ref and a general ref.
+                     * If we came in with PGT_partial set, then we 1)
+                     * don't need to grab an extra type count, and 2)
+                     * do need to drop the extra page ref we grabbed
+                     * at the top of the loop.  If we didn't come in
+                     * with PGT_partial set, we 1) do need to drab an
+                     * extra type count, but 2) can transfer the page
+                     * ref we grabbed above to it.
+                     *
+                     * Note that we must increment type_info before
+                     * setting PGT_partial.  Theoretically it should
+                     * be safe to drop the page ref before setting
+                     * PGT_partial, but do it afterwards just to be
+                     * extra safe.
+                     */
+                    if ( !(x & PGT_partial) )
+                        page->u.inuse.type_info++;
+                    smp_wmb();
                     page->u.inuse.type_info |= PGT_partial;
                     if ( x & PGT_partial )
                         put_page(page);
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.9

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/xen-changelog

 


Rackspace

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