summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRadim Krcmar <rkrcmar@redhat.com>2019-08-13 23:37:37 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2019-09-06 10:23:36 +0200
commit7d01c081e86142a39ea89588a9cf154816262e52 (patch)
tree7cf4f3b68c119246c5ee36783ff9a0ad66cec084
parente824fe6a6750521ebcf8b71c574e081a09dbdd9d (diff)
downloadlinux-stable-7d01c081e86142a39ea89588a9cf154816262e52.tar.gz
linux-stable-7d01c081e86142a39ea89588a9cf154816262e52.tar.bz2
linux-stable-7d01c081e86142a39ea89588a9cf154816262e52.zip
kvm: x86: skip populating logical dest map if apic is not sw enabled
commit b14c876b994f208b6b95c222056e1deb0a45de0e upstream. recalculate_apic_map does not santize ldr and it's possible that multiple bits are set. In that case, a previous valid entry can potentially be overwritten by an invalid one. This condition is hit when booting a 32 bit, >8 CPU, RHEL6 guest and then triggering a crash to boot a kdump kernel. This is the sequence of events: 1. Linux boots in bigsmp mode and enables PhysFlat, however, it still writes to the LDR which probably will never be used. 2. However, when booting into kdump, the stale LDR values remain as they are not cleared by the guest and there isn't a apic reset. 3. kdump boots with 1 cpu, and uses Logical Destination Mode but the logical map has been overwritten and points to an inactive vcpu. Signed-off-by: Radim Krcmar <rkrcmar@redhat.com> Signed-off-by: Bandan Das <bsd@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--arch/x86/kvm/lapic.c5
1 files changed, 5 insertions, 0 deletions
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 4dabc318adb8..8d22c79f5333 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -212,6 +212,9 @@ static void recalculate_apic_map(struct kvm *kvm)
if (!apic_x2apic_mode(apic) && !new->phys_map[xapic_id])
new->phys_map[xapic_id] = apic;
+ if (!kvm_apic_sw_enabled(apic))
+ continue;
+
ldr = kvm_lapic_get_reg(apic, APIC_LDR);
if (apic_x2apic_mode(apic)) {
@@ -254,6 +257,8 @@ static inline void apic_set_spiv(struct kvm_lapic *apic, u32 val)
static_key_slow_dec_deferred(&apic_sw_disabled);
else
static_key_slow_inc(&apic_sw_disabled.key);
+
+ recalculate_apic_map(apic->vcpu->kvm);
}
}