xen/gnttab: Prevent GNTTABOP_cache_flush from corrupting RO grants

Grants can be offered read-only by the owning domain.  While a domain mapping
a RO grant may have a need to invalidate the cache, it must not modify the
other-guests data while doing so.  Force-upgrade to a clean operation in this
case.

This is CVE-2026-102702, part of XSA-519.

Fixes: 18e8d22fe7 ("introduce GNTTABOP_cache_flush")
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>
(cherry picked from commit c89185286c)
This commit is contained in:
Andrew Cooper committed 2026-10-13 14:18:50 +01:00
1 parent 931d3ce43d
commit c09aea4191
1 file changed
+26 -1
+26 -1
View File
@@ -983,6 +983,13 @@ static struct active_grant_entry *grant_map_exists(const struct domain *ld,
return ERR_PTR(-EINVAL);
}
static bool grant_map_is_ro(struct active_grant_entry *act)
{
ASSERT(spin_is_locked(&act->lock));
return (act->pin & (GNTPIN_hstw_mask | GNTPIN_devw_mask)) == 0;
}
union maptrack_node {
struct {
/* Radix tree slot pointers use two of the bits. */
@@ -3590,7 +3597,7 @@ gnttab_swap_grant_ref(XEN_GUEST_HANDLE_PARAM(gnttab_swap_grant_ref_t) uop,
return 0;
}
static int _cache_flush(const gnttab_cache_flush_t *cflush, grant_ref_t *cur_ref)
static int _cache_flush(gnttab_cache_flush_t *cflush, grant_ref_t *cur_ref)
{
struct domain *d, *owner;
struct page_info *page;
@@ -3641,6 +3648,24 @@ static int _cache_flush(const gnttab_cache_flush_t *cflush, grant_ref_t *cur_ref
put_page(page);
return act ? PTR_ERR(act) : 1;
}
/*
* If the grant mapping is read-only, it must be cleaned as well as
* invalidated. Invalidation without cleaning may modify memory the
* granter is expecting not to change.
*
* It is highly unlikely but legal to have multiple grant mappings of
* differing read-only-ness. If a read-write grant mapping is found
* first, then it's fine to invalidate without clean.
*
* If a read-only grant mapping is found first, a later read-write
* mapping could be missed. Assume that the read-only mapping is the
* only mapping. The cost is a clean of up to 4k, while the saving is
* not requiring the search of grant maps to be exhaustive in order to
* spot a corner-case expected not to exist in practice.
*/
if ( grant_map_is_ro(act) )
cflush->op |= GNTTAB_CACHE_CLEAN;
}
v = map_domain_page(mfn);
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.