| From akpm@linux-foundation.org Fri Jun 1 01:04:29 2007 |
| Message-Id: <200706010746.l517kcLv005486@shell0.pdx.osdl.net> |
| Subject: x86: fix oprofile double free |
| To: torvalds@linux-foundation.org |
| Cc: akpm@linux-foundation.org, chrisw@sous-sol.org, acme@redhat.com, ak@suse.de, alan@lxorguk.ukuu.org.uk, cebbert@redhat.com, davej@redhat.com |
| From: akpm@linux-foundation.org |
| Date: Fri, 01 Jun 2007 00:46:39 -0700 |
| |
| From: Chris Wright <chrisw@sous-sol.org> |
| |
| Chuck reports that the recent fix from Andi to oprofile |
| 6c977aad03a18019015035958c65b6729cd0574c introduces a double free. Each |
| cpu's cpu_msrs is setup to point to cpu 0's, which causes free_msrs to free |
| cpu 0's pointers for_each_possible_cpu. Rather than copy the pointers, do |
| a deep copy instead. |
| |
| [acme@redhat.com: allocate_msrs() was using for_each_online_cpu()] |
| Signed-off-by: Chris Wright <chrisw@sous-sol.org> |
| Cc: Andi Kleen <ak@suse.de> |
| Cc: Alan Cox <alan@lxorguk.ukuu.org.uk> |
| Cc: Dave Jones <davej@redhat.com> |
| Cc: Chuck Ebbert <cebbert@redhat.com> |
| Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> |
| Signed-off-by: Andrew Morton <akpm@linux-foundation.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| --- |
| |
| arch/i386/oprofile/nmi_int.c | 12 +++++++++--- |
| 1 file changed, 9 insertions(+), 3 deletions(-) |
| |
| --- linux-2.6.21.4.orig/arch/i386/oprofile/nmi_int.c |
| +++ linux-2.6.21.4/arch/i386/oprofile/nmi_int.c |
| @@ -154,7 +154,7 @@ static int allocate_msrs(void) |
| size_t counters_size = sizeof(struct op_msr) * model->num_counters; |
| |
| int i; |
| - for_each_online_cpu(i) { |
| + for_each_possible_cpu(i) { |
| cpu_msrs[i].counters = kmalloc(counters_size, GFP_KERNEL); |
| if (!cpu_msrs[i].counters) { |
| success = 0; |
| @@ -211,8 +211,14 @@ static int nmi_setup(void) |
| /* Assume saved/restored counters are the same on all CPUs */ |
| model->fill_in_addresses(&cpu_msrs[0]); |
| for_each_possible_cpu (cpu) { |
| - if (cpu != 0) |
| - cpu_msrs[cpu] = cpu_msrs[0]; |
| + if (cpu != 0) { |
| + memcpy(cpu_msrs[cpu].counters, cpu_msrs[0].counters, |
| + sizeof(struct op_msr) * model->num_counters); |
| + |
| + memcpy(cpu_msrs[cpu].controls, cpu_msrs[0].controls, |
| + sizeof(struct op_msr) * model->num_controls); |
| + } |
| + |
| } |
| on_each_cpu(nmi_save_registers, NULL, 0, 1); |
| on_each_cpu(nmi_cpu_setup, NULL, 0, 1); |