[PATCH v4 00/11] KVM: x86/hyperv: Fix racy usage of vcpu->arch.hyperv

From: Sean Christopherson

Date: Tue Jun 30 2026 - 18:56:25 EST


Fix a bug found by syzkaller (originally on a Google-internal kernel, but now
on upstream as well) where KVM consumes a vCPU's HyperV structure before it's
fully initialized, by concurrently triggering PV TLB flushes (queues flushes
into a vCPU's FIFO without holding the vCPU's mutex) on a vCPU that is in the
process of activating HyperV.

Harden against similar bugs by asserting the vcpu->mutex is held when using
the "normal" to_hv_vcpu(), same as we did for get_vmcs12() and
get_shadow_vmcs12() (also in response to cross-task races). To avoid false
positives when creating a vCPU, initialize vcpu_idx to -1, and treat the vCPU
as unreachable (other than the caller, obviously) if its index is -1.

v4:
- Route non-timer hypercalls at the very beginning of kvm_xen_hcall_vcpu_op()
so that KVM doesn't unintentionally resume the guest on bad input (which
might not even be bad since KVM would misinterpet the input). [Sashiko]
- Suck less at unwinding on failure, i.e. invalidate the vcpu_idx on any
failure during vCPU creation. [Sashiko, syzbot]
- Reference U32_MAX, not -1u. [David]
- Add a compile-time assert to ensure XEN_VCPU_ID_INVALID can't collide with
KVM's range of legal values.

v3:
- https://lore.kernel.org/all/20260625223623.3376478-1-seanjc@xxxxxxxxxx
- Reset vcpu_idx back to -1 if adding the vCPU to the xarray fails. [syzbot]
- Use the safe accessor in kvm_hv_has_stimer_pending(). [sashiko]
- Explicitly initialize vcpu->arch.xen.vcpu_id to XEN_VCPU_ID_INVALID, and
punt singleshot timer hypercalls to userspace if the vCPU ID hasn't been
set. [sashiko, David]

v2:
- https://lore.kernel.org/all/20260612230622.687665-1-seanjc@xxxxxxxxxx
- Init vcpu->vcpu_idx to -1, use that as a canary to detect the vCPU is
unreachable, and allow accessing Hyper-V state if the vCPU is otherwise
unreachable. [syzbot]

v1: https://lore.kernel.org/all/20260423140833.439512-1-seanjc@xxxxxxxxxx

Sean Christopherson (11):
KVM: x86/hyperv: Get target FIFO in hv_tlb_flush_enqueue(), not caller
KVM: x86/hyperv: Check for NULL vCPU Hyper-V object in
kvm_hv_get_tlb_flush_fifo()
KVM: x86/hyperv: Ensure vCPU's Hyper-V object is initialized on
cross-vCPU accesses
KVM: x86/xen: Always route non-singleshot-timer vCPU hypercalls to
userspace
KVM: x86/xen: Consolidate checks on Xen vCPU ID for singleshot timer
hypercalls
KVM: x86/xen: Punt singleshot timer hcalls to userspace if Xen vCPU ID
isn't set
KVM: Initialize a vCPU's index to '-1' while it's being created
KVM: Move nVMX's lockdep logic for vcpu->mutex to a common helper
KVM: x86: Treat a vCPU as unreachable if its index is invalid
KVM: x86/hyperv: Assert vCPU's mutex is held in to_hv_vcpu()
KVM: x86/hyperv: Use {READ,WRITE}_ONCE for cross-task synic->active
accesses

arch/x86/kvm/hyperv.c | 64 +++++++++++++++++++++------------------
arch/x86/kvm/hyperv.h | 27 ++++++++++++++---
arch/x86/kvm/vmx/nested.h | 6 ++--
arch/x86/kvm/xen.c | 43 +++++++++++++++-----------
include/linux/kvm_host.h | 7 +++++
virt/kvm/kvm_main.c | 8 +++++
6 files changed, 99 insertions(+), 56 deletions(-)


base-commit: a204badd8432f93b7e862e7dac6db0fe3d65f370
--
2.55.0.rc0.799.gd6f94ed593-goog