* [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
* Re: [BUG] KVM: x86: __set_regs() silently drops a pending nested exception destined to VM-exit to L1
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
0 siblings, 0 replies; 2+ messages in thread
From: Sean Christopherson @ 2026-10-17 0:50 UTC (permalink / raw)
To: Amirmohammad Eftekhar; +Cc: pbonzini, kvm, linux-kernel
On Sat, Oct 17, 2026, Amirmohammad Eftekhar wrote:
> 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 */
And? It's an ioctl. KVM can do whatever it wants, so long as it doesn't break
userspace. Clearing the exception queue was deliberately added by commit
b4f14abd95cd ("KVM: Avoid spurious execeptions after setting registers") back in
2008. Whether or not that was the best fix way back when, probably not. But it
simply doesn't matter, this has been KVM's behavior for 18+ years.
^ 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.