diff options
| author | Christoffer Dall <christoffer.dall@linaro.org> | 2016-08-02 16:05:42 -0400 |
|---|---|---|
| committer | Christoffer Dall <christoffer.dall@linaro.org> | 2016-08-10 05:41:54 -0400 |
| commit | 2cccbb368a2bf27d98cf36bb424fbbf5572c0fab (patch) | |
| tree | 83edb3161029df208d04341330a381b8c6e9f5a1 /virt/kvm | |
| parent | 99e5e886a0a59df267ff6838f763b789847df982 (diff) | |
KVM: arm64: vgic-its: Plug race in vgic_put_irq
Right now the following sequence of events can happen:
1. Thread X calls vgic_put_irq
2. Thread Y calls vgic_add_lpi
3. Thread Y gets lpi_list_lock
4. Thread X drops the ref count to 0 and blocks on lpi_list_lock
5. Thread Y finds the irq via the lpi_list_lock, raises the ref
count to 1, and release the lpi_list_lock.
6. Thread X proceeds and frees the irq.
Avoid this by holding the spinlock around the kref_put.
Reviewed-by: Andre Przywara <andre.przywara@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Diffstat (limited to 'virt/kvm')
| -rw-r--r-- | virt/kvm/arm/vgic/vgic.c | 10 |
1 files changed, 5 insertions, 5 deletions
diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c index e7aeac719e09..e83b7fe4baae 100644 --- a/virt/kvm/arm/vgic/vgic.c +++ b/virt/kvm/arm/vgic/vgic.c | |||
| @@ -117,17 +117,17 @@ static void vgic_irq_release(struct kref *ref) | |||
| 117 | 117 | ||
| 118 | void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq) | 118 | void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq) |
| 119 | { | 119 | { |
| 120 | struct vgic_dist *dist; | 120 | struct vgic_dist *dist = &kvm->arch.vgic; |
| 121 | 121 | ||
| 122 | if (irq->intid < VGIC_MIN_LPI) | 122 | if (irq->intid < VGIC_MIN_LPI) |
| 123 | return; | 123 | return; |
| 124 | 124 | ||
| 125 | if (!kref_put(&irq->refcount, vgic_irq_release)) | 125 | spin_lock(&dist->lpi_list_lock); |
| 126 | if (!kref_put(&irq->refcount, vgic_irq_release)) { | ||
| 127 | spin_unlock(&dist->lpi_list_lock); | ||
| 126 | return; | 128 | return; |
| 129 | }; | ||
| 127 | 130 | ||
| 128 | dist = &kvm->arch.vgic; | ||
| 129 | |||
| 130 | spin_lock(&dist->lpi_list_lock); | ||
| 131 | list_del(&irq->lpi_list); | 131 | list_del(&irq->lpi_list); |
| 132 | dist->lpi_list_count--; | 132 | dist->lpi_list_count--; |
| 133 | spin_unlock(&dist->lpi_list_lock); | 133 | spin_unlock(&dist->lpi_list_lock); |
