[tip:irq/urgent] genirq: Prevent access beyond allocated_irqs bitmap

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Commit-ID:  d1a084e2323a39365f450c5061ddd62dfea960d5
Gitweb:     http://git.kernel.org/tip/d1a084e2323a39365f450c5061ddd62dfea960d5
Author:     Thomas Gleixner <tglx@xxxxxxxxxxxxx>
AuthorDate: Tue, 15 Feb 2011 23:27:09 +0100
Committer:  Thomas Gleixner <tglx@xxxxxxxxxxxxx>
CommitDate: Wed, 16 Feb 2011 14:15:41 +0100

genirq: Prevent access beyond allocated_irqs bitmap

Lars-Peter Clausen pointed out:

   I stumbled upon this while looking through the existing archs using
   SPARSE_IRQ.  Even with SPARSE_IRQ the NR_IRQS is still the upper
   limit for the number of IRQs.
 
   Both PXA and MMP set NR_IRQS to IRQ_BOARD_START, with
   IRQ_BOARD_START being the number of IRQs used by the core.

   In various machine files the nr_irqs field of the ARM machine
   defintion struct is then set to "IRQ_BOARD_START + NR_BOARD_IRQS".

   As a result "nr_irqs" will greater then NR_IRQS which then again
   causes the "allocated_irqs" bitmap in the core irq code to be
   accessed beyond its size overwriting unrelated data.
 
The core code really misses a sanity check there.

This went unnoticed so far as by chance the compiler/linker places
data behind that bitmap which gets initialized later on those affected
platforms.

So the obvious fix would be to add a sanity check in early_irq_init()
and break all affected platforms. Though that check wants to be
backported to stable as well, which will require to fix all known
problematic platforms and probably some more yet not known ones as
well. Lots of churn.

The more elegant solution is to dynamically allocate the bitmap
according to the nr of irqs reported by the architecture.

Add a hard upper limit so we wont exceed the kmalloc size. That should
be sufficient for the next few years..

Reported-by: Lars-Peter Clausen <lars@xxxxxxxxxx>
Signed-off-by: Thomas Gleixner <tglx@xxxxxxxxxxxxx>
Cc: stable@xxxxxxxxxx # .37
Cc: Haojian Zhuang <haojian.zhuang@xxxxxxxxxxx>
Cc: Eric Miao <eric.y.miao@xxxxxxxxx>
Cc: Peter Zijlstra <peterz@xxxxxxxxxxxxx>

---
 kernel/irq/irqdesc.c |   11 ++++++++++-
 1 files changed, 10 insertions(+), 1 deletions(-)

diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c
index 282f202..c595827 100644
--- a/kernel/irq/irqdesc.c
+++ b/kernel/irq/irqdesc.c
@@ -94,10 +94,12 @@ int nr_irqs = NR_IRQS;
 EXPORT_SYMBOL_GPL(nr_irqs);
 
 static DEFINE_MUTEX(sparse_irq_lock);
-static DECLARE_BITMAP(allocated_irqs, NR_IRQS);
 
 #ifdef CONFIG_SPARSE_IRQ
 
+#define NR_IRQS_LIMIT		(KMALLOC_MAX_SIZE * 8)
+
+static unsigned long *allocated_irqs;
 static RADIX_TREE(irq_desc_tree, GFP_KERNEL);
 
 static void irq_insert_desc(unsigned int irq, struct irq_desc *desc)
@@ -217,6 +219,11 @@ int __init early_irq_init(void)
 	initcnt = arch_probe_nr_irqs();
 	printk(KERN_INFO "NR_IRQS:%d nr_irqs:%d %d\n", NR_IRQS, nr_irqs, initcnt);
 
+	BUG_ON(nr_irqs > NR_IRQS_LIMIT || initcnt > nr_irqs);
+
+	allocated_irqs = kzalloc(BITS_TO_LONGS(nr_irqs) * sizeof(long), GFP_KERNEL);
+	BUG_ON(!allocated_irqs);
+
 	for (i = 0; i < initcnt; i++) {
 		desc = alloc_desc(i, node);
 		set_bit(i, allocated_irqs);
@@ -227,6 +234,8 @@ int __init early_irq_init(void)
 
 #else /* !CONFIG_SPARSE_IRQ */
 
+static DECLARE_BITMAP(allocated_irqs, NR_IRQS);
+
 struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {
 	[0 ... NR_IRQS-1] = {
 		.status		= IRQ_DEFAULT_INIT_FLAGS,
--
To unsubscribe from this list: send the line "unsubscribe linux-tip-commits" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Stable Commits]     [Linux Stable Kernel]     [Linux Kernel]     [Linux USB Devel]     [Linux Video &Media]     [Linux Audio Users]     [Yosemite News]     [Linux SCSI]

  Powered by Linux