mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 14:42:24 +00:00
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>
This commit is contained in:
parent
99e5e886a0
commit
2cccbb368a
@ -117,17 +117,17 @@ static void vgic_irq_release(struct kref *ref)
|
|||||||
|
|
||||||
void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq)
|
void vgic_put_irq(struct kvm *kvm, struct vgic_irq *irq)
|
||||||
{
|
{
|
||||||
struct vgic_dist *dist;
|
struct vgic_dist *dist = &kvm->arch.vgic;
|
||||||
|
|
||||||
if (irq->intid < VGIC_MIN_LPI)
|
if (irq->intid < VGIC_MIN_LPI)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!kref_put(&irq->refcount, vgic_irq_release))
|
|
||||||
return;
|
|
||||||
|
|
||||||
dist = &kvm->arch.vgic;
|
|
||||||
|
|
||||||
spin_lock(&dist->lpi_list_lock);
|
spin_lock(&dist->lpi_list_lock);
|
||||||
|
if (!kref_put(&irq->refcount, vgic_irq_release)) {
|
||||||
|
spin_unlock(&dist->lpi_list_lock);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
list_del(&irq->lpi_list);
|
list_del(&irq->lpi_list);
|
||||||
dist->lpi_list_count--;
|
dist->lpi_list_count--;
|
||||||
spin_unlock(&dist->lpi_list_lock);
|
spin_unlock(&dist->lpi_list_lock);
|
||||||
|
Loading…
Reference in New Issue
Block a user