|
|
82709f7 |
From: Jan Beulich <jbeulich@suse.com>
|
|
|
82709f7 |
Subject: x86: don't wrongly trigger linear page table assertion
|
|
|
82709f7 |
|
|
|
82709f7 |
_put_page_type() may do multiple iterations until its cmpxchg()
|
|
|
82709f7 |
succeeds. It invokes set_tlbflush_timestamp() on the first
|
|
|
82709f7 |
iteration, however. Code inside the function takes care of this, but
|
|
|
82709f7 |
- the assertion in _put_final_page_type() would trigger on the second
|
|
|
82709f7 |
iteration if time stamps in a debug build are permitted to be
|
|
|
82709f7 |
sufficiently much wider than the default 6 bits (see WRAP_MASK in
|
|
|
82709f7 |
flushtlb.c),
|
|
|
82709f7 |
- it returning -EINTR (for a continuation to be scheduled) would leave
|
|
|
82709f7 |
the page inconsistent state (until the re-invocation completes).
|
|
|
82709f7 |
Make the set_tlbflush_timestamp() invocation conditional, bypassing it
|
|
|
82709f7 |
(for now) only in the case we really can't tolerate the stamp to be
|
|
|
82709f7 |
stored.
|
|
|
82709f7 |
|
|
|
82709f7 |
This is part of XSA-240.
|
|
|
82709f7 |
|
|
|
82709f7 |
Signed-off-by: Jan Beulich <jbeulich@suse.com>
|
|
|
82709f7 |
Reviewed-by: George Dunlap <george.dunlap@citrix.com>
|
|
|
82709f7 |
|
|
|
82709f7 |
--- a/xen/arch/x86/mm.c
|
|
|
82709f7 |
+++ b/xen/arch/x86/mm.c
|
|
|
82709f7 |
@@ -2613,30 +2613,22 @@ static int _put_page_type(struct page_in
|
|
|
82709f7 |
break;
|
|
|
82709f7 |
}
|
|
|
82709f7 |
|
|
|
82709f7 |
- if ( ptpg && PGT_type_equal(x, ptpg->u.inuse.type_info) )
|
|
|
82709f7 |
- {
|
|
|
82709f7 |
- /*
|
|
|
82709f7 |
- * set_tlbflush_timestamp() accesses the same union
|
|
|
82709f7 |
- * linear_pt_count lives in. Unvalidated page table pages,
|
|
|
82709f7 |
- * however, should occur during domain destruction only
|
|
|
82709f7 |
- * anyway. Updating of linear_pt_count luckily is not
|
|
|
82709f7 |
- * necessary anymore for a dying domain.
|
|
|
82709f7 |
- */
|
|
|
82709f7 |
- ASSERT(page_get_owner(page)->is_dying);
|
|
|
82709f7 |
- ASSERT(page->linear_pt_count < 0);
|
|
|
82709f7 |
- ASSERT(ptpg->linear_pt_count > 0);
|
|
|
82709f7 |
- ptpg = NULL;
|
|
|
82709f7 |
- }
|
|
|
82709f7 |
-
|
|
|
82709f7 |
/*
|
|
|
82709f7 |
* Record TLB information for flush later. We do not stamp page
|
|
|
82709f7 |
* tables when running in shadow mode:
|
|
|
82709f7 |
* 1. Pointless, since it's the shadow pt's which must be tracked.
|
|
|
82709f7 |
* 2. Shadow mode reuses this field for shadowed page tables to
|
|
|
82709f7 |
* store flags info -- we don't want to conflict with that.
|
|
|
82709f7 |
+ * Also page_set_tlbflush_timestamp() accesses the same union
|
|
|
82709f7 |
+ * linear_pt_count lives in. Pages (including page table ones),
|
|
|
82709f7 |
+ * however, don't need their flush time stamp set except when
|
|
|
82709f7 |
+ * the last reference is being dropped. For page table pages
|
|
|
82709f7 |
+ * this happens in _put_final_page_type().
|
|
|
82709f7 |
*/
|
|
|
82709f7 |
- if ( !(shadow_mode_enabled(page_get_owner(page)) &&
|
|
|
82709f7 |
- (page->count_info & PGC_page_table)) )
|
|
|
82709f7 |
+ if ( ptpg && PGT_type_equal(x, ptpg->u.inuse.type_info) )
|
|
|
82709f7 |
+ BUG_ON(!IS_ENABLED(CONFIG_PV_LINEAR_PT));
|
|
|
82709f7 |
+ else if ( !(shadow_mode_enabled(page_get_owner(page)) &&
|
|
|
82709f7 |
+ (page->count_info & PGC_page_table)) )
|
|
|
82709f7 |
page_set_tlbflush_timestamp(page);
|
|
|
82709f7 |
}
|
|
|
82709f7 |
else if ( unlikely((nx & (PGT_locked | PGT_count_mask)) ==
|