From c1fe7d10e8b489dd66ad5a2d7508e98e9c8dabc6 Mon Sep 17 00:00:00 2001
From: Roger Pau Monne <roger.pau@citrix.com>
Date: Tue, 14 Jul 2026 17:05:45 +0200
Subject: x86/pod: do not reclaim special pages for PoD cache
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

When doing PoD cache reclaim as part of a decrease reservation call, avoid
reclaiming special pages for the PoD cache.  Otherwise such pages get moved
from the domain ->xenpage_list to the ->page_list, while still being
referenced in ->shared_info domain field.

Prevent PoD cache from reclaiming special pages, as nothing good can come
out of it.

This is XSA-507 / CVE-2026-62434.

Fixes: 41aa0b62699e ("PoD memory 4/9: Decrease reservation")
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
---
 xen/arch/x86/mm/p2m-pod.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/xen/arch/x86/mm/p2m-pod.c b/xen/arch/x86/mm/p2m-pod.c
index 7a0bebd2d3b5..4602c32cffaf 100644
--- a/xen/arch/x86/mm/p2m-pod.c
+++ b/xen/arch/x86/mm/p2m-pod.c
@@ -536,12 +536,13 @@ decrease_reservation(struct domain *d, gfn_t gfn, unsigned int order)
         p2m_access_t a;
         p2m_type_t t;
         unsigned int cur_order;
+        mfn_t mfn = p2m->get_entry(p2m, gfn_add(gfn, i), &t, &a, 0, &cur_order,
+                                   NULL);
 
-        p2m->get_entry(p2m, gfn_add(gfn, i), &t, &a, 0, &cur_order, NULL);
         n = 1UL << min(order, cur_order);
         if ( p2m_is_pod(t) )
             pod += n;
-        else if ( p2m_is_ram(t) )
+        else if ( p2m_is_ram(t) && !is_special_page(mfn_to_page(mfn)) )
             ram += n;
     }
 
@@ -644,6 +645,9 @@ decrease_reservation(struct domain *d, gfn_t gfn, unsigned int order)
             ASSERT(mfn_valid(mfn));
 
             page = mfn_to_page(mfn);
+            if ( is_special_page(page) )
+                /* Do not touch special pages, let generic code handle them. */
+                continue;
 
             /* This shouldn't be able to fail */
             if ( p2m_set_entry(p2m, gfn_add(gfn, i), INVALID_MFN, cur_order,
-- 
2.53.0

