mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Amirmohammad Eftekhar <amirmohammad.eftekhar@cispa.de>
To: <seanjc@google.com>, <pbonzini@redhat.com>
Cc: <kvm@vger.kernel.org>, <linux-kernel@vger.kernel.org>
Subject: [BUG] KVM: x86: __set_regs() silently drops a pending nested exception destined to VM-exit to L1
Date: Sat, 17 Oct 2026 01:52:21 +0200	[thread overview]
Message-ID: <20261016235221.33726-5-amirmohammad.eftekhar@cispa.de> (raw)

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


             reply	other threads:[~2026-10-17  0:33 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-16 23:52 Amirmohammad Eftekhar [this message]
2026-10-17  0:50 ` Sean Christopherson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261016235221.33726-5-amirmohammad.eftekhar@cispa.de \
    --to=amirmohammad.eftekhar@cispa.de \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=pbonzini@redhat.com \
    --cc=seanjc@google.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®