* [PATCH] perf tools: Fix a problem when opening old perf.data with different byte order
@ 2015-06-17 3:40 Wang Nan
2015-06-17 8:46 ` Jiri Olsa
0 siblings, 1 reply; 5+ messages in thread
From: Wang Nan @ 2015-06-17 3:40 UTC (permalink / raw)
To: acme, namhyung, masami.hiramatsu.pt, a.p.zijlstra, mingo, jolsa
Cc: linux-kernel, pi3orama, lizefan
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>
---
tools/perf/util/session.c | 40 ++++++++++++++++++++++++++--------------
1 file changed, 26 insertions(+), 14 deletions(-)
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 88d87bf..d51ba31 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -517,20 +517,32 @@ 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) \
+ (attr->size > offsetof(struct perf_event_attr, f))
+#define bswap_field(f, sz) \
+do { \
+ if (bswap_safe(f)) \
+ 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);
+
+ if (bswap_safe(read_format))
+ swap_bitfield((u8 *) (&attr->read_format + 1),
+ sizeof(u64));
}
static void perf_event__hdr_attr_swap(union perf_event *event,
--
1.8.3.4
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH] perf tools: Fix a problem when opening old perf.data with different byte order
2015-06-17 3:40 [PATCH] perf tools: Fix a problem when opening old perf.data with different byte order Wang Nan
@ 2015-06-17 8:46 ` Jiri Olsa
2015-06-17 9:56 ` [PATCH v2] " Wang Nan
0 siblings, 1 reply; 5+ messages in thread
From: Jiri Olsa @ 2015-06-17 8:46 UTC (permalink / raw)
To: Wang Nan
Cc: acme, namhyung, masami.hiramatsu.pt, a.p.zijlstra, mingo, jolsa,
linux-kernel, pi3orama, lizefan
On Wed, Jun 17, 2015 at 03:40:42AM +0000, Wang Nan wrote:
> 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:
>
SNIP
> - 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) \
> + (attr->size > offsetof(struct perf_event_attr, f))
> +#define bswap_field(f, sz) \
> +do { \
> + if (bswap_safe(f)) \
> + 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)
all macros are function specific, please undef them
at the bottom
> +
> + 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);
> +
> + if (bswap_safe(read_format))
should this check for 'read_format + 1' ?
jirka
> + swap_bitfield((u8 *) (&attr->read_format + 1),
> + sizeof(u64));
> }
>
> static void perf_event__hdr_attr_swap(union perf_event *event,
> --
> 1.8.3.4
>
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v2] perf tools: Fix a problem when opening old perf.data with different byte order
2015-06-17 8:46 ` Jiri Olsa
@ 2015-06-17 9:56 ` Wang Nan
2015-06-17 18:24 ` Jiri Olsa
2015-06-18 8:16 ` [tip:perf/core] " tip-bot for Wang Nan
0 siblings, 2 replies; 5+ messages in thread
From: Wang Nan @ 2015-06-17 9:56 UTC (permalink / raw)
To: acme, namhyung, masami.hiramatsu.pt, a.p.zijlstra, mingo, jolsa
Cc: linux-kernel, pi3orama, lizefan
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>
---
Patch v2:
- Undefine macros inside perf_event__attr_swap()
- Check read_format + 1 before swap bitfields after read_format.
---
tools/perf/util/session.c | 50 ++++++++++++++++++++++++++++++++++-------------
1 file changed, 36 insertions(+), 14 deletions(-)
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 88d87bf..425ec5c 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -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,
--
1.8.3.4
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v2] perf tools: Fix a problem when opening old perf.data with different byte order
2015-06-17 9:56 ` [PATCH v2] " Wang Nan
@ 2015-06-17 18:24 ` Jiri Olsa
2015-06-18 8:16 ` [tip:perf/core] " tip-bot for Wang Nan
1 sibling, 0 replies; 5+ messages in thread
From: Jiri Olsa @ 2015-06-17 18:24 UTC (permalink / raw)
To: Wang Nan
Cc: acme, namhyung, masami.hiramatsu.pt, a.p.zijlstra, mingo, jolsa,
linux-kernel, pi3orama, lizefan
On Wed, Jun 17, 2015 at 09:56:39AM +0000, Wang Nan wrote:
> 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>
thanks,
jirka
^ permalink raw reply [flat|nested] 5+ messages in thread
* [tip:perf/core] perf tools: Fix a problem when opening old perf.data with different byte order
2015-06-17 9:56 ` [PATCH v2] " Wang Nan
2015-06-17 18:24 ` Jiri Olsa
@ 2015-06-18 8:16 ` tip-bot for Wang Nan
1 sibling, 0 replies; 5+ messages in thread
From: tip-bot for Wang Nan @ 2015-06-18 8:16 UTC (permalink / raw)
To: linux-tip-commits
Cc: a.p.zijlstra, tglx, acme, wangnan0, masami.hiramatsu.pt, mingo,
mingo, linux-kernel, hpa, jolsa, lizefan, namhyung
Commit-ID: b30b617292462ca7ee68834b117a7833f4a52e16
Gitweb: http://git.kernel.org/tip/b30b617292462ca7ee68834b117a7833f4a52e16
Author: Wang Nan <wangnan0@huawei.com>
AuthorDate: Wed, 17 Jun 2015 09:56:39 +0000
Committer: Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Wed, 17 Jun 2015 16:28:08 -0300
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>
---
tools/perf/util/session.c | 50 ++++++++++++++++++++++++++++++++++-------------
1 file changed, 36 insertions(+), 14 deletions(-)
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index f31e024..e1cd17c 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -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,
^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2015-06-18 8:16 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-06-17 3:40 [PATCH] perf tools: Fix a problem when opening old perf.data with different byte order Wang Nan
2015-06-17 8:46 ` Jiri Olsa
2015-06-17 9:56 ` [PATCH v2] " Wang Nan
2015-06-17 18:24 ` Jiri Olsa
2015-06-18 8:16 ` [tip:perf/core] " tip-bot for Wang Nan
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.