Calling vnuma_destroy() without any locking can race the handling of both
XENMEM_get_vnumainfo and XEN_DOMCTL_setvnumainfo. While the latter is,
without Flask, strictly only exposed to the control domain, the former
can also be invoked by a stubdom DM or a de-privileged DM running in the
control domain. Isolate the logic used by XEN_DOMCTL_setvnumainfo into a
new helper function, which then is also used from domain_kill(). While
doing so also move the vnuma_destroy() invocation out of the locked
region.
With d->vnuma properly cleared by domain_kill(), XENMEM_get_vnumainfo now
really only needs to check for the field being NULL. That check needs
repeating, though, after re-acquiring the lock.
This is CVE-2026-62429 / XSA-502.
Fixes: 9695014966 ("xen: vnuma topology and subop hypercalls")
Reported-by: Teddy Astie <teddy.astie@vates.tech>
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Juergen Gross <jgross@suse.com>
(cherry picked from commit 2afa6fea9d)
Dropping and re-acquiring the grant table lock for a particular operation
requires special care, as in the meantime the grant table version can
change.
During a v2 -> v1 change, status frames going away means that pre-
calculated status pointers go stale, referencing freed (and possibly
already re-used) memory. Record in-flight v2 operations, permitting the
version change only when there are none of them. Recalculate "status" in
the one place (map_grant_ref()'s error path) where it could be stale, but
confine this to reserved entries.
This is CVE-2026-62436.
Reported-by: Mark Esler <mark@hexproof.dev>
During a v1 -> v2 change, the number of shared table entries reduces,
meaning that previously validated grant references may now be out of
bounds. Because of the checking of pin counts in gnttab_set_version()
(with the grant table lock held for writing), for now-out-of-bounds gref-s
neither active mappings can exist, nor can there be in-progress copy
operations. Nevertheless bounds checks are added there, just to be on the
safe side.
For gnttab_transfer(), to cover the gap between the lock being dropped by
gnttab_prepare_for_transfer() and it being re-acquired, have the helper
return the version it found, and fail the operation if the version turns
out to have changed after re-acquiring the lock.
Further avoid needless use of shared_entry_header(), as it involves
pointer arithmetic which, when using an out-of-bounds ref, is UB.
This is CVE-2026-62435.
Everything together is XSA-501.
Fixes: a98dc13703 ("Introduce a grant_entry_v2 structure")
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Tested-by: Mark Esler <mark@hexproof.dev>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
(cherry picked from commit 96dfeb4177)
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: d8cbecb1ee ("grant-tables: Use get_page_from_gfn() instead of get_gfn()/put_gfn")
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Juergen Gross <jgross@suse.com>
(cherry picked from commit 61b0a59ce2)
Integrate the checking with xsm_sysctl(), now that it has the full op
struct passed. As a positive side effect, permissions are then checked at
the same early point with and without Flask.
This is part of CVE-2026-62426 / XSA-499.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
Acked-By: Daniel P. Smith <dpsmith@apertussolutions.com>
(cherry picked from commit 299de2aeda)
Integrate the checking with xsm_sysctl(), now that it has the full op
struct passed. As a positive side effect, permissions are then checked at
the same early point with and without Flask. Note that these were x86-
only, i.e. some dead/unreachable code gets eliminated for (in particular)
Arm.
This is part of CVE-2026-62426 / XSA-499.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
Acked-By: Daniel P. Smith <dpsmith@apertussolutions.com>
(cherry picked from commit 0501e1dc04)
Integrate the checking with xsm_sysctl(), now that it has the full op
struct passed. As a positive side effect, permissions are then checked at
the same early point with and without Flask.
This is part of CVE-2026-62426 / XSA-499.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
Acked-By: Daniel P. Smith <dpsmith@apertussolutions.com>
(cherry picked from commit 4b249cba4b)
To shield the sysctl lock from abuse by unauthorized domains, follow what
5154fdda11 ("domctl: protect locking for get_domain_state") did: Check
for permission to issue the operation against DOM_XEN in flask_sysctl().
The finer-grained xsm_getdomaininfo() later in the handling of the sub-op
remains unaltered.
In the in-tree policy respective permission therefore needs granting.
This is part of CVE-2026-62426 / XSA-499.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
Acked-by: Daniel P. Smith <dpsmith@apertussolutions.com>
(cherry picked from commit 3179bf2931)
Integrate the checking with xsm_sysctl(), now that it has the full op
struct passed. As a positive side effect, permissions are then checked at
the same early point with and without Flask.
This is part of CVE-2026-62426 / XSA-499.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
Acked-By: Daniel P. Smith <dpsmith@apertussolutions.com>
(cherry picked from commit 751e371c91)
Integrate the checking with flask_platform_op(); there never really was a
need to defer these checks, as the sub-op has always been known to the
function. As a positive side effect, permissions are then checked at the
same early point with and without Flask.
This is CVE-2026-62427 / part of XSA-499.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
Acked-By: Daniel P. Smith <dpsmith@apertussolutions.com>
(cherry picked from commit 4ef45cbe31)
The directory and Rock Ridge / SUSP walk in iso9660_dir() derives several
lengths directly from attacker-controlled on-disk fields without validating
them. libfsimage is used by pygrub, which parses the filesystem of an
untrusted guest disk image from dom0, so these are reachable across a trust
boundary.
Five related problems are addressed:
* The directory record loop advances by
idr = (char *)idr + idr->length.l
and only stops on length.l == 0. A record whose length is smaller than
the fixed part of the on-disk layout cannot hold its own mandatory
fields, yet the body still reads name_len/extent/size and computes the
System Use area length from it. Require length to cover at least the
fixed record (sizeof(*idr) - sizeof(idr->name)) before entering the body.
This is CVE-2026-42494.
* The System Use area length is computed before the inner loop as
rr_len = idr->length.l - idr->name_len.l
- sizeof(struct iso_directory_record) + sizeof(idr->name);
in unsigned arithmetic. If length.l is smaller than name_len.l plus the
fixed record size, rr_len underflows to a huge value and the whole SUSP
walk runs off the directory buffer. Guard the subtraction and treat such
records as having no System Use area.
This is CVE-2026-42495.
* Inside the loop, each entry is consumed with
rr_len -= rr_ptr.rr->len;
rr_ptr.ptr += rr_ptr.rr->len;
with no lower or upper bound on the entry's own len byte. A len of 0
spins forever; a len greater than the remaining rr_len underflows it and
walks past the buffer. Validate 4 <= len <= rr_len at the top of the
loop and stop on violation: a structurally broken entry stream cannot be
advanced reliably, so continuing is not meaningful.
This is CVE-2026-62423.
* The NM handler subtracted the 5-byte SUSP/NM header from len without a
lower-bound check, underflowing name_len (the original report). The
generic check above only guarantees len >= 4; NM has an extra flags byte,
so keep an NM-specific len >= 5 check.
This is CVE-2026-62424.
* The CE continuation resets rr_ptr/rr_len from ce.offset and ce.size, both
image-controlled, into the fixed single-sector RRCONT_BUF with no bounds
check. Reject a window that does not fit in the buffer.
This is CVE-2026-62425.
This is XSA-497.
Signed-off-by: Syed Abdul Khaliq <abdul@bugqore.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
(cherry picked from commit fd11acab3d)
Addressing certain issues, in particular related to operations which may
take excessively long and therefore would need preemption, has turned out
overly costly. Since alternatives (HVM/PVH: HAP, PV: shim) are commonly
available, the decision was to deprecate the functionality, while still
retaining it for people to use at their own (security) risk. Memory-wise
small enough guests may still be okay to run.
Some CI testing depends on SHADOW_PAGING. Explicitly enable it when needed.
This is CVE-2026-42493 / XSA-495.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Juergen Gross <jgross@suse.com>
(cherry picked from commit f2cac32029)
A privileged domain on Arm64 can trigger a data abort in the hypervisor
by issuing memory_op's XENMEM_add_to_physmap_batch sub-op with
space=XENMAPSPACE_gmfn_foreign, idx=0 and foreign_domid=DOMID_IO.
get_pg_owner(DOMID_IO) succeeds, returning a pointer to the dom_io
pseudo-domain. The subsequent get_page_from_gfn(dom_io, ...) then
attempts to walk dom_io's P2M table, which is not initialized for
pseudo-domains, resulting in a data abort in p2m_get_entry() when
it dereferences the invalid pointer returned by p2m_get_root_pointer().
Replace get_pg_owner() with explicit domain lookup logic matching
the x86 implementation: handle DOMID_XEN via rcu_lock_domain(dom_xen),
and resolve all other domain IDs via rcu_lock_remote_domain_by_id(),
which rejects pseudo-domains (DOMID_IO, etc.) that are not present in
the domain hash, returning -ESRCH before any P2M access occurs.
Fixes: 615897bc6c ("xen/arm: Allow a privileged domain to map foreign page from DOMID_XEN")
Signed-off-by: Oleksandr Tyshchenko <oleksandr_tyshchenko@epam.com>
Reviewed-by: Michal Orzel <michal.orzel@amd.com>
Release-Acked-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
(cherry picked from commit f795a9c491)
AFL has pointed out that the op_bytes-is-not-0 assertion in common SIMD
handling can trigger for these insns. Indeed when the (relevant part of)
the controlling mask register is 0, no memory is accessed at all. Leave
op_bytes unaltered in this case, to engage the short-circuiting in common
SIMD handling when fault_suppression is true and op_bytes is 0.
While there also correct a related typo in the test harness.
Fixes: 65f82d4ce1 ("x86emul: support AVX512{F,_VBMI2} compress/expand insns")
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
master commit: cf90c8a48a
master date: 2026-07-20 09:50:00 +0200
pv_map_ldt_shadow_page() takes the whole guest PTE, adds _PAGE_RW to it, then
installs it into Xen's pagetables. It has had this behaviour ever since LDT
support was added in 2003.
However, it allows the guest to control the software available bits and
cacheability. This happens to be benign right now, but is bad form.
Use only the guest frame, and construct the mapping as regular RW frame, and
notably includes NX. This is how the GDT logic already works.
Fixes: 005c272397 ("Finished virtualisation of x86 LDT")
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
master commit: 1cc1f4d7a0
master date: 2026-07-14 17:31:08 +0100
The APM description of the AltMovCR8 feature bit is:
"LOCK MOV CR0 means MOV CR8"
Adjust the decode logic to behave like this.
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Teddy Astie <teddy.astie@vates.tech>
master commit: 7d48ef45b6
master date: 2026-07-10 19:35:49 +0100
The logic to populate memnodemap in populate_memnodemap() assumes that all
ranges are aligned to the hash shift, this however is only true for the
first address in a memory affinity node. Any subsequent ranges belonging
to the same node might not be aligned to the hash shift value.
Such lack of alignment causes issues to the logic in populate_memnodemap(),
as then the tail of the range might not be properly accounted for and setup
in memnodemap. Fix this by forcing the start address of all regions to
be aligned to the hash shift; if such alignment causes a region overlap it
would always be between regions on the same node, and hence will never
cause setup issues of the memnodemap array.
Fixes: 1666086b00 ("x86/NUMA: improve memnode_shift calculation for multi node system")
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
master commit: 188d530529
master date: 2026-06-05 19:13:47 +0200
A malformed partial DTB specifying both '#address-cells = <0>' and
'#size-cells = <0>' causes '(address_cells * 2 + size_cells)' to
evaluate to 0. This sum is subsequently used as a divisor when
calculating the number of regions in the 'xen,reg' property inside
handle_passthrough_prop():
len = fdt32_to_cpu(xen_reg->len) / ((address_cells * 2 + size_cells) *
sizeof(uint32_t));
This leads to a division by zero exception in the Xen hypervisor during
boot, causing a hypervisor panic/crash.
Fix this by validating that both 'address_cells' and 'size_cells'
are within the range of [1, 2] at the top of handle_passthrough_prop().
Any invalid cell size combination is safely rejected early with an error
message and return -EINVAL.
Furthermore, update handle_passthrough_prop() to use the sizeof(*cell)
instead of sizeof(uint32_t).
Fixes: 9ce974c475 ("xen/arm: assign devices to boot domains")
Signed-off-by: Dmytro Prokopchuk <dmytro_prokopchuk1@epam.com>
Reviewed-by: Michal Orzel <michal.orzel@amd.com>
Release-Acked-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
[michal: adjust for handle_passthrough_prop() living in a different file]
Signed-off-by: Michal Orzel <michal.orzel@amd.com>
(cherry picked from commit b83e1d9a1a)
construct_domain() creates the secondary vCPUs in a loop, but on a
vcpu_create() failure it only prints a message and breaks out of the
loop returning success. As a result the domain can be partially
constructed with fewer vCPUs than d->max_vcpus. This causes two contract
violations:
- Xen-Guest: domain's FDT is generated before vCPU creation - Xen exposes
incorrect information (e.g. two vCPUs listed in a device tree while only
one is actually created),
- User-Xen: unlike x86, on Arm port we try to bail out as soon as
possible on unsatisfied user requests (e.g. user requested two vCPUs
for a domain but it was created with only one).
Return an error instead of breaking out of the loop. Both callers
(construct_domU() and construct_hwdom()) already propagate a negative
return value and fail domain construction.
Fixes: 6b0e8e4334 ("xen/arm: allocate secondaries dom0 vcpus")
Signed-off-by: Michal Orzel <michal.orzel@amd.com>
Reviewed-by: Ayan Kumar Halder <ayan.kumar.halder@amd.com>
Release-Acked-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
Acked-by: Stefano Stabellini <sstabellini@kernel.org>
(cherry picked from commit e3aa330017)
Currently, during ARM Xen's SMP initialization, if there is
a Device Tree error (such as an invalid 'enable-method'),
cpu_possible_map can end up being sparse.
The issue here is that nr_cpu_ids is calculated in a way that
doesn't properly account for the maximum CPU ID when the map is
sparse, causing a mismatch. For example, if cpu_possible_map is
0xff0f, nr_cpu_ids becomes 12, but the actual maximum CPU ID
is 15. Xen's common code is built on the assumption that
'CPU ID < nr_cpu_ids', so this mismatch can break things.
To fix this, modify dt_smp_init_cpus() so that if the
arch_cpu_init() call fails, we don't consume the CPU ID slot.
Fixes: 4557c22928 ("xen: arm: rewrite start of day page table and cpu bring up")
Signed-off-by: Hirokazu Takahashi <taka@valinux.co.jp>
Reviewed-by: Michal Orzel <michal.orzel@amd.com>
(cherry picked from commit ccde3773c1)
When a node's depth exceeds DEVICE_TREE_MAX_DEPTH inside the
device_tree_for_each_node() loop, the code prints a warning and
executes 'continue;' statement, which jumps to condition check,
bypassing the iterator update step:
node = fdt_next_node(fdt, node, &depth).
The node and depth are not updated, the loop repeatedly evaluates
the same too-deep node, causing a hang.
Fix this by wrapping the node processing logic in an 'else' block.
This ensures the loop update step is executed on every iteration,
safely skipping deeply nested nodes and doing the traversal.
Fixes: 40f2ea3df2 ("xen/arm: pass node to device_tree_for_each_node")
Signed-off-by: Dmytro Prokopchuk <dmytro_prokopchuk1@epam.com>
Reviewed-by: Michal Orzel <michal.orzel@amd.com>
Release-Acked-by: Oleskii Kurochko <oleksii.kurochko@gmail.com>
(cherry picked from commit 3b717f57dc)
fdt_property() unconditionally calls memcpy(ptr, val, len) even when
len is zero and val is NULL. This is a legitimate calling convention
for adding empty FDT properties such as "interrupt-controller", which
carry no payload.
However, compilers that treat memcpy as nonnull on its pointer arguments
will fire UBSAN before observing that len is zero.
Guard the memcpy() with a check on len so it is skipped entirely when
there is no payload to copy, bringing the code in line with the
nonnull contract.
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Origin: git://git.kernel.org/pub/scm/utils/dtc/dtc.git f57e7df35df4
Fixes: f0ea065580 ("libfdt: add version 1.3.0")
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
Reviewed-by: Baptiste Le Duc <baptiste.le-duc@vates.tech>
Reviewed-by: Michal Orzel <michal.orzel@amd.com>
Release-Acked-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
(cherry picked from commit be18ad502e)
gicv3_enable_redist() clears GICR_WAKER.ProcessorSleep and then waits for
GICR_WAKER.ChildrenAsleep to clear, as required after waking a
redistributor.
However, the polling loop currently uses "while ( timeout )". Since
timeout is initially false, the loop runs only once unless the timeout
path has already been reached. As a result, Xen can continue before the
redistributor has completed wakeup.
Use an unconditional loop, matching the surrounding timeout/break pattern,
so the code polls until either ChildrenAsleep is clear or the deadline is
reached.
While there, also fix the timeout message. This path polls
GICR_WAKER.ChildrenAsleep, not an RWP bit, so "RWP timeout" is misleading.
Fixes: bc183a0235 ("xen/arm: Add support for GIC v3")
Signed-off-by: Luca Fancellu <luca.fancellu@arm.com>
Reviewed-by: Mykola Kvach <mykola_kvach@epam.com>
Reviewed-by: Michal Orzel <michal.orzel@amd.com>
Release-Acked-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
(cherry picked from commit 941fdfc03e)
The vGIC per-vCPU init callback can fail. In particular, GICv3 rejects
a vCPU when the domain's redistributor layout has no MMIO slot covering
that vCPU. However, the generic vGIC init path ignored the callback
return value, so vcpu_create() could succeed with an invalid vGICv3
per-vCPU state.
This can be reproduced on FVP Base RevC by exposing a 2 MiB GICv3
redistributor region to Dom0 and booting Xen with:
maxcpus=1 dom0_max_vcpus=64
The host GICv3 redistributor range is:
region 0: 0x0000002f100000 - 0x0000002f300000
With Xen's guest redistributor frame size of 128 KiB, that range covers
16 guest redistributors. vCPU16 and above have no corresponding
redistributor slot.
Before this fix, Xen detected the missing redistributors:
d0: Unable to find a re-distributor for VCPU 16
...
d0: Unable to find a re-distributor for VCPU 63
but ignored the error and continued as if the secondary vCPUs had been
created correctly. Dom0 then saw 64 possible CPUs and could hang during
secondary CPU bring-up:
smp: Bringing up secondary CPUs ...
d0v15: vGICR: SGI: unhandled word write ... to ICACTIVER0
Propagate the vGIC vcpu_init() error so the caller can stop creating
secondary vCPUs. With this fix, Dom0 construction reports:
d0: Unable to find a re-distributor for VCPU 16
Failed to allocate d0v16
and the guest continues booting with the vCPUs created before the
failure:
smp: Brought up 1 node, 16 CPUs
Free the private IRQ rank allocated by vcpu_vgic_init() on this error
path. The caller will still run the generic vCPU creation cleanup, but
XFREE() clears the pointer so that cleanup remains idempotent.
Also fix the host-layout redistributor region count for the case where
the requested vCPU count is larger than the capacity of all host
redistributor regions. The old code always stored i + 1 after the loop.
That is correct when the loop stops inside a valid region because the
requested vCPU count is covered. If the loop exits after consuming all
hardware regions, i is already equal to the number of allocated regions,
so i + 1 records one region too many.
In the same FVP setup, that off-by-one made Xen describe host-layout
GICR state beyond the populated redistributor region list. Dom0 then
accessed the GICR MMIO window described in its device tree, but Xen could
not match the access to a valid emulated redistributor frame. During
debugging this was seen as an unexpected vGICR access followed by a
guest panic:
d0v0: vGICR: unknown gpa read address 000000002f10ffe8
pc : gic_iterate_rdists+0x4c/0x104
Kernel panic - not syncing: Attempted to kill the idle task!
Keep the existing construct_domain() policy used by Dom0 and dom0less
domain construction: a failure to create a secondary vCPU stops the
secondary vCPU creation loop, but does not fail the whole domain
construction.
Fixes: ea37fd2111 ("xen/arm: split vgic driver into generic and vgic-v2 driver")
Fixes: 54ec59f6b0 ("xen/arm: vgic-v3: Don't create empty re-distributor regions")
Signed-off-by: Mykola Kvach <mykola_kvach@epam.com>
Reviewed-by: Michal Orzel <michal.orzel@amd.com>
(cherry picked from commit 961cc8cc0f)
gicv3_dist_init() disables the distributor before reprogramming the
global interrupt state. It used to do this by writing 0 to GICD_CTLR.
On a system where firmware has already enabled Non-secure affinity
routing, a zero write clears the Non-secure view's GICD_CTLR.ARE_NS bit.
Arm IHI 0069H.b, section 2.3.3 ("Changing affinity routing enables"),
states that changing GICD_CTLR.ARE_NS from 1 to 0 is UNPREDICTABLE. The
GICD_CTLR register description in section 12.9.4 carries the same rule
for the ARE_NS field.
Preserve ARE_NS while clearing the group enable bits. If firmware left
ARE_NS clear, the value written is still 0, preserving the existing
initialization flow.
Fixes: bc183a0235 ("xen/arm: Add support for GIC v3")
Signed-off-by: Mykola Kvach <mykola_kvach@epam.com>
Reviewed-by: Michal Orzel <michal.orzel@amd.com>
Reviewed-by: Luca Fancellu <luca.fancellu@arm.com>
Release-Acked-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
(cherry picked from commit e63ba93511)
gicv3_do_wait_for_rwp() is used for both distributor and
redistributor writes. The CTLR register is at offset 0 for both,
but the RWP bit is not in the same position.
For GICD_CTLR, RWP is bit 31. For GICR_CTLR, bit 31 is UWP,
while RWP is bit 3. The redistributor wait path was therefore
polling UWP instead of RWP.
UWP covers upstream writes, including Generate SGI packets, and is
not a substitute for redistributor register write completion. The
existing redistributor callers need RWP semantics for redistributor
register writes such as GICR_ICENABLER0 and GICR_CTLR updates.
Add GICR_CTLR_RWP and pass the expected RWP bit to the shared
helper.
Fixes: bc183a0235 ("xen/arm: Add support for GIC v3")
Reported-by: Luca Fancellu <luca.fancellu@arm.com>
Signed-off-by: Mykola Kvach <mykola_kvach@epam.com>
Reviewed-by: Luca Fancellu <luca.fancellu@arm.com>
Acked-by: Stefano Stabellini <sstabellini@kernel.org>
(cherry picked from commit d86cf3cbd4)
Widen the len argument of copy_to_guest_phys_flush_dcache() and the
copy_to_guest_phys_cb typedef from unsigned int to unsigned long, as
the function can be used to copy large blobs such as the initrd which
may exceed 4GB. Update the internal copy_guest() len argument to
unsigned long accordingly.
Change the type for local variable size in copy_guest() to avoid
compilation error because of type mismatch.
raw_* wrappers above copy_guest() keep returning unsigned long to
avoid type narrowing; it is not an issue for raw_*'s len argument
to remain 'unsigned int' since the assignment to copy_guest()'s wider
unsigned long parameter is safe and there is no raw_* users who
are using a value bigger than what can fit into 'unsigned int'.
Fixes: 2986481b3d ("xen/arm: guest_copy: Extend the prototype to pass the vCPU")
Fixes: 5302bd490b ("xen/arm: Introduce copy_to_guest_phys_flush_dcache")
Fixes: d07b7369aa ("xen/common: dom0less: introduce common domain-build.c")
Reported-by: Jan Beulich <jbeulich@suse.com>
Signed-off-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Luca Fancellu <luca.fancellu@arm.com>
Acked-by: Michal Orzel <michal.orzel@amd.com>
(cherry picked from commit e4424b9a63)
The GICv2 CPU shutdown path currently writes 0 to GICC_CTLR.
Per IHI0048B.b section 2.3.1, clearing the architected bypass-disable
bits selects bypass rather than deasserted interrupt outputs when the
CPU interface stops driving them. Tables 2-2 and 2-3 show that a zeroed
GICC_CTLR can fall back to the legacy IRQ/FIQ inputs instead of fully
disabling the interface.
Fix this by reading GICC_CTLR, then setting the bypass-disable bits and
clearing the group-enable bits that are architecturally defined for the
current GICC_CTLR view before writing the value back. When Security
Extensions are implemented Xen accesses the Non-secure copy of
GICC_CTLR, where IRQBypDisGrp1 and FIQBypDisGrp1 are at bits [6:5] and
bits [8:7] are reserved.
Without Security Extensions (GICD_CTLR.DS=1), GICD_IGROUPR is RAZ/WI
and all interrupts are Group 0, so clearing EnableGrp0 alone is
sufficient to stop interrupt delivery through the CPU interface.
Section 2.3.2 also states that wakeup event signals remain available
even when both GIC interrupt signaling and interrupt bypass are
disabled, so disabling bypass does not break the power-management use
case, i.e. suspend modes.
Fixes: 5e40a1b435 ("arm: SMP CPU shutdown")
Signed-off-by: Mykola Kvach <mykola_kvach@epam.com>
Reviewed-by: Luca Fancellu <luca.fancellu@arm.com>
Reviewed-by: Michal Orzel <michal.orzel@amd.com>
(cherry picked from commit 6f00fd9d6c)
Branch offset decoding sign-extends the immediate by shifting it left into
bit 31 and back. Perform the left shift in uint32_t and cast to int32_t
only for the final right shift to avoid UBSAN failures on negative offsets.
Fixes: 6dbf3f0e30 ("xen/arm: arm64: Add helpers to decode and encode branch instructions")
Signed-off-by: Edgar E. Iglesias <edgar.iglesias@amd.com>
Reviewed-by: Stefano Stabellini <sstabellini@kernel.org>
(cherry picked from commit 65a99a4063)
gicv3_cpu_disable() currently writes 0 to ICC_CTLR_EL1. Unlike
GICC_CTLR in the GICv2 path, ICC_CTLR_EL1 does not enable or disable
physical Group 1 interrupt signalling, so this write only clears
EOImode.
The GICv3 power management rules require the physical group enables in
the CPU interface to be cleared before the redistributor is driven into
ProcessorSleep, otherwise behaviour is UNPREDICTABLE. Xen only enables
Group 1 interrupts on this path, so disable the interface by clearing
ICC_IGRPEN1_EL1 instead.
This appears to be a copy of the GICv2 pattern where the enable control
lives in CTLR, but for GICv3 the enable moved to ICC_IGRPEN1_EL1.
Fixes: bc183a0235 ("xen/arm: Add support for GIC v3")
Signed-off-by: Mykola Kvach <mykola_kvach@epam.com>
Reviewed-by: Michal Orzel <michal.orzel@amd.com>
(cherry picked from commit 18b718b6af)
gicv3_iomem_deny_access() incorrectly uses csize (physical CPU
interface size) instead of vsize (virtual CPU interface size) when
calculating the number of pages to deny for the virtual CPU interface
region at vbase.
Fixes: 8300b3377e ("arm/gic: Add a new callback to deny Dom0 access to GIC regions")
Signed-off-by: Michal Orzel <michal.orzel@amd.com>
Reviewed-by: Ayan Kumar Halder <ayan.kumar.halder@amd.com>
Reviewed-by: Luca Fancellu <luca.fancellu@arm.com>
Acked-by: Stefano Stabellini <sstabellini@kernel.org>
(cherry picked from commit 9af54b65a4)
iomem_deny_access() wraps rangeset_remove_range() which takes inclusive
endpoints. All call sites in the GIC and ACPI code pass 'mfn + nr' (or
'mfn + 1' for single-page regions) as the end parameter, which causes
one extra page beyond each region to be denied.
For single-page regions, use 'mfn' as the end (denying exactly one page).
For all multi-page regions, use 'mfn + nr - 1'.
This matches the correct pattern used elsewhere, e.g. in device.c.
Fixes: 8300b3377e ("arm/gic: Add a new callback to deny Dom0 access to GIC regions")
Fixes: 66158be465 ("ARM: ITS: Deny hardware domain access to ITS")
Fixes: 97e9875646 ("arm/acpi: Permit MMIO access of Xen unused devices for Dom0")
Signed-off-by: Michal Orzel <michal.orzel@amd.com>
Reviewed-by: Luca Fancellu <luca.fancellu@arm.com>
Reviewed-by: Stefano Stabellini <stefano.stabellini@amd.com>
(cherry picked from commit f25fe2452b)
When building Xen with CONFIG_STATIC_SHM=n, booting a hardware
domain with exactly NR_MEM_BANKS (256) reserved-memory regions
causes a panic:
(XEN) Xen BUG at common/device-tree/domain-build.c:497
(XEN) Xen call trace:
(XEN) [<00000a0000289aa8>] make_memory_node+0x178/0x234 (PC)
This occurs due to an off-by-one error in the bounds checking of
the reg array in make_memory_node(). The check:
BUG_ON(nr_cells >= ARRAY_SIZE(reg));
incorrectly triggers when the array is exactly full (i.e., when
nr_cells == ARRAY_SIZE(reg)), preventing the 256th and final valid
memory region from being written.
When CONFIG_STATIC_SHM=y, this bug is usually hidden because
DT_MEM_NODE_REG_RANGE_SIZE adds extra space for SHM banks.
This extra capacity prevents the array from reaching its
maximum limit while processing the 256th memory region.
However, if a domain is configured with exactly NR_MEM_BANKS
and NR_SHMEM_BANKS, the array will completely fill up and trigger
the same panic.
Fix this by changing the condition to strictly greater than (>).
Apply the exact same fix to shm_mem_node_fill_reg_range() to
prevent the same error.
Fixes: cd8015b634 ("ARM/dom0: Avoid using a variable length array in make_memory_node()")
Fixes: 7846f7699f ("xen/arm: List static shared memory regions as /memory nodes")
Signed-off-by: Oleksandr Tyshchenko <oleksandr_tyshchenko@epam.com>
Reviewed-by: Michal Orzel <michal.orzel@amd.com>
[michal: adjust for functions living in different files]
Signed-off-by: Michal Orzel <michal.orzel@amd.com>
(cherry picked from commit fc453fef77)
For now run similar set of tests as ADL.
Exclude suspend test for now. While firmware claims S3 is supported,
suspend attempt fails (power LED blinks for a few seconds, and
then system reboots). With no messages on the serial console, even with
`sync_console`.
Signed-off-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
(cherry picked from commit 77ed730bfb)
Unmapping the virtual VMCB is performed near the end of the domain
destroy procedure but the mapped guest frame prevents domain destroy
from getting to that point. This means guests that call VMRUN cannot
be fully destroyed.
Move the unmap of the virtual VMCB earlier to fix the issue.
Fixes: bcf557675d ("x86: properly use map_domain_page() in nested HVM code")
Signed-off-by: Ross Lagerwall <ross.lagerwall@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
master commit: 4d069a84ee
master date: 2026-06-30 09:41:35 +0200
The current logic in ns16550_interrupt() will loop until the device sets
the NOINT in IIR. At least on the Lenovo ThinkSystem SR630 V4 the flow
control of the serial-over-lan emulated UART seems to be broken, as it
doesn't set the NOINT bit consistently. The Transmitter Holding Register
Empty in LSR also seems to not be properly signaled, as even with it set
writes to the transmit register take ~6ms. This leads to the watchdog
triggering very easily on such system.
Introduce an upper bound on the execution time of ns16550_interrupt(), this
is currently set as 4x the polling interval, which is calculated as the
time to fill RX FIFO and/or empty TX FIFO. The current maximum timeout is
either 5ms or the polling interval, whatever is higher. Once the timeout
triggers the interrupt is disabled and the uart is switched to polling
mode.
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
master commit: d1b72a9aed
master date: 2026-06-29 17:14:47 +0200
It's possible for IRQ_DISABLED to be set while running the handler
execution loop in do_IRQ(). Such disabling can be done by the handler
itself, or from a remote CPU.
Check for IRQ_DISABLED not being set in the loop condition, as to not
execute the handler if the IRQ has been disabled.
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
master commit: b5edd9c58e
master date: 2026-06-29 17:14:47 +0200
In preparation for irq_to_desc() being called by common IRQ code.
PowerPC doesn't have an irq_desc array defined, so it cannot use the
generic irq_to_desc macro in the common header.
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Oleksii Kurochko <oleksii.kurochko@gmail.com>
master commit: ed39935f50
master date: 2026-06-29 17:14:47 +0200
Setting ->orig_video_isVGA to the specific marker should be done only when
the VBE tag is present and the FRAMEBUFFER is either absent or indicates
RGB type. Since the "video" variable now starts out non-NULL, this
property was broken when in particular neither of the tags are present. To
move back to at least close to original behavior, add a 2nd check to said
conditional.
Fixes: d5a73cdc6b ("x86/boot: Use boot_vid_info variable directly from C code")
Reported-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Tested-by: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Teddy Astie <teddy.astie@vates.tech>
master commit: c7b7429854
master date: 2026-06-25 13:37:33 +0200
XEN_DOMCTL_SCHEDOP_putvcpuinfo can flip the RTDS_extratime bit on a vCPU
that is currently depleted (cur_budget == 0, possibly sitting on the
depleted queue). rt_dom_cntl() touches only svc->flags; cur_budget is
left unchanged. As a result the next code path that calls runq_insert()
on this vCPU - rt_unit_wake() after a domain_unpause(),
rt_context_saved() following a delayed runq add, or repl_timer_handler()
after a replenishment - places the vCPU on the run queue, because
has_extratime(svc) is now true and runq_insert() admits extratime units
regardless of cur_budget:
/* add svc to runq if svc still has budget or its extratime is set */
if ( svc->cur_budget > 0 ||
has_extratime(svc) )
deadline_runq_insert(svc, &svc->q_elem, runq);
else
list_add(&svc->q_elem, &prv->depletedq);
The very next rt_schedule() iterates the run queue from runq_pick()
and trips the ASSERT(iter_svc->cur_budget > 0) at the bottom of the
loop, panicking the host. Observed trace:
Assertion 'iter_svc->cur_budget > 0' failed at common/sched/rt.c:1035
----[ Xen-4.22-unstable arm64 debug=y ubsan=y Not tainted ]----
[<...>] rt.c#rt_schedule+0x1558/0x33e0 (PC)
[<...>] core.c#do_schedule+0x2e4/0x15b4
[<...>] core.c#schedule+0xb14/0xe50
[<...>] softirq.c#__do_softirq+0x20c/0x3d4
[<...>] do_softirq+0x14/0x1c
[<...>] domain.c#idle_loop+0x194/0x558
Minimal reproducer: pin a single-vCPU domU to a pCPU, program RTDS with
extratime off and a low utilisation (e.g. budget = 10ms / period = 100ms)
so the vCPU spends most of its time in the depleted queue, pause the
domain, issue a putvcpuinfo that sets XEN_DOMCTL_SCHEDRT_extra, then
unpause. As soon as the schedule softirq fires on the pCPU, the BUG
hits. The same sequence is reachable without an explicit pause: any
window in which rt_dom_cntl() runs between burn_budget()'s budget
exhaustion and rt_context_saved()'s runq_insert() also closes onto the
same broken state, because the per-scheduler lock is dropped between
those two points.
The semantics for "extratime gets exhausted budget refilled" already
live in burn_budget():
if ( has_extratime(svc) )
{
svc->priority_level++;
svc->cur_budget = svc->budget;
}
Apply the same priority-demotion-and-refill in rt_dom_cntl() when the
flag transitions from off to on while the vCPU is depleted, clear
RTDS_depleted to match, and - if the vCPU is currently on the depleted
queue - move it to the run queue using the same q_remove() +
runq_insert() pattern already used by repl_timer_handler(). The vCPU
remains on the replenishment queue throughout, so its normal
replenishment cadence is preserved.
The complementary transition (on -> off) is already safe: clearing the
flag only narrows the runq_insert() admission condition, so subsequent
depleted insertions correctly route to the depleted queue.
No other call sites need changes: with cur_budget restored before the
flag is observable to runq_insert(), runq_pick()'s long-standing
invariant (every run-queue entry has cur_budget > 0) is preserved.
Fixes: 463b958317 ("xen:rtds: towards work conserving RTDS")
Signed-off-by: Oleksii Moisieiev <oleksii_moisieiev@epam.com>
Reviewed-by: Juergen Gross <jgross@suse.com>
master commit: 37b49cb48e
master date: 2026-06-25 13:36:43 +0200
cpumask_to_xenctl_bitmap() may return errors. Clearing the error indicator
of an earlier such call by a (successful) later call is misleading the
caller. For "set", keep setting soft affinity if the hard affinity copy-
back fails; only accumulate respective errors.
While fiddling with return values, also drop a redundant clearing of
"ret". This eliminates a Misra C:2012 rule 2.2 ("There shall be no dead
code") violation.
Fixes: 6e4ecc6d58 ("sched: DOMCTL_*vcpuaffinity works with hard and soft affinity")
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Juergen Gross <jgross@suse.com>
Reviewed-by: Roger Pau Monné <roger.pau@citrix.com>
master commit: 6a21252a74
master date: 2026-06-18 10:02:34 +0200
There is a 3rd path which should have gained an is_zen6_uarch() check to
exclude Zen6 from entrysign mitigations.
Fixes: bd15fdedaf ("x86/ucode: Exclude Zen6 from entrysign mitigations")
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Teddy Astie <teddy.astie@vates.tech>
Acked-by: Jan Beulich <jbeulich@suse.com>
master commit: 6ba5e9c7b8
master date: 2026-06-16 18:33:39 +0100
Today the inline tracking of the stub page is problematic. 0xcc is used to
indicate unused, but it is also a "clear value." A !CONFIG_PV build or
when running with FRED support will not populate the LSTAR/CSTAR stubs at
CPU bringup. If a CPU is then offlined, the stubs page will be freed as
its content will be all 0xcc, regardless of the stubs page still begin
referenced by other CPUs.
The new approach uses a global, CPU-indexed dynamically allocated array of
stub addresses. However, to handle NUMA aware allocations, we cannot
allocate all the memory in advance because of the NUMA dependency. Take
advantage of the fact that Xen will attempt to contiguously pack CPUs on
the same NUMA node (see normalise_cpu_order()), and on CPU bringup use the
same stubs page the previous CPU did if suitable. Note the code would
still function properly even if CPUs from NUMA nodes are not contiguously
packed, it just consumes more memory.
Stubs pages are no longer freed. They remain referenced in the global
CPU-indexed array and are re-used if the CPU is re-onlined.
The stubs array doesn't have an explicit lock. During boot it's accessed
single threaded. During runtime, &cpu_add_remove_lock serializes access.
Fixes: 7a66ac8d16 ("x86: move syscall trampolines off the stack")
Signed-off-by: Jason Andryuk <jason.andryuk@amd.com>
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
Tested-by: Jason Andryuk <jason.andryuk@amd.com>
Reviewed-by: Jason Andryuk <jason.andryuk@amd.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
master commit: 4f2c223c59
master date: 2026-06-12 12:00:12 +0200
Per PCI Firmware 3.3 specification, section 4.1.2, ECAM space must be
reserved by declaring a motherboard resource, but there's no requirement to
mention it in E820. The specification additionally states that: the
resources can optionally be returned in Int15 E820h or EFIGetMemoryMap as
reserved memory.
Recent Lenovo systems have been found to have the MMCFG region in an
E820 hole, which looks to be technically spec compliant, but is rejected
by Xen.
The logic was introduced in Linux in 2006 as 946f2ee5c731 ("[PATCH]
i386/x86-64: Check that MCFG points to an e820 reserved area"). This was
picked up by Xen when MCFG support was added in 3b35911d70 ("Enable pci
mmcfg and ATS for x86_64"). Apply an approach similar to what Linux has
done in 199f968f1484 ("x86/pci: Skip early E820 check for ECAM region") and
relax the strict reserved region checking so it's only done for firmware
manufactured prior to 2016. For firmware from 2016 and newer allow MCFG
region to reside in holes on the memory map. Note Xen is still more strict
than Linux however, as it will refuse to use MCFG regions that overlap with
memory map regions different than reserved.
When dom0 boots it can prevent access to misconfigured MCFG regions by
using the PHYSDEVOP_pci_mmcfg_reserved hypercall. This brings Xen's early
usage of MCFG (prior to ACPI AML parsing) more in line with the
implementation in Linux.
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
master commit: 87279cafc0
master date: 2026-06-05 17:40:21 +0200
reserve_offlined_page() reserves pages marked for offlining and
returns free buddies from the remaining healthy tail pages back
to the free list.
Consider an order-2 buddy (4 pages) with the following layout:
+---------------+---------------+---------------+---------------+
| head page tail page 1, tail page 2 tail page 3 |
| PFN_ORDER(pg) marked as to |
| == 2 be offlined |
+---------------+---------------+---------------+---------------+
The expected result after removing tail page 1 and returning the
remaining healthy pages to the free list would be:
+---------------+ +---------------+---------------+
| single page | offlined page | head page tail page |
| PFN_ORDER(pg) | not returned | PFN_ORDER(pg) |
| == 0 | to the heap | == 1 |
+---------------+ +---------------+---------------+
A trivial off-by-one error in the growth loop stops the growth loop
early before the tail end of the original buddy and we end up with:
+---------------+ +---------------+---------------+
| single page | offlined page | single page | single page |
| PFN_ORDER(pg) | not returned | PFN_ORDER(pg) | PFN_ORDER(pg) |
| == 0 | to the heap | == 0 | == 0 |
+---------------+ +---------------+---------------+
If the offlined page was in a much larger buddy, this would lead
to much more memory not available for higher order allocations
requiring the full tail end of the original buddy for allocation.
Fix the growth loop to correctly grow the buddy to the tail end
to make the full allocation unit available for future allocation.
Fixes: e4865c2315 ('Page offline support in Xen side')
Signed-off-by: Bernhard Kaindl <bernhard.kaindl@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
master commit: 5cb7ff13ee
master date: 2026-06-05 10:08:42 +0200
reserve_offlined_page() fails to verify alignment when growing
buddies around offlined pages. Consequently, misaligned buddies
may be constructed from non-offlined page ranges and returned to
the free lists.
After a particular sequence of allocations and frees, pages
from such a misaligned buddy may be allocated more than once,
eventually triggering a Xen BUG() in alloc_heap_pages().
Fixes: e4865c2315 ('Page offline support in Xen side')
Signed-off-by: Bernhard Kaindl <bernhard.kaindl@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
master commit: 71c6a62317
master date: 2026-06-05 10:08:22 +0200
Attempting to memset the whole IOMMU MMIO region to zero is dangerous to
say the least. We don't know which registers might be there, nor which
values might be safe for those registers. On a forthcoming platform doing
the zeroing of the MMIO region does put the IOMMU in a broken state, which
is not recoverable by the IOMMU initialization procedure in Xen.
Instead just zero the control register, which mimics the current behavior
with regards to how the control register is handled, and ensures the IOMU
setup is done with the unit disabled. This approach will need revisiting
in order to support Preboot DMA Protection.
Fold map_iommu_mmio_region() into its only caller, as the function body is
just an ioremap() call after the removal of the memset().
Fixes: 0700c962ac ("Add AMD IOMMU support into hypervisor")
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
Reviewed-by: Andrew Cooper <andrew.cooper@citrix.com>
master commit: bdb30883f3
master date: 2026-05-06 18:56:59 +0200
In order to avoid serialising the testing on both boards, the runner
configuration is being adjusted.
Have the .xilinx-arm64 and .xilinx-x86_64 templates choose the board directly
using a more specific tag.
No functional change.
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Victor Lira <victorm.lira@amd.com>
(cherry picked from commit efcb4c5e2f)
Ocaml's lib directory layout changed in 5.0: the unix and dynlink
libraries have been moved out of the standard library directory into
subdirectories. The compiler still locates them automatically but emits
an ocaml_deprecated_auto_include alert when doing so.
This patch sets the paths explicitly with -I +unix and -I +dynlink to
silence the alert.
Signed-off-by: Guillaume Thouvenin <guillaume.thouvenin@vates.tech>
Reviewed-by: Andrii Sultanov <andriy.sultanov@vates.tech>
Tested-by: Andrii Sultanov <andriy.sultanov@vates.tech>
Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
(cherry picked from commit c3cf7c4121)