Skip to content

Commit fd1d0dd

Browse files
Andre-ARMMarc Zyngier
authored and
Marc Zyngier
committed
KVM: arm/arm64: check IRQ number on userland injection
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 torvalds#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> CC: <stable@vger.kernel.org> # 4.0, 3.19, 3.18 [maz: wrap KVM_ARM_IRQ_GIC_MAX with #ifndef __KERNEL__, as suggested by Christopher Covington] Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
1 parent 0b3289e commit fd1d0dd

File tree

4 files changed

+18
-4
lines changed

4 files changed

+18
-4
lines changed

arch/arm/include/uapi/asm/kvm.h

+7-1
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,14 @@ struct kvm_arch_memory_slot {
195195
#define KVM_ARM_IRQ_CPU_IRQ 0
196196
#define KVM_ARM_IRQ_CPU_FIQ 1
197197

198-
/* Highest supported SPI, from VGIC_NR_IRQS */
198+
/*
199+
* This used to hold the highest supported SPI, but it is now obsolete
200+
* and only here to provide source code level compatibility with older
201+
* userland. The highest SPI number can be set via KVM_DEV_ARM_VGIC_GRP_NR_IRQS.
202+
*/
203+
#ifndef __KERNEL__
199204
#define KVM_ARM_IRQ_GIC_MAX 127
205+
#endif
200206

201207
/* One single KVM irqchip, ie. the VGIC */
202208
#define KVM_NR_IRQCHIPS 1

arch/arm/kvm/arm.c

+1-2
Original file line numberDiff line numberDiff line change
@@ -671,8 +671,7 @@ int kvm_vm_ioctl_irq_line(struct kvm *kvm, struct kvm_irq_level *irq_level,
671671
if (!irqchip_in_kernel(kvm))
672672
return -ENXIO;
673673

674-
if (irq_num < VGIC_NR_PRIVATE_IRQS ||
675-
irq_num > KVM_ARM_IRQ_GIC_MAX)
674+
if (irq_num < VGIC_NR_PRIVATE_IRQS)
676675
return -EINVAL;
677676

678677
return kvm_vgic_inject_irq(kvm, 0, irq_num, level);

arch/arm64/include/uapi/asm/kvm.h

+7-1
Original file line numberDiff line numberDiff line change
@@ -188,8 +188,14 @@ struct kvm_arch_memory_slot {
188188
#define KVM_ARM_IRQ_CPU_IRQ 0
189189
#define KVM_ARM_IRQ_CPU_FIQ 1
190190

191-
/* Highest supported SPI, from VGIC_NR_IRQS */
191+
/*
192+
* This used to hold the highest supported SPI, but it is now obsolete
193+
* and only here to provide source code level compatibility with older
194+
* userland. The highest SPI number can be set via KVM_DEV_ARM_VGIC_GRP_NR_IRQS.
195+
*/
196+
#ifndef __KERNEL__
192197
#define KVM_ARM_IRQ_GIC_MAX 127
198+
#endif
193199

194200
/* One single KVM irqchip, ie. the VGIC */
195201
#define KVM_NR_IRQCHIPS 1

virt/kvm/arm/vgic.c

+3
Original file line numberDiff line numberDiff line change
@@ -1561,6 +1561,9 @@ int kvm_vgic_inject_irq(struct kvm *kvm, int cpuid, unsigned int irq_num,
15611561
goto out;
15621562
}
15631563

1564+
if (irq_num >= kvm->arch.vgic.nr_irqs)
1565+
return -EINVAL;
1566+
15641567
vcpu_id = vgic_update_irq_pending(kvm, cpuid, irq_num, level);
15651568
if (vcpu_id >= 0) {
15661569
/* kick the specified vcpu */

0 commit comments

Comments
 (0)