Commit 802bf931f2688ad125b73db597ce63cc842fb27a

Authored by Mike Travis
Committed by Ingo Molnar
1 parent 651f8118cf

cpumask: fix bug in use cpumask_var_t in irq_desc

Impact: fix bug where new irq_desc uses old cpumask pointers which are freed.

As Yinghai pointed out, init_copy_one_irq_desc() copies the old desc to
the new desc overwriting the cpumask pointers.  Since the old_desc and
the cpumask pointers are freed, then memory corruption will occur if
these old pointers are used.

Move the allocation of these pointers to after the copy.

Signed-off-by: Mike Travis <travis@sgi.com>
Cc: Yinghai Lu <yinghai@kernel.org>

Showing 3 changed files with 16 additions and 14 deletions Side-by-side Diff

... ... @@ -426,15 +426,18 @@
426 426 /**
427 427 * init_alloc_desc_masks - allocate cpumasks for irq_desc
428 428 * @desc: pointer to irq_desc struct
  429 + * @cpu: cpu which will be handling the cpumasks
429 430 * @boot: true if need bootmem
430 431 *
431 432 * Allocates affinity and pending_mask cpumask if required.
432 433 * Returns true if successful (or not required).
433 434 * Side effect: affinity has all bits set, pending_mask has all bits clear.
434 435 */
435   -static inline bool init_alloc_desc_masks(struct irq_desc *desc, int node,
  436 +static inline bool init_alloc_desc_masks(struct irq_desc *desc, int cpu,
436 437 bool boot)
437 438 {
  439 + int node;
  440 +
438 441 if (boot) {
439 442 alloc_bootmem_cpumask_var(&desc->affinity);
440 443 cpumask_setall(desc->affinity);
... ... @@ -446,6 +449,8 @@
446 449 return true;
447 450 }
448 451  
  452 + node = cpu_to_node(cpu);
  453 +
449 454 if (!alloc_cpumask_var_node(&desc->affinity, GFP_ATOMIC, node))
450 455 return false;
451 456 cpumask_setall(desc->affinity);
... ... @@ -484,7 +489,7 @@
484 489  
485 490 #else /* !CONFIG_SMP */
486 491  
487   -static inline bool init_alloc_desc_masks(struct irq_desc *desc, int node,
  492 +static inline bool init_alloc_desc_masks(struct irq_desc *desc, int cpu,
488 493 bool boot)
489 494 {
490 495 return true;
... ... @@ -85,8 +85,6 @@
85 85  
86 86 static void init_one_irq_desc(int irq, struct irq_desc *desc, int cpu)
87 87 {
88   - int node = cpu_to_node(cpu);
89   -
90 88 memcpy(desc, &irq_desc_init, sizeof(struct irq_desc));
91 89  
92 90 spin_lock_init(&desc->lock);
... ... @@ -100,7 +98,7 @@
100 98 printk(KERN_ERR "can not alloc kstat_irqs\n");
101 99 BUG_ON(1);
102 100 }
103   - if (!init_alloc_desc_masks(desc, node, false)) {
  101 + if (!init_alloc_desc_masks(desc, cpu, false)) {
104 102 printk(KERN_ERR "can not alloc irq_desc cpumasks\n");
105 103 BUG_ON(1);
106 104 }
... ... @@ -186,10 +184,6 @@
186 184 irq, cpu, node);
187 185 if (!desc) {
188 186 printk(KERN_ERR "can not alloc irq_desc\n");
189   - BUG_ON(1);
190   - }
191   - if (!init_alloc_desc_masks(desc, node, false)) {
192   - printk(KERN_ERR "can not alloc irq_desc cpumasks\n");
193 187 BUG_ON(1);
194 188 }
195 189 init_one_irq_desc(irq, desc, cpu);
kernel/irq/numa_migrate.c
... ... @@ -38,16 +38,22 @@
38 38 old_desc->kstat_irqs = NULL;
39 39 }
40 40  
41   -static void init_copy_one_irq_desc(int irq, struct irq_desc *old_desc,
  41 +static bool init_copy_one_irq_desc(int irq, struct irq_desc *old_desc,
42 42 struct irq_desc *desc, int cpu)
43 43 {
44 44 memcpy(desc, old_desc, sizeof(struct irq_desc));
  45 + if (!init_alloc_desc_masks(desc, cpu, false)) {
  46 + printk(KERN_ERR "irq %d: can not get new irq_desc cpumask "
  47 + "for migration.\n", irq);
  48 + return false;
  49 + }
45 50 spin_lock_init(&desc->lock);
46 51 desc->cpu = cpu;
47 52 lockdep_set_class(&desc->lock, &irq_desc_lock_class);
48 53 init_copy_kstat_irqs(old_desc, desc, cpu, nr_cpu_ids);
49 54 init_copy_desc_masks(old_desc, desc);
50 55 arch_init_copy_chip_data(old_desc, desc, cpu);
  56 + return true;
51 57 }
52 58  
53 59 static void free_one_irq_desc(struct irq_desc *old_desc, struct irq_desc *desc)
54 60  
... ... @@ -83,15 +89,12 @@
83 89 desc = old_desc;
84 90 goto out_unlock;
85 91 }
86   - if (!init_alloc_desc_masks(desc, node, false)) {
87   - printk(KERN_ERR "irq %d: can not get new irq_desc cpumask "
88   - "for migration.\n", irq);
  92 + if (!init_copy_one_irq_desc(irq, old_desc, desc, cpu)) {
89 93 /* still use old one */
90 94 kfree(desc);
91 95 desc = old_desc;
92 96 goto out_unlock;
93 97 }
94   - init_copy_one_irq_desc(irq, old_desc, desc, cpu);
95 98  
96 99 irq_desc_ptrs[irq] = desc;
97 100