Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2cccbb36 authored by Christoffer Dall's avatar Christoffer Dall
Browse files

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: default avatarAndre Przywara <andre.przywara@arm.com>
Signed-off-by: default avatarChristoffer Dall <christoffer.dall@linaro.org>
parent 99e5e886
Loading
Loading
Loading
Loading
+5 −5
Original line number Original line Diff line number Diff line
@@ -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))
	spin_lock(&dist->lpi_list_lock);
	if (!kref_put(&irq->refcount, vgic_irq_release)) {
		spin_unlock(&dist->lpi_list_lock);
		return;
		return;
	};


	dist = &kvm->arch.vgic;

	spin_lock(&dist->lpi_list_lock);
	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);