genirq/generic_chip: Verify irqs_per_chip <= 32
authorSebastian Frias <sf84@laposte.net>
Tue, 16 Aug 2016 14:05:08 +0000 (16:05 +0200)
committerThomas Gleixner <tglx@linutronix.de>
Fri, 2 Sep 2016 18:20:59 +0000 (20:20 +0200)
Most (if not all) code here implicitly assumes that the maximum number of
IRQs per chip will be 32, and thus uses 'u32' or 'unsigned long' for many
tasks (for example "struct irq_data" declares its 'mask' field as 'u32',
and "struct irq_chip_generic" declares its 'installed' field as 'unsigned
long')

However, there is no check to verify that irqs_per_chip is <= 32.  Hence,
calling irq_alloc_domain_generic_chips() with a bigger value will result in
unexpected results.

Provide a wrapper with a MAYBE_BUILD_BUG_ON(nrirqs >= 32) to catch such
cases.

[ tglx: Reduced changelog to the essential information ]

Signed-off-by: Sebastian Frias <sf84@laposte.net>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Mason <slash.tmp@free.fr>
Cc: Jason Cooper <jason@lakedaemon.net>
Link: http://lkml.kernel.org/r/57B31D94.5040701@laposte.net
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
include/linux/irq.h
kernel/irq/generic-chip.c

index b52424e..6039867 100644 (file)
@@ -916,12 +916,20 @@ void irq_remove_generic_chip(struct irq_chip_generic *gc, u32 msk,
                             unsigned int clr, unsigned int set);
 
 struct irq_chip_generic *irq_get_domain_generic_chip(struct irq_domain *d, unsigned int hw_irq);
-int irq_alloc_domain_generic_chips(struct irq_domain *d, int irqs_per_chip,
-                                  int num_ct, const char *name,
-                                  irq_flow_handler_t handler,
-                                  unsigned int clr, unsigned int set,
-                                  enum irq_gc_flags flags);
 
+int __irq_alloc_domain_generic_chips(struct irq_domain *d, int irqs_per_chip,
+                                    int num_ct, const char *name,
+                                    irq_flow_handler_t handler,
+                                    unsigned int clr, unsigned int set,
+                                    enum irq_gc_flags flags);
+
+#define irq_alloc_domain_generic_chips(d, irqs_per_chip, num_ct, name, \
+                                      handler, clr, set, flags)        \
+({                                                                     \
+       MAYBE_BUILD_BUG_ON(irqs_per_chip > 32);                         \
+       __irq_alloc_domain_generic_chips(d, irqs_per_chip, num_ct, name,\
+                                        handler, clr, set, flags);     \
+})
 
 static inline struct irq_chip_type *irq_data_get_chip_type(struct irq_data *d)
 {
index a3a3920..ee32870 100644 (file)
@@ -260,9 +260,9 @@ irq_gc_init_mask_cache(struct irq_chip_generic *gc, enum irq_gc_flags flags)
 }
 
 /**
- * irq_alloc_domain_generic_chip - Allocate generic chips for an irq domain
+ * __irq_alloc_domain_generic_chip - Allocate generic chips for an irq domain
  * @d:                 irq domain for which to allocate chips
- * @irqs_per_chip:     Number of interrupts each chip handles
+ * @irqs_per_chip:     Number of interrupts each chip handles (max 32)
  * @num_ct:            Number of irq_chip_type instances associated with this
  * @name:              Name of the irq chip
  * @handler:           Default flow handler associated with these chips
@@ -270,11 +270,11 @@ irq_gc_init_mask_cache(struct irq_chip_generic *gc, enum irq_gc_flags flags)
  * @set:               IRQ_* bits to set in the mapping function
  * @gcflags:           Generic chip specific setup flags
  */
-int irq_alloc_domain_generic_chips(struct irq_domain *d, int irqs_per_chip,
-                                  int num_ct, const char *name,
-                                  irq_flow_handler_t handler,
-                                  unsigned int clr, unsigned int set,
-                                  enum irq_gc_flags gcflags)
+int __irq_alloc_domain_generic_chips(struct irq_domain *d, int irqs_per_chip,
+                                    int num_ct, const char *name,
+                                    irq_flow_handler_t handler,
+                                    unsigned int clr, unsigned int set,
+                                    enum irq_gc_flags gcflags)
 {
        struct irq_domain_chip_generic *dgc;
        struct irq_chip_generic *gc;
@@ -326,7 +326,7 @@ int irq_alloc_domain_generic_chips(struct irq_domain *d, int irqs_per_chip,
        d->name = name;
        return 0;
 }
-EXPORT_SYMBOL_GPL(irq_alloc_domain_generic_chips);
+EXPORT_SYMBOL_GPL(__irq_alloc_domain_generic_chips);
 
 static struct irq_chip_generic *
 __irq_get_domain_generic_chip(struct irq_domain *d, unsigned int hw_irq)