KVM: arm/arm64: vgic: Fix potential deadlock when ap_list is long [Linux 4.19.70]

This Linux kernel change "KVM: arm/arm64: vgic: Fix potential deadlock when ap_list is long" is included in the Linux 4.19.70 release. This change is authored by Heyi Guo <guoheyi [at] huawei.com> on Tue Aug 27 12:26:50 2019 +0100. The commit for this change in Linux stable tree is ab8ecc2 (patch) which is from upstream commit d4a8061. The same Linux upstream change may have been applied to various maintained Linux releases and you can find all Linux releases containing changes from upstream d4a8061.

KVM: arm/arm64: vgic: Fix potential deadlock when ap_list is long

[ Upstream commit d4a8061a7c5f7c27a2dc002ee4cb89b3e6637e44 ]

If the ap_list is longer than 256 entries, merge_final() in list_sort()
will call the comparison callback with the same element twice, causing
a deadlock in vgic_irq_cmp().

Fix it by returning early when irqa == irqb.

Cc: stable@vger.kernel.org # 4.7+
Fixes: 8e4447457965 ("KVM: arm/arm64: vgic-new: Add IRQ sorting")
Signed-off-by: Zenghui Yu <yuzenghui@huawei.com>
Signed-off-by: Heyi Guo <guoheyi@huawei.com>
[maz: massaged commit log and patch, added Fixes and Cc-stable]
Signed-off-by: Marc Zyngier <maz@kernel.org>
Signed-off-by: Will Deacon <will@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>

There are 7 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 virt/kvm/arm/vgic/vgic.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/virt/kvm/arm/vgic/vgic.c b/virt/kvm/arm/vgic/vgic.c
index 250cd72..4040a33 100644
--- a/virt/kvm/arm/vgic/vgic.c
+++ b/virt/kvm/arm/vgic/vgic.c
@@ -244,6 +244,13 @@ static int vgic_irq_cmp(void *priv, struct list_head *a, struct list_head *b)
    bool penda, pendb;
    int ret;

+   /*
+    * list_sort may call this function with the same element when
+    * the list is fairly long.
+    */
+   if (unlikely(irqa == irqb))
+       return 0;
+
    spin_lock(&irqa->irq_lock);
    spin_lock_nested(&irqb->irq_lock, SINGLE_DEPTH_NESTING);

Leave a Reply

Your email address will not be published. Required fields are marked *