commit f458d039db7e ("kvm: ioapic: Lazy update IOAPIC EOI") introduces the following regression. BUG: stack guard page was hit at 000000008f595917 \ (stack is 00000000bdefe5a4..00000000ae2b06f5) kernel stack overflow (double-fault): 0000 [#1] SMP NOPTI RIP: 0010:kvm_set_irq+0x51/0x160 [kvm] Call Trace: irqfd_resampler_ack+0x32/0x90 [kvm] kvm_notify_acked_irq+0x62/0xd0 [kvm] kvm_ioapic_update_eoi_one.isra.0+0x30/0x120 [kvm] ioapic_set_irq+0x20e/0x240 [kvm] kvm_ioapic_set_irq+0x5c/0x80 [kvm] kvm_set_irq+0xbb/0x160 [kvm] ? kvm_hv_set_sint+0x20/0x20 [kvm] irqfd_resampler_ack+0x32/0x90 [kvm] kvm_notify_acked_irq+0x62/0xd0 [kvm] kvm_ioapic_update_eoi_one.isra.0+0x30/0x120 [kvm] ioapic_set_irq+0x20e/0x240 [kvm] kvm_ioapic_set_irq+0x5c/0x80 [kvm] kvm_set_irq+0xbb/0x160 [kvm] ? kvm_hv_set_sint+0x20/0x20 [kvm] .... This is due to re-entrancy of the lazy update EOI logic when enable APICv with VFIO pass-through device, which sets up kvm_irqfd() w/ KVM_IRQFD_FLAG_RESAMPLE. Fixes by adding re-entrancy check logic. Reported-by: borisvk@xxxxxxxxxx Suggested-by: Paolo Bonzini <pbonzini@xxxxxxxxxx> Link: https://www.spinics.net/lists/kvm/msg213512.html Fixes: f458d039db7e ("kvm: ioapic: Lazy update IOAPIC EOI") Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=207489 Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@xxxxxxx> --- arch/x86/kvm/ioapic.c | 11 +++++++++++ arch/x86/kvm/ioapic.h | 1 + 2 files changed, 12 insertions(+) diff --git a/arch/x86/kvm/ioapic.c b/arch/x86/kvm/ioapic.c index 750ff0b..a68f624 100644 --- a/arch/x86/kvm/ioapic.c +++ b/arch/x86/kvm/ioapic.c @@ -188,6 +188,14 @@ static void ioapic_lazy_update_eoi(struct kvm_ioapic *ioapic, int irq) struct kvm_vcpu *vcpu; union kvm_ioapic_redirect_entry *entry = &ioapic->redirtbl[irq]; + /* + * Re-entrancy check due to KVM_IRQFD_FLAG_RESAMPLE can cause + * stack overflow where irqfd_resampler_ack() repeatedly calls + * ioapic_set_irq(). + */ + if (atomic_cmpxchg(&ioapic->in_lazy_update_eoi, 0, 1)) + return; + kvm_for_each_vcpu(i, vcpu, ioapic->kvm) { if (!kvm_apic_match_dest(vcpu, NULL, APIC_DEST_NOSHORT, entry->fields.dest_id, @@ -205,6 +213,8 @@ static void ioapic_lazy_update_eoi(struct kvm_ioapic *ioapic, int irq) irq); break; } + + atomic_set(&ioapic->in_lazy_update_eoi, 0); } static int ioapic_set_irq(struct kvm_ioapic *ioapic, unsigned int irq, @@ -707,6 +717,7 @@ int kvm_ioapic_init(struct kvm *kvm) kvm->arch.vioapic = NULL; kfree(ioapic); } + atomic_set(&ioapic->in_lazy_update_eoi, 0); return ret; } diff --git a/arch/x86/kvm/ioapic.h b/arch/x86/kvm/ioapic.h index 2fb2e3c..898a967 100644 --- a/arch/x86/kvm/ioapic.h +++ b/arch/x86/kvm/ioapic.h @@ -91,6 +91,7 @@ struct kvm_ioapic { struct delayed_work eoi_inject; u32 irq_eoi[IOAPIC_NUM_PINS]; u32 irr_delivered; + atomic_t in_lazy_update_eoi; }; #ifdef DEBUG -- 1.8.3.1