]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
KVM: arm/arm64: check IRQ number on userland injection
authorAndre Przywara <andre.przywara@arm.com>
Fri, 10 Apr 2015 15:17:59 +0000 (16:17 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 6 May 2015 20:01:43 +0000 (22:01 +0200)
commit fd1d0ddf2ae92fb3df42ed476939861806c5d785 upstream.

When userland injects a SPI via the KVM_IRQ_LINE ioctl we currently
only check it against a fixed limit, which historically is set
to 127. With the new dynamic IRQ allocation the effective limit may
actually be smaller (64).
So when now a malicious or buggy userland injects a SPI in that
range, we spill over on our VGIC bitmaps and bytemaps memory.
I could trigger a host kernel NULL pointer dereference with current
mainline by injecting some bogus IRQ number from a hacked kvmtool:
-----------------
....
DEBUG: kvm_vgic_inject_irq(kvm, cpu=0, irq=114, level=1)
DEBUG: vgic_update_irq_pending(kvm, cpu=0, irq=114, level=1)
DEBUG: IRQ #114 still in the game, writing to bytemap now...
Unable to handle kernel NULL pointer dereference at virtual address 00000000
pgd = ffffffc07652e000
[00000000] *pgd=00000000f658b003, *pud=00000000f658b003, *pmd=0000000000000000
Internal error: Oops: 96000006 [#1] PREEMPT SMP
Modules linked in:
CPU: 1 PID: 1053 Comm: lkvm-msi-irqinj Not tainted 4.0.0-rc7+ #3027
Hardware name: FVP Base (DT)
task: ffffffc0774e9680 ti: ffffffc0765a8000 task.ti: ffffffc0765a8000
PC is at kvm_vgic_inject_irq+0x234/0x310
LR is at kvm_vgic_inject_irq+0x30c/0x310
pc : [<ffffffc0000ae0a8>] lr : [<ffffffc0000ae180>] pstate: 80000145
.....

So this patch fixes this by checking the SPI number against the
actual limit. Also we remove the former legacy hard limit of
127 in the ioctl code.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
[maz: wrap KVM_ARM_IRQ_GIC_MAX with #ifndef __KERNEL__,
as suggested by Christopher Covington]
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/arm/include/uapi/asm/kvm.h
arch/arm/kvm/arm.c
arch/arm64/include/uapi/asm/kvm.h
virt/kvm/arm/vgic.c

index 09ee408c1a67621e9c052e53492b61ef308de6f8..b404cf88602934e5764783f23ebd955559c29db4 100644 (file)
@@ -193,8 +193,14 @@ struct kvm_arch_memory_slot {
 #define KVM_ARM_IRQ_CPU_IRQ            0
 #define KVM_ARM_IRQ_CPU_FIQ            1
 
-/* Highest supported SPI, from VGIC_NR_IRQS */
+/*
+ * This used to hold the highest supported SPI, but it is now obsolete
+ * and only here to provide source code level compatibility with older
+ * userland. The highest SPI number can be set via KVM_DEV_ARM_VGIC_GRP_NR_IRQS.
+ */
+#ifndef __KERNEL__
 #define KVM_ARM_IRQ_GIC_MAX            127
+#endif
 
 /* PSCI interface */
 #define KVM_PSCI_FN_BASE               0x95c1ba5e
index 0b0d58a905c43ba05afc61ca06341bfab348b528..3ec96878e1c345d8a6a99cd21a91c7cd1c007ef1 100644 (file)
@@ -644,8 +644,7 @@ int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_level,
                if (!irqchip_in_kernel(kvm))
                        return -ENXIO;
 
-               if (irq_num < VGIC_NR_PRIVATE_IRQS ||
-                   irq_num > KVM_ARM_IRQ_GIC_MAX)
+               if (irq_num < VGIC_NR_PRIVATE_IRQS)
                        return -EINVAL;
 
                return kvm_vgic_inject_irq(kvm, 0, irq_num, level);
index 8e38878c87c61dc9145f8950e5b977ee081886d0..d9e9822efcee2457836495623c9d9f0ffc014465 100644 (file)
@@ -179,8 +179,14 @@ struct kvm_arch_memory_slot {
 #define KVM_ARM_IRQ_CPU_IRQ            0
 #define KVM_ARM_IRQ_CPU_FIQ            1
 
-/* Highest supported SPI, from VGIC_NR_IRQS */
+/*
+ * This used to hold the highest supported SPI, but it is now obsolete
+ * and only here to provide source code level compatibility with older
+ * userland. The highest SPI number can be set via KVM_DEV_ARM_VGIC_GRP_NR_IRQS.
+ */
+#ifndef __KERNEL__
 #define KVM_ARM_IRQ_GIC_MAX            127
+#endif
 
 /* PSCI interface */
 #define KVM_PSCI_FN_BASE               0x95c1ba5e
index 03affc7bf453244300552bb5a448546e9730c08a..b43e891dc5bfc4e54844319ff6a26344a0c55ffa 100644 (file)
@@ -1706,6 +1706,9 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num,
                        goto out;
        }
 
+       if (irq_num >= kvm->arch.vgic.nr_irqs)
+               return -EINVAL;
+
        vcpu_id = vgic_update_irq_pending(kvm, cpuid, irq_num, level);
        if (vcpu_id >= 0) {
                /* kick the specified vcpu */