Commit 802bf931f2688ad125b73db597ce63cc842fb27a
Committed by
Ingo Molnar
1 parent
651f8118cf
Exists in
master
and in
4 other branches
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
include/linux/irq.h
... | ... | @@ -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; |
kernel/irq/handle.c
... | ... | @@ -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 |