[PATCH v2 00/11] KVM: x86/xen: Clean up shared info / vcpu info handling
From: David Woodhouse
Date: Tue Aug 11 2026 - 07:14:01 EST
KVM reads kvm->arch.xen.long_mode in a dozen places to decide whether the
guest's shared_info and vcpu_info are in native or compat layout. The guest
can change that flag at any time from another vCPU, and several code paths
read it more than once, assuming the two reads agree.
The most serious case is kvm_xen_set_evtchn_fast(), where max_evtchn_port()
and the bitmap layout selection each call it separately. If the mode changes
in between, a port accepted by the 64-bit range check (up to 4095) can be
handled with the 32-bit layout, giving a port_word_bit of up to 127 — and
test_and_set_bit() then runs off the end of the 8-byte evtchn_pending_sel,
into the adjacent vcpu_id and timer_virq fields.
Related, the vcpu_info is guest-controlled and only 4-byte aligned, but the
generic test_and_set_bit()/set_bit() helpers use 64-bit locked operations on
x86-64. On a host with split_lock_detect=fatal that is a guest-triggerable
panic.
Patches 10 and 11 are new bugfixes in v2. One bug I found while working
on the SRCU conversion of the gfn_to_pfn_cache locking, and syzbot found
the other. These could potentially each be submitted separately, but
I've elected to round them up here to slightly reduce the number of
patch series in flight.
So:
- Patches 1-3 are preparatory renames and a kvm_xen_has_64bit_shinfo()
helper which does the READ_ONCE() in one place.
- Patches 4-5 latch the mode once on entry to kvm_xen_set_evtchn_fast()
and kvm_xen_schedop_poll(), so the range check and the layout selection
cannot disagree.
- Patch 6 enforces 4-byte alignment of the vcpu_info registration. Note
this deliberately does *not* require 8-byte alignment even in 64-bit
mode: a guest may validly register a 4-byte aligned vcpu_info while in
32-bit mode and only later switch to 64-bit, and rejecting that would
break migration of such guests.
- Patches 7-9 use 32-bit atomics where the address is guest-controlled,
and then replace the open-coded asm with the atomic*() APIs.
- Patch 10 takes kvm->srcu in __kvm_xen_has_interrupt(), which has been
calling kvm_gpc_check() — and thus dereferencing kvm->memslots — without
it since 2022.
- Patch 11 fixes a use-after-free in the gfn_to_pfn_cache refresh path
for HVA-based caches (e.g. a shared_info page registered with
KVM_XEN_ATTR_TYPE_SHARED_INFO_HVA), reported by syzbot. The refresh
retry check relies on kvm->mmu_invalidate_seq, which is only advanced
for invalidations overlapping a memslot; an HVA-based cache need not
be backed by a memslot at all, so an invalidation of the cached HVA
which starts and ends entirely within the HVA->PFN lookup window is
invisible to it, and the refresh publishes a mapping of a freed page.
Add a dedicated sequence count advanced by every invalidation.
v2:
- Add patch 10 (kvm->srcu in __kvm_xen_has_interrupt()).
- Add patch 11 (dedicated invalidation sequence for HVA-based caches).
- Take Sean's version of the 32-bit atomics patch, and his follow-up
replacing the remaining asm blobs with atomic*() APIs.
- Use GEN_BINARY_RMWcc() rather than open-coding the btsl.
- Explain why the pending_bits access in kvm_xen_set_evtchn_fast() does
not need the same treatment as the vcpu_info one (it is in the page
aligned per-VM shared_info).
- Don't require 8-byte alignment of vcpu_info in 64-bit mode; always
accept 4-byte alignment, so as not to break migration of guests which
registered while in 32-bit mode.
- Add Closes: links for the reported issues.
- Cast to u64 before the >> 32 in the unaligned evtchn_pending_sel
handling; evtchn_pending_sel is unsigned long, so the shift was
undefined on 32-bit even though the branch is unreachable there
(kernel test robot).
- Rebase onto kvm-x86/next; the mode-aware kvm_<reg>_read() helpers which
landed in the meantime subsume most of what patch 1 was doing by hand.
v1: https://lore.kernel.org/all/20260605143034.3603-1-dwmw2@xxxxxxxxxxxxx/
David Woodhouse (8):
KVM: x86/xen: Rename 'longmode' to 'is_64bit' in hypercall handling
KVM: x86/xen: Introduce kvm_xen_has_64bit_shinfo() macro
KVM: x86/xen: Rename max_evtchn_port() to kvm_max_evtchn_port()
KVM: x86/xen: Latch shinfo mode in kvm_xen_schedop_poll()
KVM: x86/xen: Enforce 4-byte alignment of vcpu_info registration
KVM: x86/xen: Use 32-bit locked bts for vcpu_info evtchn_pending_sel
KVM: x86/xen: Take kvm->srcu in __kvm_xen_has_interrupt()
KVM: pfncache: use a dedicated invalidation sequence for cache refresh
Hyunwoo Kim (1):
KVM: x86/xen: Latch shinfo mode in kvm_xen_set_evtchn_fast()
Sean Christopherson (2):
KVM: x86/xen: Use 32-bit atomics if vCPU's evtchn_pending_sel isn't aligned
KVM: x86/xen: Use atomic*() APIs instead of open coded equivalents
arch/x86/kvm/xen.c | 170 ++++++++++++++++++++++++++++++-----------------
arch/x86/kvm/xen.h | 5 ++
include/linux/kvm_host.h | 2 +
virt/kvm/kvm_main.c | 10 +++
virt/kvm/pfncache.c | 18 ++---
5 files changed, 135 insertions(+), 70 deletions(-)