* [PATCH] KVM: x86: Cancel IOAPIC EOI work before freeing vCPUs
@ 2026-07-28 9:33 Myeonghun Pak
2026-07-28 12:56 ` Sean Christopherson
0 siblings, 1 reply; 2+ messages in thread
From: Myeonghun Pak @ 2026-07-28 9:33 UTC (permalink / raw)
To: seanjc, pbonzini; +Cc: kvm, security, stable
The IOAPIC delayed EOI injection worker dereferences local APIC pointers
from the VM's APIC map. Since commit 17bcd7144263 ("KVM: x86: Free
vCPUs before freeing VM state"), kvm_arch_destroy_vm() frees vCPUs and
their local APICs before kvm_ioapic_destroy() synchronously cancels the
worker.
Consequently, if the delayed work is pending when VM teardown starts,
the worker can run after a local APIC has been freed. Generic KASAN
reported:
BUG: KASAN: slab-use-after-free in
__kvm_irq_delivery_to_apic_fast+0x7f6/0x840 [kvm]
Read of size 8 by task kworker/3:3
Workqueue: events kvm_ioapic_eoi_inject_work [kvm]
The allocation stack contains kvm_create_lapic(). The free stack is:
kvm_arch_vcpu_destroy
kvm_destroy_vcpus
kvm_arch_destroy_vm
kvm_put_kvm
A ring-0 guest can arm the delayed work by repeatedly acknowledging an
asserted level-triggered interrupt, and can then request a reset that
causes an unmodified QEMU process started with -no-reboot to perform
final VM teardown. I reproduced the UAF on current Linux master as of
2026-07-27 with unmodified Debian QEMU 10.0.11. No guest vCPU
hot-unplug or post-launch host-side teardown ioctl was used.
The regression first appeared upstream in v6.14. The same ordering
change was backported to the v6.12.y stable series and first released in
v6.12.41.
Cancel the delayed work from kvm_arch_pre_destroy_vm(), before vCPUs and
their local APICs are freed. Keep the cancellation in the final IOAPIC
destroy path through the same helper so that partial initialization and
error paths remain covered.
With this patch applied to the same KASAN build:
- arch/x86/kvm modules build successfully;
- scripts/checkpatch.pl --strict reports no errors or warnings;
- 500 complete stock-QEMU guest trigger/teardown iterations completed
without a new KASAN report;
- 50 iterations of the direct KVM race reproducer, each with 64 vCPUs,
completed without a new KASAN report;
- a stock-QEMU kernel-irqchip=split smoke test completed successfully,
covering the no in-kernel IOAPIC case;
- ftrace confirms kvm_ioapic_pre_destroy() runs before
kvm_destroy_vcpus() and kvm_free_lapic().
The source reproducer and full KASAN report are available on request.
Fixes: 17bcd7144263 ("KVM: x86: Free vCPUs before freeing VM state")
Cc: stable@vger.kernel.org
Signed-off-by: Myeonghun Pak <mhun512@gmail.com>
---
arch/x86/kvm/ioapic.c | 12 +++++++++++-
arch/x86/kvm/ioapic.h | 1 +
arch/x86/kvm/x86.c | 1 +
3 files changed, 13 insertions(+), 1 deletion(-)
AI disclosure: I used AI assistance during the audit and am treating the
issue as public as required by Documentation/process/security-bugs.rst.
The reproducer has not been posted publicly.
diff --git a/arch/x86/kvm/ioapic.c b/arch/x86/kvm/ioapic.c
index 757667fb2bfa0..6133061e18f10 100644
--- a/arch/x86/kvm/ioapic.c
+++ b/arch/x86/kvm/ioapic.c
@@ -741,7 +741,7 @@ int kvm_ioapic_init(struct kvm *kvm)
return ret;
}
-void kvm_ioapic_destroy(struct kvm *kvm)
+void kvm_ioapic_pre_destroy(struct kvm *kvm)
{
struct kvm_ioapic *ioapic = kvm->arch.vioapic;
@@ -749,6 +749,16 @@ void kvm_ioapic_destroy(struct kvm *kvm)
return;
cancel_delayed_work_sync(&ioapic->eoi_inject);
+}
+
+void kvm_ioapic_destroy(struct kvm *kvm)
+{
+ struct kvm_ioapic *ioapic = kvm->arch.vioapic;
+
+ if (!ioapic)
+ return;
+
+ kvm_ioapic_pre_destroy(kvm);
mutex_lock(&kvm->slots_lock);
kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS, &ioapic->dev);
mutex_unlock(&kvm->slots_lock);
diff --git a/arch/x86/kvm/ioapic.h b/arch/x86/kvm/ioapic.h
index 3dadae0936902..5bfbae63f3689 100644
--- a/arch/x86/kvm/ioapic.h
+++ b/arch/x86/kvm/ioapic.h
@@ -105,6 +105,7 @@ void kvm_rtc_eoi_tracking_restore_one(struct
kvm_vcpu *vcpu);
void kvm_ioapic_update_eoi(struct kvm_vcpu *vcpu, int vector,
int trigger_mode);
int kvm_ioapic_init(struct kvm *kvm);
+void kvm_ioapic_pre_destroy(struct kvm *kvm);
void kvm_ioapic_destroy(struct kvm *kvm);
int kvm_ioapic_set_irq(struct kvm_kernel_irq_routing_entry *e, struct kvm *kvm,
int irq_source_id, int level, bool line_status);
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index afcac1042947a..9b4e89cd8169c 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -13432,6 +13432,7 @@ void kvm_arch_pre_destroy_vm(struct kvm *kvm)
*/
#ifdef CONFIG_KVM_IOAPIC
kvm_free_pit(kvm);
+ kvm_ioapic_pre_destroy(kvm);
#endif
kvm_mmu_pre_destroy_vm(kvm);
--
2.47.2
^ permalink raw reply related [flat|nested] 2+ messages in thread* Re: [PATCH] KVM: x86: Cancel IOAPIC EOI work before freeing vCPUs
2026-07-28 9:33 [PATCH] KVM: x86: Cancel IOAPIC EOI work before freeing vCPUs Myeonghun Pak
@ 2026-07-28 12:56 ` Sean Christopherson
0 siblings, 0 replies; 2+ messages in thread
From: Sean Christopherson @ 2026-07-28 12:56 UTC (permalink / raw)
To: Myeonghun Pak; +Cc: pbonzini, kvm, security, stable
On Tue, Jul 28, 2026, Myeonghun Pak wrote:
> The IOAPIC delayed EOI injection worker dereferences local APIC pointers
> from the VM's APIC map. Since commit 17bcd7144263 ("KVM: x86: Free
> vCPUs before freeing VM state"), kvm_arch_destroy_vm() frees vCPUs and
> their local APICs before kvm_ioapic_destroy() synchronously cancels the
> worker.
>
> Consequently, if the delayed work is pending when VM teardown starts,
> the worker can run after a local APIC has been freed.
...
> Fixes: 17bcd7144263 ("KVM: x86: Free vCPUs before freeing VM state")
> Cc: stable@vger.kernel.org
> Signed-off-by: Myeonghun Pak <mhun512@gmail.com>
> ---
> arch/x86/kvm/ioapic.c | 12 +++++++++++-
> arch/x86/kvm/ioapic.h | 1 +
> arch/x86/kvm/x86.c | 1 +
> 3 files changed, 13 insertions(+), 1 deletion(-)
>
> AI disclosure: I used AI assistance during the audit and am treating the
> issue as public as required by Documentation/process/security-bugs.rst.
> The reproducer has not been posted publicly.
Though that doesn't seem to matter much given you're the fourth person/group to
independently report this bug. :-)
A fix is already pending:
https://lore.kernel.org/all/20260727171718.543491-1-seanjc@google.com
Thanks!
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-07-28 12:56 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-28 9:33 [PATCH] KVM: x86: Cancel IOAPIC EOI work before freeing vCPUs Myeonghun Pak
2026-07-28 12:56 ` 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.