[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH v5 02/45] x86/mm: refuse to promote an L4 while the domain has no per-domain L3



init_xen_l4_slots() puts the domain's per-domain L3 in slot 260 of the
L4s it fills.  Since fcf91ce9de66 ("x86/pv: don't populate the GDT/LDT
L3 slot at domain creation") a PV domain gets that L3 with its first
vCPU (pv_create_gdt_ldt_l1tab()).  Only mapcache_domain_init() makes it
earlier, with the domain, and release builds skip that unless memory
hotplug is enabled or the host's memory reaches past the part of the
directmap PV guests can see.  So in release builds on most hosts, an L4
that is promoted before XEN_DOMCTL_max_vcpus has created the domain's
vCPUs gets a slot 260 entry made from a NULL page (0x803e900000000063),
pointing far beyond the host's memory.

Have promote_l4_table() return -EINVAL while the domain has no
per-domain L3, before taking any reference.  The other callers of
init_xen_l4_slots() all run once the L3 exists; have init_xen_l4_slots()
check that with a BUG_ON().  An ASSERT() would not do: the case above
arises only in release builds.  libxl is unaffected: it creates the
vCPUs before it builds or restores a domain.

There's no way to trigger the issue from the current toolstack; this
is just belt-and-braces.

Fixes: fcf91ce9de66 ("x86/pv: don't populate the GDT/LDT L3 slot at domain 
creation")
Assisted-by: Claude Code:claude-opus-5-5
Signed-off-by: George Dunlap <gwd@xxxxxxxxxxxxxx>
---
Changes in v5:
- Test for the per-domain L3 itself, not for vCPU 0 (Roger).
- BUG_ON() in init_xen_l4_slots() if the domain has no per-domain L3.
- Retitle (was: "x86/mm: refuse to promote an L4 while the domain has
  no vCPU").

Changes in v4:
- New in this version, split out of "x86/hvm: introduce per-vCPU L3
  page-table": promote_l4_table() fails while the domain has no vCPU
---
 xen/arch/x86/mm.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c
index e42cd33c0d..f00f0b831d 100644
--- a/xen/arch/x86/mm.c
+++ b/xen/arch/x86/mm.c
@@ -1721,6 +1721,7 @@ void init_xen_l4_slots(l4_pgentry_t *l4t, mfn_t l4mfn,
         l4e_from_mfn(sl4mfn, __PAGE_HYPERVISOR_RW);
 
     /* Slot 260: Per-domain mappings. */
+    BUG_ON(!d->arch.perdomain_l3_pg);
     l4t[l4_table_offset(PERDOMAIN_VIRT_START)] =
         l4e_from_page(d->arch.perdomain_l3_pg, __PAGE_HYPERVISOR_RW);
 
@@ -1798,11 +1799,20 @@ static int promote_l4_table(struct page_info *page)
 {
     struct domain *d = page_get_owner(page);
     mfn_t          l4mfn = page_to_mfn(page);
-    l4_pgentry_t  *pl4e = map_domain_page(l4mfn);
+    l4_pgentry_t  *pl4e;
     unsigned int   i;
     int            rc = 0;
     unsigned int   partial_flags = page->partial_flags;
 
+    /*
+     * init_xen_l4_slots() puts the domain's per-domain L3 in slot 260, and a
+     * PV domain may get that only with its first vCPU.
+     */
+    if ( !d->arch.perdomain_l3_pg )
+        return -EINVAL;
+
+    pl4e = map_domain_page(l4mfn);
+
     for ( i = page->nr_validated_ptes; i < L4_PAGETABLE_ENTRIES;
           i++, partial_flags = 0 )
     {
-- 
2.56.0




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.