Skip to content

Commit

Permalink
genirq: Prevent access beyond allocated_irqs bitmap
Browse files Browse the repository at this point in the history
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.

A way simpler solution is to allocate a slightly larger bitmap and
avoid the whole churn w/o breaking anything. Add a few warnings when
an arch returns utter crap.

Reported-by: Lars-Peter Clausen <[email protected]>
Signed-off-by: Thomas Gleixner <[email protected]>
Cc: [email protected] # .37
Cc: Haojian Zhuang <[email protected]>
Cc: Eric Miao <[email protected]>
Cc: Peter Zijlstra <[email protected]>
  • Loading branch information
KAGA-KOKO committed Feb 19, 2011
1 parent 0cc9d52 commit c1ee626
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 2 deletions.
6 changes: 6 additions & 0 deletions kernel/irq/internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@
*/
#include <linux/irqdesc.h>

#ifdef CONFIG_SPARSE_IRQ
# define IRQ_BITMAP_BITS (NR_IRQS + 8196)
#else
# define IRQ_BITMAP_BITS NR_IRQS
#endif

extern int noirqdebug;

#define irq_data_to_desc(data) container_of(data, struct irq_desc, irq_data)
Expand Down
11 changes: 10 additions & 1 deletion kernel/irq/irqdesc.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ int nr_irqs = NR_IRQS;
EXPORT_SYMBOL_GPL(nr_irqs);

static DEFINE_MUTEX(sparse_irq_lock);
static DECLARE_BITMAP(allocated_irqs, NR_IRQS);
static DECLARE_BITMAP(allocated_irqs, IRQ_BITMAP_BITS);

#ifdef CONFIG_SPARSE_IRQ

Expand Down Expand Up @@ -217,6 +217,15 @@ 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);

if (WARN_ON(nr_irqs > IRQ_BITMAP_BITS))
nr_irqs = IRQ_BITMAP_BITS;

if (WARN_ON(initcnt > IRQ_BITMAP_BITS))
initcnt = IRQ_BITMAP_BITS;

if (initcnt > nr_irqs)
nr_irqs = initcnt;

for (i = 0; i < initcnt; i++) {
desc = alloc_desc(i, node);
set_bit(i, allocated_irqs);
Expand Down
2 changes: 1 addition & 1 deletion kernel/irq/resend.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
#ifdef CONFIG_HARDIRQS_SW_RESEND

/* Bitmap to handle software resend of interrupts: */
static DECLARE_BITMAP(irqs_resend, NR_IRQS);
static DECLARE_BITMAP(irqs_resend, IRQ_BITMAP_BITS);

/*
* Run software resends of IRQ's
Expand Down

0 comments on commit c1ee626

Please sign in to comment.