Skip to contentSkip to conversation

Patch "genirq: Make sparse_irq_lock protect what it should protect" has been added to the 4.9-stable tree

PATCH [email protected] 1 participant 1 message Oct 2, 2017

Subsystems (2)
lore
Share & tools
lore

[email protected]

author maintainer Applied
#0 lore raw

This is a note to let you know that I've just added the patch titled

genirq: Make sparse_irq_lock protect what it should protect

to the 4.9-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
genirq-make-sparse_irq_lock-protect-what-it-should-protect.patch
and it can be found in the queue-4.9 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.

Quoted 1 line

From 12ac1d0f6c3e95732d144ffa65c8b20fbd9aa462 Mon Sep 17 00:00:00 2001

From: Thomas Gleixner <[email protected]>
Date: Tue, 5 Sep 2017 10:12:20 +0200
Subject: genirq: Make sparse_irq_lock protect what it should protect

From: Thomas Gleixner <[email protected]>

commit 12ac1d0f6c3e95732d144ffa65c8b20fbd9aa462 upstream.

for_each_active_irq() iterates the sparse irq allocation bitmap. The caller must hold sparse_irq_lock. Several code pathes expect that an active bit in the sparse bitmap also has a valid interrupt descriptor.

Unfortunately that's not true. The (de)allocation is a two step process, which holds the sparse_irq_lock only across the queue/remove from the radix tree and the set/clear in the allocation bitmap.

If a iteration locks sparse_irq_lock between the two steps, then it might see an active bit but the corresponding irq descriptor is NULL. If that is dereferenced unconditionally, then the kernel oopses. Of course, all iterator sites could be audited and fixed, but....

There is no reason why the sparse_irq_lock needs to be dropped between the two steps, in fact the code becomes simpler when the mutex is held across both and the semantics become more straight forward, so future problems of missing NULL pointer checks in the iteration are avoided and all existing sites are fixed in one go.

Expand the lock held sections so both operations are covered and the bitmap and the radixtree are in sync.

Fixes a05a900a51c7 ("genirq: Make sparse_lock a mutex")
Reported-and-tested-by Huang Ying <[email protected]>
---
 kernel/irq/irqdesc.c |   24 +++++++-----------------
 1 file changed, 7 insertions(+), 17 deletions(-)
kernel/irq/irqdesc.c +7 -17
@@ -405,10 +405,8 @@ static void free_desc(unsigned int irq)
 	 * The sysfs entry must be serialized against a concurrent
 	 * irq_sysfs_init() as well.
 	 */
-	mutex_lock(&sparse_irq_lock);
 	kobject_del(&desc->kobj);
 	delete_irq_desc(irq);
-	mutex_unlock(&sparse_irq_lock);
 
 	/*
 	 * We free the descriptor, masks and stat fields via RCU. That
@@ -446,20 +444,15 @@ static int alloc_descs(unsigned int star
 		desc = alloc_desc(start + i, node, flags, mask, owner);
 		if (!desc)
 			goto err;
-		mutex_lock(&sparse_irq_lock);
 		irq_insert_desc(start + i, desc);
 		irq_sysfs_add(start + i, desc);
-		mutex_unlock(&sparse_irq_lock);
 	}
+	bitmap_set(allocated_irqs, start, cnt);
 	return start;
 
 err:
 	for (i--; i >= 0; i--)
 		free_desc(start + i);
-
-	mutex_lock(&sparse_irq_lock);
-	bitmap_clear(allocated_irqs, start, cnt);
-	mutex_unlock(&sparse_irq_lock);
 	return -ENOMEM;
 }
 
@@ -558,6 +551,7 @@ static inline int alloc_descs(unsigned i
 
 		desc->owner = owner;
 	}
+	bitmap_set(allocated_irqs, start, cnt);
 	return start;
 }
 
@@ -653,10 +647,10 @@ void irq_free_descs(unsigned int from, u
 	if (from >= nr_irqs || (from + cnt) > nr_irqs)
 		return;
 
+	mutex_lock(&sparse_irq_lock);
 	for (i = 0; i < cnt; i++)
 		free_desc(from + i);
 
-	mutex_lock(&sparse_irq_lock);
 	bitmap_clear(allocated_irqs, from, cnt);
 	mutex_unlock(&sparse_irq_lock);
 }
@@ -703,19 +697,15 @@ __irq_alloc_descs(int irq, unsigned int
 					   from, cnt, 0);
 	ret = -EEXIST;
 	if (irq >=0 && start != irq)
-		goto err;
+		goto unlock;
 
 	if (start + cnt > nr_irqs) {
 		ret = irq_expand_nr_irqs(start + cnt);
 		if (ret)
-			goto err;
+			goto unlock;
 	}
-
-	bitmap_set(allocated_irqs, start, cnt);
-	mutex_unlock(&sparse_irq_lock);
-	return alloc_descs(start, cnt, node, affinity, owner);
-
-err:
+	ret = alloc_descs(start, cnt, node, affinity, owner);
+unlock:
 	mutex_unlock(&sparse_irq_lock);
 	return ret;
 }

Patches currently in stable-queue which might be from [email protected] are

queue-4.9/genirq-make-sparse_irq_lock-protect-what-it-should-protect.patch queue-4.9/fs-proc-report-eip-esp-in-prod-pid-stat-for-coredumping.patch