| From 572193552d718ea007cda05e3ad08e506524d191 Mon Sep 17 00:00:00 2001 |
| From: Ravi Bangoria <ravi.bangoria@linux.vnet.ibm.com> |
| Date: Tue, 24 Oct 2017 19:50:06 +0530 |
| Subject: perf symbols: Fix memory corruption because of zero length symbols |
| |
| [ Upstream commit 331c7cb307971eac38e9470340e10c87855bf4bc ] |
| |
| Perf top is often crashing at very random locations on powerpc. After |
| investigating, I found the crash only happens when sample is of zero |
| length symbol. Powerpc kernel has many such symbols which does not |
| contain length details in vmlinux binary and thus start and end |
| addresses of such symbols are same. |
| |
| Structure |
| |
| struct sym_hist { |
| u64 nr_samples; |
| u64 period; |
| struct sym_hist_entry addr[0]; |
| }; |
| |
| has last member 'addr[]' of size zero. 'addr[]' is an array of addresses |
| that belongs to one symbol (function). If function consist of 100 |
| instructions, 'addr' points to an array of 100 'struct sym_hist_entry' |
| elements. For zero length symbol, it points to the *empty* array, i.e. |
| no members in the array and thus offset 0 is also invalid for such |
| array. |
| |
| static int __symbol__inc_addr_samples(...) |
| { |
| ... |
| offset = addr - sym->start; |
| h = annotation__histogram(notes, evidx); |
| h->nr_samples++; |
| h->addr[offset].nr_samples++; |
| h->period += sample->period; |
| h->addr[offset].period += sample->period; |
| ... |
| } |
| |
| Here, when 'addr' is same as 'sym->start', 'offset' becomes 0, which is |
| valid for normal symbols but *invalid* for zero length symbols and thus |
| updating h->addr[offset] causes memory corruption. |
| |
| Fix this by adding one dummy element for zero length symbols. |
| |
| Link: https://lkml.org/lkml/2016/10/10/148 |
| Fixes: edee44be5919 ("perf annotate: Don't throw error for zero length symbols") |
| Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.vnet.ibm.com> |
| Acked-by: Jiri Olsa <jolsa@kernel.org> |
| Acked-by: Namhyung Kim <namhyung@kernel.org> |
| Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> |
| Cc: Jin Yao <yao.jin@linux.intel.com> |
| Cc: Kim Phillips <kim.phillips@arm.com> |
| Cc: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com> |
| Cc: Peter Zijlstra <peterz@infradead.org> |
| Cc: Taeung Song <treeze.taeung@gmail.com> |
| Link: http://lkml.kernel.org/r/1508854806-10542-1-git-send-email-ravi.bangoria@linux.vnet.ibm.com |
| Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| tools/perf/util/annotate.c | 12 +++++++++++- |
| 1 file changed, 11 insertions(+), 1 deletion(-) |
| |
| diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c |
| index a38227eb5450..3336cbc6ec48 100644 |
| --- a/tools/perf/util/annotate.c |
| +++ b/tools/perf/util/annotate.c |
| @@ -495,9 +495,19 @@ static struct ins *ins__find(const char *name) |
| int symbol__alloc_hist(struct symbol *sym) |
| { |
| struct annotation *notes = symbol__annotation(sym); |
| - const size_t size = symbol__size(sym); |
| + size_t size = symbol__size(sym); |
| size_t sizeof_sym_hist; |
| |
| + /* |
| + * Add buffer of one element for zero length symbol. |
| + * When sample is taken from first instruction of |
| + * zero length symbol, perf still resolves it and |
| + * shows symbol name in perf report and allows to |
| + * annotate it. |
| + */ |
| + if (size == 0) |
| + size = 1; |
| + |
| /* Check for overflow when calculating sizeof_sym_hist */ |
| if (size > (SIZE_MAX - sizeof(struct sym_hist)) / sizeof(u64)) |
| return -1; |
| -- |
| 2.17.1 |
| |