]>
Commit | Line | Data |
---|---|---|
c9c77b0b GKH |
1 | From fd1d0ddf2ae92fb3df42ed476939861806c5d785 Mon Sep 17 00:00:00 2001 |
2 | From: Andre Przywara <andre.przywara@arm.com> | |
3 | Date: Fri, 10 Apr 2015 16:17:59 +0100 | |
4 | Subject: KVM: arm/arm64: check IRQ number on userland injection | |
5 | ||
6 | From: Andre Przywara <andre.przywara@arm.com> | |
7 | ||
8 | commit fd1d0ddf2ae92fb3df42ed476939861806c5d785 upstream. | |
9 | ||
10 | When userland injects a SPI via the KVM_IRQ_LINE ioctl we currently | |
11 | only check it against a fixed limit, which historically is set | |
12 | to 127. With the new dynamic IRQ allocation the effective limit may | |
13 | actually be smaller (64). | |
14 | So when now a malicious or buggy userland injects a SPI in that | |
15 | range, we spill over on our VGIC bitmaps and bytemaps memory. | |
16 | I could trigger a host kernel NULL pointer dereference with current | |
17 | mainline by injecting some bogus IRQ number from a hacked kvmtool: | |
18 | ----------------- | |
19 | .... | |
20 | DEBUG: kvm_vgic_inject_irq(kvm, cpu=0, irq=114, level=1) | |
21 | DEBUG: vgic_update_irq_pending(kvm, cpu=0, irq=114, level=1) | |
22 | DEBUG: IRQ #114 still in the game, writing to bytemap now... | |
23 | Unable to handle kernel NULL pointer dereference at virtual address 00000000 | |
24 | pgd = ffffffc07652e000 | |
25 | [00000000] *pgd=00000000f658b003, *pud=00000000f658b003, *pmd=0000000000000000 | |
26 | Internal error: Oops: 96000006 [#1] PREEMPT SMP | |
27 | Modules linked in: | |
28 | CPU: 1 PID: 1053 Comm: lkvm-msi-irqinj Not tainted 4.0.0-rc7+ #3027 | |
29 | Hardware name: FVP Base (DT) | |
30 | task: ffffffc0774e9680 ti: ffffffc0765a8000 task.ti: ffffffc0765a8000 | |
31 | PC is at kvm_vgic_inject_irq+0x234/0x310 | |
32 | LR is at kvm_vgic_inject_irq+0x30c/0x310 | |
33 | pc : [<ffffffc0000ae0a8>] lr : [<ffffffc0000ae180>] pstate: 80000145 | |
34 | ..... | |
35 | ||
36 | So this patch fixes this by checking the SPI number against the | |
37 | actual limit. Also we remove the former legacy hard limit of | |
38 | 127 in the ioctl code. | |
39 | ||
40 | Signed-off-by: Andre Przywara <andre.przywara@arm.com> | |
41 | Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org> | |
42 | [maz: wrap KVM_ARM_IRQ_GIC_MAX with #ifndef __KERNEL__, | |
43 | as suggested by Christopher Covington] | |
44 | Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> | |
45 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
46 | ||
47 | --- | |
48 | arch/arm/include/uapi/asm/kvm.h | 8 +++++++- | |
49 | arch/arm/kvm/arm.c | 3 +-- | |
50 | arch/arm64/include/uapi/asm/kvm.h | 8 +++++++- | |
51 | virt/kvm/arm/vgic.c | 3 +++ | |
52 | 4 files changed, 18 insertions(+), 4 deletions(-) | |
53 | ||
54 | --- a/arch/arm/include/uapi/asm/kvm.h | |
55 | +++ b/arch/arm/include/uapi/asm/kvm.h | |
56 | @@ -193,8 +193,14 @@ struct kvm_arch_memory_slot { | |
57 | #define KVM_ARM_IRQ_CPU_IRQ 0 | |
58 | #define KVM_ARM_IRQ_CPU_FIQ 1 | |
59 | ||
60 | -/* Highest supported SPI, from VGIC_NR_IRQS */ | |
61 | +/* | |
62 | + * This used to hold the highest supported SPI, but it is now obsolete | |
63 | + * and only here to provide source code level compatibility with older | |
64 | + * userland. The highest SPI number can be set via KVM_DEV_ARM_VGIC_GRP_NR_IRQS. | |
65 | + */ | |
66 | +#ifndef __KERNEL__ | |
67 | #define KVM_ARM_IRQ_GIC_MAX 127 | |
68 | +#endif | |
69 | ||
70 | /* PSCI interface */ | |
71 | #define KVM_PSCI_FN_BASE 0x95c1ba5e | |
72 | --- a/arch/arm/kvm/arm.c | |
73 | +++ b/arch/arm/kvm/arm.c | |
74 | @@ -644,8 +644,7 @@ int kvm_vm_ioctl_irq_line(struct kvm *kv | |
75 | if (!irqchip_in_kernel(kvm)) | |
76 | return -ENXIO; | |
77 | ||
78 | - if (irq_num < VGIC_NR_PRIVATE_IRQS || | |
79 | - irq_num > KVM_ARM_IRQ_GIC_MAX) | |
80 | + if (irq_num < VGIC_NR_PRIVATE_IRQS) | |
81 | return -EINVAL; | |
82 | ||
83 | return kvm_vgic_inject_irq(kvm, 0, irq_num, level); | |
84 | --- a/arch/arm64/include/uapi/asm/kvm.h | |
85 | +++ b/arch/arm64/include/uapi/asm/kvm.h | |
86 | @@ -179,8 +179,14 @@ struct kvm_arch_memory_slot { | |
87 | #define KVM_ARM_IRQ_CPU_IRQ 0 | |
88 | #define KVM_ARM_IRQ_CPU_FIQ 1 | |
89 | ||
90 | -/* Highest supported SPI, from VGIC_NR_IRQS */ | |
91 | +/* | |
92 | + * This used to hold the highest supported SPI, but it is now obsolete | |
93 | + * and only here to provide source code level compatibility with older | |
94 | + * userland. The highest SPI number can be set via KVM_DEV_ARM_VGIC_GRP_NR_IRQS. | |
95 | + */ | |
96 | +#ifndef __KERNEL__ | |
97 | #define KVM_ARM_IRQ_GIC_MAX 127 | |
98 | +#endif | |
99 | ||
100 | /* PSCI interface */ | |
101 | #define KVM_PSCI_FN_BASE 0x95c1ba5e | |
102 | --- a/virt/kvm/arm/vgic.c | |
103 | +++ b/virt/kvm/arm/vgic.c | |
104 | @@ -1706,6 +1706,9 @@ int kvm_vgic_inject_irq(struct kvm *kvm, | |
105 | goto out; | |
106 | } | |
107 | ||
108 | + if (irq_num >= kvm->arch.vgic.nr_irqs) | |
109 | + return -EINVAL; | |
110 | + | |
111 | vcpu_id = vgic_update_irq_pending(kvm, cpuid, irq_num, level); | |
112 | if (vcpu_id >= 0) { | |
113 | /* kick the specified vcpu */ |