From: Anel Orazgaliyeva Date: Fri, 6 Mar 2026 07:59:52 +0000 (+0100) Subject: KVM: X86: Fix array_index_nospec protection in __pv_send_ipi X-Git-Tag: v7.1-rc1~118^2~9^2~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=00d572d4cd7d23f9a7a498d2d824b68ba3ea5b88;p=thirdparty%2Fkernel%2Flinux.git KVM: X86: Fix array_index_nospec protection in __pv_send_ipi The __pv_send_ipi() function iterates over up to BITS_PER_LONG vCPUs starting from the APIC ID specified in its 'min' argument, which is provided by the guest. Commit c87bd4dd43a6 used array_index_nospec() to clamp the value of 'min' but then the for_each_set_bit() loop dereferences higher indices without further protection. Theoretically, a guest can trigger speculative access to up to BITS_PER_LONG elements off the end of the phys_map[] array. (In practice it would probably need aggressive loop unrolling by the compiler to go more than one element off the end, and even that seems unlikely, but the theoretical possibility exists.) Move the array_index_nospec() inside the loop to protect the [map + i] index which is actually being used each time. Fixes: c87bd4dd43a6 ("KVM: x86: use array_index_nospec with indices that come from guest") Fixes: bdf7ffc89922 ("KVM: LAPIC: Fix pv ipis out-of-bounds access") Fixes: 4180bf1b655a ("KVM: X86: Implement "send IPI" hypercall") Signed-off-by: Anel Orazgaliyeva Signed-off-by: David Woodhouse Reviewed-by: Jim Mattson Link: https://patch.msgid.link/9d50fc3ca9e8e58f551d015f95d51a3c29ce6ccc.camel@infradead.org Signed-off-by: Sean Christopherson --- diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index 02f2039d5f99d..e3ec4d8607c19 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c @@ -840,16 +840,16 @@ static int __pv_send_ipi(unsigned long *ipi_bitmap, struct kvm_apic_map *map, { int i, count = 0; struct kvm_vcpu *vcpu; + size_t map_index; if (min > map->max_apic_id) return 0; - min = array_index_nospec(min, map->max_apic_id + 1); - for_each_set_bit(i, ipi_bitmap, - min((u32)BITS_PER_LONG, (map->max_apic_id - min + 1))) { - if (map->phys_map[min + i]) { - vcpu = map->phys_map[min + i]->vcpu; + min((u32)BITS_PER_LONG, (map->max_apic_id - min + 1))) { + map_index = array_index_nospec(min + i, map->max_apic_id + 1); + if (map->phys_map[map_index]) { + vcpu = map->phys_map[map_index]->vcpu; count += kvm_apic_set_irq(vcpu, irq, NULL); } }