aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndre Przywara <andre.przywara@arm.com>2016-02-03 11:56:51 -0500
committerMarc Zyngier <marc.zyngier@arm.com>2016-02-08 10:23:39 -0500
commitb3aff6ccbb1d25e506b60ccd9c559013903f3464 (patch)
treefca935aa27b4860d1a8bdaa378086260a016b4ba
parent6327f35a2010c06a3bc2bfb14202a38764fb9920 (diff)
KVM: arm/arm64: Fix reference to uninitialised VGIC
Commit 4b4b4512da2a ("arm/arm64: KVM: Rework the arch timer to use level-triggered semantics") brought the virtual architected timer closer to the VGIC. There is one occasion were we don't properly check for the VGIC actually having been initialized before, but instead go on to check the active state of some IRQ number. If userland hasn't instantiated a virtual GIC, we end up with a kernel NULL pointer dereference: ========= Unable to handle kernel NULL pointer dereference at virtual address 00000000 pgd = ffffffc9745c5000 [00000000] *pgd=00000009f631e003, *pud=00000009f631e003, *pmd=0000000000000000 Internal error: Oops: 96000006 [#2] PREEMPT SMP Modules linked in: CPU: 0 PID: 2144 Comm: kvm_simplest-ar Tainted: G D 4.5.0-rc2+ #1300 Hardware name: ARM Juno development board (r1) (DT) task: ffffffc976da8000 ti: ffffffc976e28000 task.ti: ffffffc976e28000 PC is at vgic_bitmap_get_irq_val+0x78/0x90 LR is at kvm_vgic_map_is_active+0xac/0xc8 pc : [<ffffffc0000b7e28>] lr : [<ffffffc0000b972c>] pstate: 20000145 .... ========= Fix this by bailing out early of kvm_timer_flush_hwstate() if we don't have a VGIC at all. Reported-by: Cosmin Gorgovan <cosmin@linux-geek.org> Acked-by: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: Andre Przywara <andre.przywara@arm.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com> Cc: <stable@vger.kernel.org> # 4.4.x
-rw-r--r--virt/kvm/arm/arch_timer.c9
1 files changed, 6 insertions, 3 deletions
diff --git a/virt/kvm/arm/arch_timer.c b/virt/kvm/arm/arch_timer.c
index 69bca185c471..ea6064696fe4 100644
--- a/virt/kvm/arm/arch_timer.c
+++ b/virt/kvm/arm/arch_timer.c
@@ -143,7 +143,7 @@ static void kvm_timer_update_irq(struct kvm_vcpu *vcpu, bool new_level)
143 * Check if there was a change in the timer state (should we raise or lower 143 * Check if there was a change in the timer state (should we raise or lower
144 * the line level to the GIC). 144 * the line level to the GIC).
145 */ 145 */
146static void kvm_timer_update_state(struct kvm_vcpu *vcpu) 146static int kvm_timer_update_state(struct kvm_vcpu *vcpu)
147{ 147{
148 struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu; 148 struct arch_timer_cpu *timer = &vcpu->arch.timer_cpu;
149 149
@@ -154,10 +154,12 @@ static void kvm_timer_update_state(struct kvm_vcpu *vcpu)
154 * until we call this function from kvm_timer_flush_hwstate. 154 * until we call this function from kvm_timer_flush_hwstate.
155 */ 155 */
156 if (!vgic_initialized(vcpu->kvm)) 156 if (!vgic_initialized(vcpu->kvm))
157 return; 157 return -ENODEV;
158 158
159 if (kvm_timer_should_fire(vcpu) != timer->irq.level) 159 if (kvm_timer_should_fire(vcpu) != timer->irq.level)
160 kvm_timer_update_irq(vcpu, !timer->irq.level); 160 kvm_timer_update_irq(vcpu, !timer->irq.level);
161
162 return 0;
161} 163}
162 164
163/* 165/*
@@ -218,7 +220,8 @@ void kvm_timer_flush_hwstate(struct kvm_vcpu *vcpu)
218 bool phys_active; 220 bool phys_active;
219 int ret; 221 int ret;
220 222
221 kvm_timer_update_state(vcpu); 223 if (kvm_timer_update_state(vcpu))
224 return;
222 225
223 /* 226 /*
224 * If we enter the guest with the virtual input level to the VGIC 227 * If we enter the guest with the virtual input level to the VGIC