Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1757059AbbGQH7V (ORCPT ); Fri, 17 Jul 2015 03:59:21 -0400 Received: from szxga01-in.huawei.com ([58.251.152.64]:61463 "EHLO szxga01-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756746AbbGQH7U (ORCPT ); Fri, 17 Jul 2015 03:59:20 -0400 From: Wang Nan To: , CC: , , , , , , , Subject: [PATCH] tools lib traceevent: Fix double free corruption in error processing code Date: Fri, 17 Jul 2015 07:58:46 +0000 Message-ID: <1437119926-17022-1-git-send-email-wangnan0@huawei.com> X-Mailer: git-send-email 1.8.3.4 MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [10.110.52.60] X-CFilter-Loop: Reflected Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 4744 Lines: 139 When kernel introduces new function to 'format' file before traceevent update correspondingly, a double-free corruption occures if the newly intorduced function resides in following format: # cat /sys/kernel/debug/tracing/events/bpf/bpf_output_data/format ... print fmt: "%s", __print_hex(__get_dynamic_array(buf), __get_dynamic_array_len(buf)) ... (where __get_dynamic_array_len is the new function) And: # perf record -e bpf:bpf_output_data ls Warning: [bpf:bpf_output_data] function __get_dynamic_array_len not defined Warning: Error: expected type 5 but read 0 *** Error in `/path/to/perf': double free or corruption (fasttop): 0x0000000001821210 *** ======= Backtrace: ========= /lib64/libc.so.6(+0x6eeef)[0x7f86a4cf6eef] /lib64/libc.so.6(+0x78cae)[0x7f86a4d00cae] /lib64/libc.so.6(+0x79987)[0x7f86a4d01987] /path/to/perf[0x51b0e2] /path/to/perf[0x51afc2] /path/to/perf[0x51fe67] /path/to/perf[0x5200a5] /path/to/perf(__pevent_parse_format+0x185)[0x525bc9] /path/to/perf[0x525d82] /path/to/perf(pevent_parse_format+0x3b)[0x525e15] /path/to/perf[0x4ceb61] /path/to/perf(perf_evsel__newtp_idx+0x9f)[0x48cabf] /path/to/perf(parse_events_add_tracepoint+0x25b)[0x49782b] /path/to/perf(parse_events_parse+0x10a3)[0x4c8243] /path/to/perf(parse_events+0x75)[0x498ce5] /path/to/perf(parse_events_option+0x41)[0x498df1] /path/to/perf[0x493e9b] /path/to/perf(parse_options+0x215)[0x4957c5] /path/to/perf(cmd_record+0x6a)[0x43c4ba] /path/to/perf[0x47b2a3] /path/to/perf(main+0x5f6)[0x42fed6] /lib64/libc.so.6(__libc_start_main+0xf5)[0x7f86a4ca9bd5] /path/to/perf[0x430005] ======= Memory map: ======== 00400000-006b9000 r-xp 00000000 08:05 23596607 /path/to/perf 008b9000-00903000 rw-p 002b9000 08:05 23596607 /path/to/perf This is caused by error processing code in process_hex() which frees arg->hex.field but doesn't set it to NULL. When event_read_print_args() freeing the hex arg, the dangling pointer will be free again and cause the above error. process_int_array() has similar problem. This patch fixes the dangling pointer problem by not setting them until everything is okay. Signed-off-by: Wang Nan Cc: Steven Rostedt Cc: Alexei Starovoitov Cc: Arnaldo Carvalho de Melo Cc: Peter Zijlstra Cc: Ingo Molnar Cc: Namhyung Kim Cc: Jiri Olsa Cc: --- tools/lib/traceevent/event-parse.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/tools/lib/traceevent/event-parse.c b/tools/lib/traceevent/event-parse.c index cc25f05..8d662b5 100644 --- a/tools/lib/traceevent/event-parse.c +++ b/tools/lib/traceevent/event-parse.c @@ -2546,19 +2546,23 @@ out_free: static enum event_type process_hex(struct event_format *event, struct print_arg *arg, char **tok) { + struct print_arg *field, *size; + memset(arg, 0, sizeof(*arg)); arg->type = PRINT_HEX; - if (alloc_and_process_delim(event, ",", &arg->hex.field)) + if (alloc_and_process_delim(event, ",", &field)) goto out; - if (alloc_and_process_delim(event, ")", &arg->hex.size)) + if (alloc_and_process_delim(event, ")", &size)) goto free_field; + arg->hex.field = field; + arg->hex.size = size; return read_token_item(tok); free_field: - free_arg(arg->hex.field); + free_arg(field); out: *tok = NULL; return EVENT_ERROR; @@ -2567,24 +2571,29 @@ out: static enum event_type process_int_array(struct event_format *event, struct print_arg *arg, char **tok) { + struct print_arg *field, *count, *el_size; + memset(arg, 0, sizeof(*arg)); arg->type = PRINT_INT_ARRAY; - if (alloc_and_process_delim(event, ",", &arg->int_array.field)) + if (alloc_and_process_delim(event, ",", &field)) goto out; - if (alloc_and_process_delim(event, ",", &arg->int_array.count)) + if (alloc_and_process_delim(event, ",", &count)) goto free_field; - if (alloc_and_process_delim(event, ")", &arg->int_array.el_size)) + if (alloc_and_process_delim(event, ")", &el_size)) goto free_size; + arg->int_array.field = field; + arg->int_array.count = count; + arg->int_array.el_size = el_size; return read_token_item(tok); free_size: - free_arg(arg->int_array.count); + free_arg(count); free_field: - free_arg(arg->int_array.field); + free_arg(field); out: *tok = NULL; return EVENT_ERROR; -- 1.8.3.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/