diff options
author | Mike Travis <travis@sgi.com> | 2009-01-11 00:58:09 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-01-11 13:13:02 -0500 |
commit | 802bf931f2688ad125b73db597ce63cc842fb27a (patch) | |
tree | e3715fce62ffeaac7f06f352dc538dccac215216 /kernel/irq | |
parent | 651f8118cf0a5724f23fe1de4a3d9d36b2e01c2e (diff) |
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>
Diffstat (limited to 'kernel/irq')
-rw-r--r-- | kernel/irq/handle.c | 8 | ||||
-rw-r--r-- | kernel/irq/numa_migrate.c | 13 |
2 files changed, 9 insertions, 12 deletions
diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c index b8fa1354f01c..f01c0a30cb42 100644 --- a/kernel/irq/handle.c +++ b/kernel/irq/handle.c | |||
@@ -85,8 +85,6 @@ void init_kstat_irqs(struct irq_desc *desc, int cpu, int nr) | |||
85 | 85 | ||
86 | static void init_one_irq_desc(int irq, struct irq_desc *desc, int cpu) | 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 | memcpy(desc, &irq_desc_init, sizeof(struct irq_desc)); | 88 | memcpy(desc, &irq_desc_init, sizeof(struct irq_desc)); |
91 | 89 | ||
92 | spin_lock_init(&desc->lock); | 90 | spin_lock_init(&desc->lock); |
@@ -100,7 +98,7 @@ static void init_one_irq_desc(int irq, struct irq_desc *desc, int cpu) | |||
100 | printk(KERN_ERR "can not alloc kstat_irqs\n"); | 98 | printk(KERN_ERR "can not alloc kstat_irqs\n"); |
101 | BUG_ON(1); | 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 | printk(KERN_ERR "can not alloc irq_desc cpumasks\n"); | 102 | printk(KERN_ERR "can not alloc irq_desc cpumasks\n"); |
105 | BUG_ON(1); | 103 | BUG_ON(1); |
106 | } | 104 | } |
@@ -188,10 +186,6 @@ struct irq_desc *irq_to_desc_alloc_cpu(unsigned int irq, int cpu) | |||
188 | printk(KERN_ERR "can not alloc irq_desc\n"); | 186 | printk(KERN_ERR "can not alloc irq_desc\n"); |
189 | BUG_ON(1); | 187 | BUG_ON(1); |
190 | } | 188 | } |
191 | if (!init_alloc_desc_masks(desc, node, false)) { | ||
192 | printk(KERN_ERR "can not alloc irq_desc cpumasks\n"); | ||
193 | BUG_ON(1); | ||
194 | } | ||
195 | init_one_irq_desc(irq, desc, cpu); | 189 | init_one_irq_desc(irq, desc, cpu); |
196 | 190 | ||
197 | irq_desc_ptrs[irq] = desc; | 191 | irq_desc_ptrs[irq] = desc; |
diff --git a/kernel/irq/numa_migrate.c b/kernel/irq/numa_migrate.c index f001a4ea6414..666260e4c065 100644 --- a/kernel/irq/numa_migrate.c +++ b/kernel/irq/numa_migrate.c | |||
@@ -38,16 +38,22 @@ static void free_kstat_irqs(struct irq_desc *old_desc, struct irq_desc *desc) | |||
38 | old_desc->kstat_irqs = NULL; | 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 | struct irq_desc *desc, int cpu) | 42 | struct irq_desc *desc, int cpu) |
43 | { | 43 | { |
44 | memcpy(desc, old_desc, sizeof(struct irq_desc)); | 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 | spin_lock_init(&desc->lock); | 50 | spin_lock_init(&desc->lock); |
46 | desc->cpu = cpu; | 51 | desc->cpu = cpu; |
47 | lockdep_set_class(&desc->lock, &irq_desc_lock_class); | 52 | lockdep_set_class(&desc->lock, &irq_desc_lock_class); |
48 | init_copy_kstat_irqs(old_desc, desc, cpu, nr_cpu_ids); | 53 | init_copy_kstat_irqs(old_desc, desc, cpu, nr_cpu_ids); |
49 | init_copy_desc_masks(old_desc, desc); | 54 | init_copy_desc_masks(old_desc, desc); |
50 | arch_init_copy_chip_data(old_desc, desc, cpu); | 55 | arch_init_copy_chip_data(old_desc, desc, cpu); |
56 | return true; | ||
51 | } | 57 | } |
52 | 58 | ||
53 | static void free_one_irq_desc(struct irq_desc *old_desc, struct irq_desc *desc) | 59 | static void free_one_irq_desc(struct irq_desc *old_desc, struct irq_desc *desc) |
@@ -83,15 +89,12 @@ static struct irq_desc *__real_move_irq_desc(struct irq_desc *old_desc, | |||
83 | desc = old_desc; | 89 | desc = old_desc; |
84 | goto out_unlock; | 90 | goto out_unlock; |
85 | } | 91 | } |
86 | if (!init_alloc_desc_masks(desc, node, false)) { | 92 | if (!init_copy_one_irq_desc(irq, old_desc, desc, cpu)) { |
87 | printk(KERN_ERR "irq %d: can not get new irq_desc cpumask " | ||
88 | "for migration.\n", irq); | ||
89 | /* still use old one */ | 93 | /* still use old one */ |
90 | kfree(desc); | 94 | kfree(desc); |
91 | desc = old_desc; | 95 | desc = old_desc; |
92 | goto out_unlock; | 96 | goto out_unlock; |
93 | } | 97 | } |
94 | init_copy_one_irq_desc(irq, old_desc, desc, cpu); | ||
95 | 98 | ||
96 | irq_desc_ptrs[irq] = desc; | 99 | irq_desc_ptrs[irq] = desc; |
97 | 100 | ||