perf tools: Fix a problem when opening old perf.data with different byte order
Following error occurs when trying to use 'perf report' on x86_64 to cross analysis a perf.data generated by an old perf on a big-endian machine: # perf report *** Error in `/home/w00229757/perf': free(): invalid next size (fast): 0x00000000032c99f0 *** ======= Backtrace: ========= /lib64/libc.so.6(+0x6eeef)[0x7ff6ff7e2eef] /lib64/libc.so.6(+0x78cae)[0x7ff6ff7eccae] /lib64/libc.so.6(+0x79987)[0x7ff6ff7ed987] /path/to/perf[0x4ac734] /path/to/perf[0x4ac829] /path/to/perf(perf_header__process_sections+0x129)[0x4ad2c9] /path/to/perf(perf_session__read_header+0x2e1)[0x4ad9e1] /path/to/perf(perf_session__new+0x168)[0x4bd458] /path/to/perf(cmd_report+0xfa0)[0x43eb70] /path/to/perf[0x47adc3] /path/to/perf(main+0x5f6)[0x42fd06] /lib64/libc.so.6(__libc_start_main+0xf5)[0x7ff6ff795bd5] /path/to/perf[0x42fe35] ======= Memory map: ======== [SNIP] The bug is in perf_event__attr_swap(). It swaps all fields in 'struct perf_event_attr' without checking whether the swapped field exist or not. In addition, in read_event_desc() allocs memory for attr according to size read from perf.data. Therefore, if the perf.data is collected by an old perf (without aux_watermark, for example), when perf_event__attr_swap() swaping attr->aux_watermark it destroy malloc's metadata. This patch introduces boundary checking in perf_event__attr_swap(). It adds macros bswap_field_64 and bswap_field_32 into perf_event__attr_swap() to make it only swap exist fields. Signed-off-by: Wang Nan <wangnan0@huawei.com> Acked-by: Jiri Olsa <jolsa@kernel.org> Cc: Ingo Molnar <mingo@redhat.com> Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Zefan Li <lizefan@huawei.com> Cc: pi3orama@163.com Link: http://lkml.kernel.org/r/1434534999-85347-1-git-send-email-wangnan0@huawei.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
Родитель
386299735e
Коммит
b30b617292
|
@ -517,20 +517,42 @@ void perf_event__attr_swap(struct perf_event_attr *attr)
|
|||
{
|
||||
attr->type = bswap_32(attr->type);
|
||||
attr->size = bswap_32(attr->size);
|
||||
attr->config = bswap_64(attr->config);
|
||||
attr->sample_period = bswap_64(attr->sample_period);
|
||||
attr->sample_type = bswap_64(attr->sample_type);
|
||||
attr->read_format = bswap_64(attr->read_format);
|
||||
attr->wakeup_events = bswap_32(attr->wakeup_events);
|
||||
attr->bp_type = bswap_32(attr->bp_type);
|
||||
attr->bp_addr = bswap_64(attr->bp_addr);
|
||||
attr->bp_len = bswap_64(attr->bp_len);
|
||||
attr->branch_sample_type = bswap_64(attr->branch_sample_type);
|
||||
attr->sample_regs_user = bswap_64(attr->sample_regs_user);
|
||||
attr->sample_stack_user = bswap_32(attr->sample_stack_user);
|
||||
attr->aux_watermark = bswap_32(attr->aux_watermark);
|
||||
|
||||
swap_bitfield((u8 *) (&attr->read_format + 1), sizeof(u64));
|
||||
#define bswap_safe(f, n) \
|
||||
(attr->size > (offsetof(struct perf_event_attr, f) + \
|
||||
sizeof(attr->f) * (n)))
|
||||
#define bswap_field(f, sz) \
|
||||
do { \
|
||||
if (bswap_safe(f, 0)) \
|
||||
attr->f = bswap_##sz(attr->f); \
|
||||
} while(0)
|
||||
#define bswap_field_32(f) bswap_field(f, 32)
|
||||
#define bswap_field_64(f) bswap_field(f, 64)
|
||||
|
||||
bswap_field_64(config);
|
||||
bswap_field_64(sample_period);
|
||||
bswap_field_64(sample_type);
|
||||
bswap_field_64(read_format);
|
||||
bswap_field_32(wakeup_events);
|
||||
bswap_field_32(bp_type);
|
||||
bswap_field_64(bp_addr);
|
||||
bswap_field_64(bp_len);
|
||||
bswap_field_64(branch_sample_type);
|
||||
bswap_field_64(sample_regs_user);
|
||||
bswap_field_32(sample_stack_user);
|
||||
bswap_field_32(aux_watermark);
|
||||
|
||||
/*
|
||||
* After read_format are bitfields. Check read_format because
|
||||
* we are unable to use offsetof on bitfield.
|
||||
*/
|
||||
if (bswap_safe(read_format, 1))
|
||||
swap_bitfield((u8 *) (&attr->read_format + 1),
|
||||
sizeof(u64));
|
||||
#undef bswap_field_64
|
||||
#undef bswap_field_32
|
||||
#undef bswap_field
|
||||
#undef bswap_safe
|
||||
}
|
||||
|
||||
static void perf_event__hdr_attr_swap(union perf_event *event,
|
||||
|
|
Загрузка…
Ссылка в новой задаче