mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs.git
synced 2026-11-01 23:04:54 +01:00
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 <[email protected]> Acked-by: Jiri Olsa <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: Masami Hiramatsu <[email protected]> Cc: Namhyung Kim <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Zefan Li <[email protected]> Cc: [email protected] Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
This commit is contained in:
1 parent
386299735e
commit
b30b617292
1 file changed
+35
-13
+35
-13
@@ -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,
|
||||
|
||||
Reference in new issue
Block a user