51 lines
2.0 KiB
Diff
51 lines
2.0 KiB
Diff
From: Gleb Natapov <gleb@redhat.com>
|
|
Date: Thu, 12 Dec 2013 21:20:08 +0100
|
|
Subject: KVM: x86: fix guest-initiated crash with x2apic (CVE-2013-6376)
|
|
Origin: https://git.kernel.org/linus/17d68b763f09a9ce824ae23eb62c9efc57b69271
|
|
|
|
A guest can cause a BUG_ON() leading to a host kernel crash.
|
|
When the guest writes to the ICR to request an IPI, while in x2apic
|
|
mode the following things happen, the destination is read from
|
|
ICR2, which is a register that the guest can control.
|
|
|
|
kvm_irq_delivery_to_apic_fast uses the high 16 bits of ICR2 as the
|
|
cluster id. A BUG_ON is triggered, which is a protection against
|
|
accessing map->logical_map with an out-of-bounds access and manages
|
|
to avoid that anything really unsafe occurs.
|
|
|
|
The logic in the code is correct from real HW point of view. The problem
|
|
is that KVM supports only one cluster with ID 0 in clustered mode, but
|
|
the code that has the bug does not take this into account.
|
|
|
|
Reported-by: Lars Bull <larsbull@google.com>
|
|
Cc: stable@vger.kernel.org
|
|
Signed-off-by: Gleb Natapov <gleb@redhat.com>
|
|
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
|
|
---
|
|
arch/x86/kvm/lapic.c | 5 ++++-
|
|
1 file changed, 4 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
|
|
index b8bec45..dec48bf 100644
|
|
--- a/arch/x86/kvm/lapic.c
|
|
+++ b/arch/x86/kvm/lapic.c
|
|
@@ -143,6 +143,8 @@ static inline int kvm_apic_id(struct kvm_lapic *apic)
|
|
return (kvm_apic_get_reg(apic, APIC_ID) >> 24) & 0xff;
|
|
}
|
|
|
|
+#define KVM_X2APIC_CID_BITS 0
|
|
+
|
|
static void recalculate_apic_map(struct kvm *kvm)
|
|
{
|
|
struct kvm_apic_map *new, *old = NULL;
|
|
@@ -180,7 +182,8 @@ static void recalculate_apic_map(struct kvm *kvm)
|
|
if (apic_x2apic_mode(apic)) {
|
|
new->ldr_bits = 32;
|
|
new->cid_shift = 16;
|
|
- new->cid_mask = new->lid_mask = 0xffff;
|
|
+ new->cid_mask = (1 << KVM_X2APIC_CID_BITS) - 1;
|
|
+ new->lid_mask = 0xffff;
|
|
} else if (kvm_apic_sw_enabled(apic) &&
|
|
!new->cid_mask /* flat mode */ &&
|
|
kvm_apic_get_reg(apic, APIC_DFR) == APIC_DFR_CLUSTER) {
|