]> xenbits.xensource.com Git - xen.git/commitdiff
x86/mm: Don't reset linear_pt_count on partial validation
authorGeorge Dunlap <george.dunlap@citrix.com>
Wed, 11 Dec 2019 14:58:29 +0000 (15:58 +0100)
committerJan Beulich <jbeulich@suse.com>
Wed, 11 Dec 2019 14:58:29 +0000 (15:58 +0100)
"Linear pagetables" is a technique which involves either pointing a
pagetable at itself, or to another pagetable the same or higher level.
Xen has limited support for linear pagetables: A page may either point
to itself, or point to another page of the same level (i.e., L2 to L2,
L3 to L3, and so on).

XSA-240 introduced an additional restriction that limited the "depth"
of such chains by allowing pages to either *point to* other pages of
the same level, or *be pointed to* by other pages of the same level,
but not both.  To implement this, we keep track of the number of
outstanding times a page points to or is pointed to another page
table, to prevent both from happening at the same time.

Unfortunately, the original commit introducing this reset this count
when resuming validation of a partially-validated pagetable, dropping
some "linear_pt_entry" counts.

On debug builds on systems where guests used this feature, this might
lead to crashes that look like this:

    Assertion 'oc > 0' failed at mm.c:874

Worse, if an attacker could engineer such a situation to occur, they
might be able to make loops or other abitrary chains of linear
pagetables, leading to the denial-of-service situation outlined in
XSA-240.

This is XSA-309.

Reported-by: Manuel Bouyer <bouyer@antioche.eu.org>
Signed-off-by: George Dunlap <george.dunlap@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
master commit: 7473efd12fb7a6548f5303f1f4c5cb521543a813
master date: 2019-12-11 14:10:27 +0100

xen/arch/x86/mm.c

index ed1e49bf6f0501947d718a313903f4d72054db20..81b6c8da721c7b7c6bc92672001d72bb359a624f 100644 (file)
@@ -3156,8 +3156,8 @@ static int __get_page_type(struct page_info *page, unsigned long type,
         {
             page->nr_validated_ptes = 0;
             page->partial_flags = 0;
+            page->linear_pt_count = 0;
         }
-        page->linear_pt_count = 0;
         rc = alloc_page_type(page, type, preemptible);
     }