Skip to content

Commit 4364b28

Browse files
committed
KVM: x86: Bail from kvm_recalculate_phys_map() if x2APIC ID is out-of-bounds
Bail from kvm_recalculate_phys_map() and disable the optimized map if the target vCPU's x2APIC ID is out-of-bounds, i.e. if the vCPU was added and/or enabled its local APIC after the map was allocated. This fixes an out-of-bounds access bug in the !x2apic_format path where KVM would write beyond the end of phys_map. Check the x2APIC ID regardless of whether or not x2APIC is enabled, as KVM's hardcodes x2APIC ID to be the vCPU ID, i.e. it can't change, and the map allocation in kvm_recalculate_apic_map() doesn't check for x2APIC being enabled, i.e. the check won't get false postivies. Note, this also affects the x2apic_format path, which previously just ignored the "x2apic_id > new->max_apic_id" case. That too is arguably a bug fix, as ignoring the vCPU meant that KVM would not send interrupts to the vCPU until the next map recalculation. In practice, that "bug" is likely benign as a newly present vCPU/APIC would immediately trigger a recalc. But, there's no functional downside to disabling the map, and a future patch will gracefully handle the -E2BIG case by retrying instead of simply disabling the optimized map. Opportunistically add a sanity check on the xAPIC ID size, along with a comment explaining why the xAPIC ID is guaranteed to be "good". Reported-by: Michal Luczaj <mhal@rbox.co> Fixes: 5b84b02 ("KVM: x86: Honor architectural behavior for aliased 8-bit APIC IDs") Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20230602233250.1014316-2-seanjc@google.com Signed-off-by: Sean Christopherson <seanjc@google.com>
1 parent 8b703a4 commit 4364b28

File tree

1 file changed

+18
-2
lines changed

1 file changed

+18
-2
lines changed

arch/x86/kvm/lapic.c

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,23 @@ static int kvm_recalculate_phys_map(struct kvm_apic_map *new,
228228
u32 xapic_id = kvm_xapic_id(apic);
229229
u32 physical_id;
230230

231+
/*
232+
* For simplicity, KVM always allocates enough space for all possible
233+
* xAPIC IDs. Yell, but don't kill the VM, as KVM can continue on
234+
* without the optimized map.
235+
*/
236+
if (WARN_ON_ONCE(xapic_id > new->max_apic_id))
237+
return -EINVAL;
238+
239+
/*
240+
* Bail if a vCPU was added and/or enabled its APIC between allocating
241+
* the map and doing the actual calculations for the map. Note, KVM
242+
* hardcodes the x2APIC ID to vcpu_id, i.e. there's no TOCTOU bug if
243+
* the compiler decides to reload x2apic_id after this check.
244+
*/
245+
if (x2apic_id > new->max_apic_id)
246+
return -E2BIG;
247+
231248
/*
232249
* Deliberately truncate the vCPU ID when detecting a mismatched APIC
233250
* ID to avoid false positives if the vCPU ID, i.e. x2APIC ID, is a
@@ -253,8 +270,7 @@ static int kvm_recalculate_phys_map(struct kvm_apic_map *new,
253270
*/
254271
if (vcpu->kvm->arch.x2apic_format) {
255272
/* See also kvm_apic_match_physical_addr(). */
256-
if ((apic_x2apic_mode(apic) || x2apic_id > 0xff) &&
257-
x2apic_id <= new->max_apic_id)
273+
if (apic_x2apic_mode(apic) || x2apic_id > 0xff)
258274
new->phys_map[x2apic_id] = apic;
259275

260276
if (!apic_x2apic_mode(apic) && !new->phys_map[xapic_id])

0 commit comments

Comments
 (0)