From: Jan Beulich <jbeulich@suse.com>
Subject: gnttab: address fallout from XSA-501

A v1 -> v2 change isn't the only scenario where "status" may go stale in
map_grant_ref(). Across a v2 -> v1 -> v2 change the status pages would
have been freed and re-populated, possibly changing the pages used for the
array. Check the pointer against the expected version-dependent value.

This is XSA-517 / CVE-2026-79610.

Fixes: 96dfeb41774a ("gnttab: cope with version changes racing other operations")
Assisted-by: Claude
Reported-by: Teddy Astie <teddy.astie@vates.tech>
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Teddy Astie <teddy.astie@vates.tech>
---
v2: Add parentheses around the || expression.

--- a/xen/common/grant_table.c
+++ b/xen/common/grant_table.c
@@ -1350,13 +1350,19 @@ map_grant_ref(
 
     grant_read_lock(rgt);
 
-    if ( unlikely(evaluate_nospec((rgt->gt_version == 1) !=
-                                  (status == &shah->flags))) )
+    /*
+     * After a v1 -> v2 change behind our backs "ref" may now be out of
+     * bounds.  While after a v2 -> v1 -> v2 change "ref" would still be
+     * suitably bounded, the underlying status page may have moved.
+     */
+    if ( evaluate_nospec(rgt->gt_version == 1
+                         ? status != &shah->flags
+                         : (ref >= nr_grant_entries(rgt) ||
+                            status != &status_entry(rgt, ref))) )
     {
         /*
-         * After a v1 -> v2 change behind our backs "ref" may now be out of
-         * bounds.  Recalculate it, but only for reserved entries.  Others
-         * will have been cleared anyway by the version change.
+         * Recalculate status, but only for reserved entries.  Others will
+         * have been cleared anyway by the version change(s).
          */
         if ( ref < GNTTAB_NR_RESERVED_ENTRIES )
             status = evaluate_nospec(rgt->gt_version == 1)
