| From 17d68b763f09a9ce824ae23eb62c9efc57b69271 Mon Sep 17 00:00:00 2001 |
| 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) |
| |
| From: Gleb Natapov <gleb@redhat.com> |
| |
| commit 17d68b763f09a9ce824ae23eb62c9efc57b69271 upstream. |
| |
| 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> |
| Signed-off-by: Gleb Natapov <gleb@redhat.com> |
| Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/x86/kvm/lapic.c | 5 ++++- |
| 1 file changed, 4 insertions(+), 1 deletion(-) |
| |
| --- a/arch/x86/kvm/lapic.c |
| +++ b/arch/x86/kvm/lapic.c |
| @@ -153,6 +153,8 @@ static inline int kvm_apic_id(struct kvm |
| 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; |
| @@ -190,7 +192,8 @@ static void recalculate_apic_map(struct |
| 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) { |