Kernel KVM virtualization development
 help / color / mirror / Atom feed
* [BUG] KVM: x86: __set_regs() silently drops a pending nested exception destined to VM-exit to L1
@ 2026-10-16 23:52 Amirmohammad Eftekhar
  2026-10-17  0:50 ` Sean Christopherson
  0 siblings, 1 reply; 2+ messages in thread
From: Amirmohammad Eftekhar @ 2026-10-16 23:52 UTC (permalink / raw)
  To: seanjc, pbonzini; +Cc: kvm, linux-kernel

Hi,

__set_regs() (arch/x86/kvm/regs.c:102) unconditionally clears both pending
exception queues:

	vcpu->arch.exception.pending        = false;	/* regs.c:129 */
	vcpu->arch.exception_vmexit.pending = false;	/* regs.c:130 */

Neither clear is gated by is_guest_mode(), and neither is visible to
KVM_GET/SET_VCPU_EVENTS. exception_vmexit is the queued exception KVM will turn
into a nested VM-exit to L1 (the vector L1 intercepts via the VMX
EXCEPTION_BITMAP / #PF error-code match, or SVM intercept_exceptions). When L2
is active and that reflection is pending, a KVM_SET_REGS the VMM issues for an
unrelated reason silently discards the reflection L1 configured, so L2 evades an
exception interception L1 relies on. __set_regs() is reached by
ioctl(KVM_SET_REGS) and by the KVM_SYNC_X86_REGS dirty-regs path
(kvm_run->s.regs, regs.c:728).

Class: a KVM ABI-level correctness bug (edge E3 -- L2 escapes an L1-intended
interception). It is NOT host corruption: the drop is clear-only, so it cannot
violate the requeue/injection WARNs (kvm_clear_exception_queue runs first in
*_complete_interrupts, so the drop cannot create dual-pending, set TRIPLE_FAULT,
or leave pending while !is_guest_mode), the SMM/#DF morph early-returns before
the #DF logic, and exception_vmexit is a software queue never written to
vmcs02/vmcb02 VM_ENTRY_INTR_INFO, so there is no stale hardware injection. All
PoC runs are dmesg-clean under KASAN. It is also not memory-safety and not a host
DoS.

Not reachable through stock QEMU: the apparent guest trigger (L2 IN 0x5658 ->
cpu_synchronize_state -> KVM_SET_REGS) does not drop anything, because QEMU's
put order is kvm_put_vcpu_events after KVM_SET_REGS in the same
kvm_arch_put_registers (it re-stuffs exception.pending, and the entry-morph
re-creates exception_vmexit), and QEMU x86 does not use KVM_SYNC_X86_REGS. So
this needs a custom/buggy VMM, or a direct /dev/kvm user issuing SET_REGS
without a paired events-put while in guest mode.

Secondary (H4): __set_regs() leaves exception_from_userspace and
exception.vector intact, so a pure-userspace KVM_SET_VCPU_EVENTS(pending=V) ->
KVM_SET_REGS with no KVM_RUN between makes the entry-morph fire a spurious
reflection of V that userspace believed it cleared. Real, self-cleaning,
VMM-userspace-only, and not QEMU-reachable (QEMU's put order is SET_REGS before
SET_VCPU_EVENTS).

Suggested direction (for your call): either do not clear exception_vmexit in
__set_regs() (leave the nested reflection to GET/SET_VCPU_EVENTS, which already
round-trips it correctly), or gate the clears appropriately and also clear
exception_from_userspace/vector so the H4 spurious-reflection path cannot fire.
I did not want to pick an ABI semantics here without your input.

Demonstrations (both dmesg-clean, deterministic, Intel 7.3-rc3): a standalone
KVM selftest that uses immediate_exit to hold exception_vmexit.pending across a
KVM_RUN return, then shows KVM_SET_REGS drops it while a GET/SET_VCPU_EVENTS
round-trip preserves it. It is small and I can post it alongside a patch once
the intended fix is agreed.

Thanks,
Amirmohammad


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-10-17  0:50 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-16 23:52 [BUG] KVM: x86: __set_regs() silently drops a pending nested exception destined to VM-exit to L1 Amirmohammad Eftekhar
2026-10-17  0:50 ` Sean Christopherson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox