|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [xen staging-4.19] xen/page_alloc: ensure TLB flush is done ahead of page scrubbing
commit 6dd278418cf2e3907f7a6770363ff2ed312b0e03
Author: Roger Pau Monne <roger@xxxxxxxxxxxxxx>
AuthorDate: Tue Aug 4 12:23:19 2026 +0200
Commit: Andrew Cooper <andrew.cooper3@xxxxxxxxxx>
CommitDate: Wed Aug 26 17:50:14 2026 +0100
xen/page_alloc: ensure TLB flush is done ahead of page scrubbing
The current way in which idle TLB flush and TLB flushing when allocating a
page are done allows for the scrubbing to be done ahead of the TLB flush.
A PV domain can still have a TLB entry for the page after scrubbing, and
hence it may be able to modify it. Such unintended page accessing allows
domains to possibly exchange information even when `xsm=silo scrub-domheap`
are in effect.
Remove the MEMF_no_tlbflush memory allocation flag, and reorder the
flushing so it's always done ahead of the scrubbing in
alloc_{,color_}heap_pages(). The sole user of MEMF_no_tlbflush is
populate_physmap(), and given the constrains above it's no longer safe
to defer the flush, hence the flag removal and the folding of the flush in
the allocator function itself.
This is XSA-511 / CVE-2026-79603.
Fixes: 24f1a58d1954 ("mm: option to _always_ scrub freed domheap pages")
Signed-off-by: Roger Pau Monné <roger@xxxxxxxxxxxxxx>
Reviewed-by: Jan Beulich <jbeulich@xxxxxxxx>
(cherry picked from commit ed7e656e6c18c1f5e6c7d0332fdaa8eeeee1b24e)
---
xen/common/memory.c | 21 ---------------------
xen/common/page_alloc.c | 22 +++++++++++++---------
xen/include/xen/mm.h | 2 --
3 files changed, 13 insertions(+), 32 deletions(-)
diff --git a/xen/common/memory.c b/xen/common/memory.c
index 723ab3c0da..e65d3ce3b0 100644
--- a/xen/common/memory.c
+++ b/xen/common/memory.c
@@ -161,8 +161,6 @@ static void populate_physmap(struct memop_args *a)
unsigned int i, j;
xen_pfn_t gpfn;
struct domain *d = a->domain, *curr_d = current->domain;
- bool need_tlbflush = false;
- uint32_t tlbflush_timestamp = 0;
if ( !guest_handle_subrange_okay(a->extent_list, a->nr_done,
a->nr_extents-1) )
@@ -174,15 +172,6 @@ static void populate_physmap(struct memop_args *a)
if ( unlikely(!d->creation_finished) )
{
- /*
- * With MEMF_no_tlbflush set, alloc_heap_pages() will ignore
- * TLB-flushes. After VM creation, this is a security issue (it can
- * make pages accessible to guest B, when guest A may still have a
- * cached mapping to them). So we do this only during domain creation,
- * when the domain itself has not yet been unpaused for the first
- * time.
- */
- a->memflags |= MEMF_no_tlbflush;
/*
* With MEMF_no_icache_flush, alloc_heap_pages() will skip
* performing icache flushes. We do it only before domain
@@ -282,13 +271,6 @@ static void populate_physmap(struct memop_args *a)
goto out;
}
- if ( unlikely(a->memflags & MEMF_no_tlbflush) )
- {
- for ( j = 0; j < (1U << a->extent_order); j++ )
- accumulate_tlbflush(&need_tlbflush, &page[j],
- &tlbflush_timestamp);
- }
-
mfn = page_to_mfn(page);
}
@@ -303,9 +285,6 @@ static void populate_physmap(struct memop_args *a)
}
out:
- if ( need_tlbflush )
- filtered_flush_tlb_mask(tlbflush_timestamp);
-
if ( a->memflags & MEMF_no_icache_flush )
invalidate_icache();
diff --git a/xen/common/page_alloc.c b/xen/common/page_alloc.c
index bbb8578459..7bd565cd27 100644
--- a/xen/common/page_alloc.c
+++ b/xen/common/page_alloc.c
@@ -1038,15 +1038,17 @@ static struct page_info *alloc_heap_pages(
/* Preserve PGC_need_scrub so we can check it after lock is dropped. */
pg[i].count_info = PGC_state_inuse | (pg[i].count_info &
PGC_need_scrub);
- if ( !(memflags & MEMF_no_tlbflush) )
- accumulate_tlbflush(&need_tlbflush, &pg[i],
- &tlbflush_timestamp);
+ accumulate_tlbflush(&need_tlbflush, &pg[i], &tlbflush_timestamp);
init_free_page_fields(&pg[i]);
}
spin_unlock(&heap_lock);
+ /* Flush ahead of scrubbing: ensure no PV domain has a stale TLB entry. */
+ if ( need_tlbflush )
+ filtered_flush_tlb_mask(tlbflush_timestamp);
+
if ( first_dirty != INVALID_DIRTY_IDX ||
(scrub_debug && !(memflags & MEMF_no_scrub)) )
{
@@ -1071,9 +1073,6 @@ static struct page_info *alloc_heap_pages(
}
}
- if ( need_tlbflush )
- filtered_flush_tlb_mask(tlbflush_timestamp);
-
/*
* Ensure cache and RAM are consistent for platforms where the guest
* can control its own visibility of/through the cache.
@@ -1320,6 +1319,13 @@ bool scrub_free_pages(void)
{
if ( test_bit(_PGC_need_scrub, &pg[i].count_info) )
{
+ bool need_tlbflush = false;
+ uint32_t tlbflush_ts = 0;
+
+ accumulate_tlbflush(&need_tlbflush, &pg[i],
&tlbflush_ts);
+ if ( need_tlbflush )
+ filtered_flush_tlb_mask(tlbflush_ts);
+
scrub_one_page(&pg[i]);
/*
* We can modify count_info without holding heap
@@ -2796,9 +2802,7 @@ static bool prepare_staticmem_pages(struct page_info *pg,
unsigned long nr_mfns,
goto out_err;
}
- if ( !(memflags & MEMF_no_tlbflush) )
- accumulate_tlbflush(&need_tlbflush, &pg[i],
- &tlbflush_timestamp);
+ accumulate_tlbflush(&need_tlbflush, &pg[i], &tlbflush_timestamp);
/*
* Preserve flag PGC_static and change page state
diff --git a/xen/include/xen/mm.h b/xen/include/xen/mm.h
index 7561297a75..cc7852662a 100644
--- a/xen/include/xen/mm.h
+++ b/xen/include/xen/mm.h
@@ -200,8 +200,6 @@ struct npfec {
#define MEMF_exact_node (1U<<_MEMF_exact_node)
#define _MEMF_no_owner 5
#define MEMF_no_owner (1U<<_MEMF_no_owner)
-#define _MEMF_no_tlbflush 6
-#define MEMF_no_tlbflush (1U<<_MEMF_no_tlbflush)
#define _MEMF_no_icache_flush 7
#define MEMF_no_icache_flush (1U<<_MEMF_no_icache_flush)
#define _MEMF_no_scrub 8
--
generated by git-patchbot for /home/xen/git/xen.git#staging-4.19
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |