From: Jan Beulich Subject: gnttab: move "only local domain may copy by frame" check gnttab_copy_one() calls gnttab_copy_lock_domain{s,}() only conditionally. The non-GREF check towards the requestor being DOMID_SELF, however, needs doing on every batch element. Move the check into gnttab_copy_claim_buf() to achieve that. This is CVE-2026-102704, part of XSA-523. Fixes: d28f42f2703e ("grant-table: defer releasing pages acquired in a grant copy") Assisted-by: Claude Reported-by: Stephan Lipp Reported-by: CodeAnt AI Security Research Signed-off-by: Jan Beulich Reviewed-by: Andrew Cooper diff --git a/xen/common/grant_table.c b/xen/common/grant_table.c index 3dc5ff88da85..5e79c012b695 100644 --- a/xen/common/grant_table.c +++ b/xen/common/grant_table.c @@ -2936,13 +2936,8 @@ struct gnttab_copy_buf { bool have_type; }; -static int gnttab_copy_lock_domain(domid_t domid, bool is_gref, - struct gnttab_copy_buf *buf) +static int gnttab_copy_lock_domain(domid_t domid, struct gnttab_copy_buf *buf) { - /* Only DOMID_SELF may reference via frame. */ - if ( domid != DOMID_SELF && !is_gref ) - return GNTST_permission_denied; - buf->domain = rcu_lock_domain_by_any_id(domid); if ( !buf->domain ) @@ -2974,12 +2969,10 @@ static int gnttab_copy_lock_domains(const struct gnttab_copy *op, { int rc; - rc = gnttab_copy_lock_domain(op->source.domid, - op->flags & GNTCOPY_source_gref, src); + rc = gnttab_copy_lock_domain(op->source.domid, src); if ( rc < 0 ) goto error; - rc = gnttab_copy_lock_domain(op->dest.domid, - op->flags & GNTCOPY_dest_gref, dest); + rc = gnttab_copy_lock_domain(op->dest.domid, dest); if ( rc < 0 ) goto error; @@ -3042,6 +3035,9 @@ static int gnttab_copy_claim_buf(const struct gnttab_copy *op, buf->ptr.u.ref = ptr->u.ref; buf->have_grant = 1; } + /* Only DOMID_SELF may reference via frame. */ + else if ( ptr->domid != DOMID_SELF ) + return GNTST_permission_denied; else { rc = get_paged_frame(ptr->u.gmfn, &buf->mfn, &buf->page,