[PATCH] KVM: arm64: vgic-its: Update GITS_CTLR.Enabled under its_lock

Fuad Tabba fuad.tabba at linux.dev
Thu Sep 17 09:20:20 PDT 2026


vgic_mmio_write_its_ctlr() clears its->enabled and invalidates the
translation cache under cmd_lock, but vgic_its_resolve_lpi() tests the
bit and populates the cache under its_lock. An injection that passed
the test before the disable can cache its translation after the
invalidation, and the cached path then injects from a disabled ITS.

Commit 13031fb6b835 ("KVM: arm64: vgic-its: Drop the translation cache
reference only for the erased entry") made the concurrent invalidations
safe but left this window open. The linked v2 closed it, and Oliver
withdrew his own diff there over a kvm->lock/vcpu->mutex inversion in
its vgic_its_invalidate_all_caches() hunk.

Take its_lock around the store and the invalidation, nested under
cmd_lock as the command handlers do. This is the v2's GITS_CTLR half,
widened to cover the store, and it has no such inversion.

Fixes: 8201d1028caa ("KVM: arm64: vgic-its: Maintain a translation cache per ITS")
Reported-by: Hyunwoo Kim <imv4bel at gmail.com>
Link: https://lore.kernel.org/ah6Lsi4MfKUU6wBR@v4bel/
Cc: stable at vger.kernel.org
Signed-off-by: Fuad Tabba <fuad.tabba at linux.dev>
---

Notes:
    Based on v7.3-rc3, applies cleanly to kvmarm/fixes.
    
    Picking up the fix Marc was worried had stalled [1]. Unlike the v2's
    GITS_CTLR hunk [2], the its->enabled store is inside the locked section
    too, so the enable test in vgic_its_resolve_lpi() is serialized by the
    lock rather than by store order.
    
    vgic_its_invalidate_all_caches(), the GICR_CTLR.EnableLPIs path, is
    left as is: it can take neither kvm->lock (it runs with vcpu->mutex
    held) nor config_lock (the userspace GICR_CTLR route already holds it).
    It belongs to the locking cleanup Oliver deferred as a long-term fix
    when he withdrew the v2 [3].
    
    [1] https://lore.kernel.org/861pbr6emw.wl-maz@kernel.org/
    [2] https://lore.kernel.org/ah6Lsi4MfKUU6wBR@v4bel/
    [3] https://lore.kernel.org/ah9KeH8bFl8NOveO@kernel.org/

 arch/arm64/kvm/vgic/vgic-its.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/arm64/kvm/vgic/vgic-its.c b/arch/arm64/kvm/vgic/vgic-its.c
index 9e782a4fea7e5..70b4acf1bf81d 100644
--- a/arch/arm64/kvm/vgic/vgic-its.c
+++ b/arch/arm64/kvm/vgic/vgic-its.c
@@ -1738,9 +1738,15 @@ static void vgic_mmio_write_its_ctlr(struct kvm *kvm, struct vgic_its *its,
 		 !(its->cbaser & GITS_CBASER_VALID)))
 		goto out;
 
+	/*
+	 * vgic_its_resolve_lpi() tests the enable bit and populates the
+	 * translation cache under its_lock.
+	 */
+	mutex_lock(&its->its_lock);
 	its->enabled = !!(val & GITS_CTLR_ENABLE);
 	if (!its->enabled)
 		vgic_its_invalidate_cache(its);
+	mutex_unlock(&its->its_lock);
 
 	/*
 	 * Try to process any pending commands. This function bails out early

base-commit: fd73f4a6659897191fa0d40695fe370925dd3780
-- 
2.39.5




More information about the linux-arm-kernel mailing list