From: Jan Beulich Subject: gnttab: check values against active entry when copying an already-pinned one acquire_grant_for_copy() passes to its caller both an MFN and a struct page_info *. The two really need to be in sync for the get_page() underlying get_paged_frame() and get_page_type() (both acting on the passed back struct page_info *) and the map_domain_page() (acting on the passed back MFN) to achieve the intended effect. Go further and also check other properties: GTF_transitive / GTF_sub_page may have been flipped in the shared entry, so respective fields / values also may not match. The one field which we can be sure does match (as it was checked earlier in the function) is ->domid. Add an assertion nevertheless. This is CVE-2026-62428 / XSA-500. Fixes: d8cbecb1eeed ("grant-tables: Use get_page_from_gfn() instead of get_gfn()/put_gfn") Signed-off-by: Jan Beulich Reviewed-by: Juergen Gross diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c index cc7f2bd82103..bf1b0d367746 100644 --- a/xen/common/grant_table.c +++ b/xen/common/grant_table.c @@ -2755,6 +2755,21 @@ acquire_grant_for_copy( act->trans_gref = trans_gref; act->mfn = grant_mfn; } + else if ( !mfn_eq(act->mfn, grant_mfn) || + act->trans_domain != td || + act->trans_gref != trans_gref || + (act->is_sub_page && + (!is_sub_page || + act->start != trans_page_off || + act->length != trans_length)) ) + { + put_page(*page); + *page = NULL; + rc = GNTST_general_error; + goto unlock_out_clear; + } + else + ASSERT(act->domid == ldom); } else {