From 091283e3d5eb9f424b85e71804fc26092c3c4915 Mon Sep 17 00:00:00 2001 From: Li Huafei Date: Tue, 1 Jun 2021 17:27:50 +0800 Subject: [PATCH] perf probe: Fix NULL pointer dereference in convert_variable_location() [ Upstream commit 3cb17cce1e76ccc5499915a4d7e095a1ad6bf7ff ] If we just check whether the variable can be converted, 'tvar' should be a null pointer. However, the null pointer check is missing in the 'Constant value' execution path. The following cases can trigger this problem: $ cat test.c #include void main(void) { int a; const int b = 1; asm volatile("mov %1, %0" : "=r"(a): "i"(b)); printf("a: %d\n", a); } $ gcc test.c -o test -O -g $ sudo ./perf probe -x ./test -L "main" 0 void main(void) { 2 int a; const int b = 1; asm volatile("mov %1, %0" : "=r"(a): "i"(b)); 6 printf("a: %d\n", a); } $ sudo ./perf probe -x ./test -V "main:6" Segmentation fault The check on 'tvar' is added. If 'tavr' is a null pointer, we return 0 to indicate that the variable can be converted. Now, we can successfully show the variables that can be accessed. $ sudo ./perf probe -x ./test -V "main:6" Available variables at main:6 @ char* __fmt int a int b However, the variable 'b' cannot be tracked. $ sudo ./perf probe -x ./test -D "main:6 b" Failed to find the location of the 'b' variable at this address. Perhaps it has been optimized out. Use -V with the --range option to show 'b' location range. Error: Failed to add events. This is because __die_find_variable_cb() did not successfully match variable 'b', which has the DW_AT_const_value attribute instead of DW_AT_location. We added support for DW_AT_const_value in __die_find_variable_cb(). With this modification, we can successfully track the variable 'b'. $ sudo ./perf probe -x ./test -D "main:6 b" p:probe_test/main_L6 /home/lhf/test:0x1156 b=\1:s32 Fixes: 66f69b219716 ("perf probe: Support DW_AT_const_value constant value") Signed-off-by: Li Huafei Tested-by: Arnaldo Carvalho de Melo Cc: Alexander Shishkin Cc: Frank Ch. Eigler Cc: Jianlin Lv Cc: Jiri Olsa Cc: Mark Rutland Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Srikar Dronamraju Cc: Yang Jihong Cc: Zhang Jinhao http://lore.kernel.org/lkml/20210601092750.169601-1-lihuafei1@huawei.com Signed-off-by: Arnaldo Carvalho de Melo Signed-off-by: Sasha Levin --- tools/perf/util/dwarf-aux.c | 8 ++++++-- tools/perf/util/probe-finder.c | 3 +++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index 7b2d471a6419d..4343356f3cf9a 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c @@ -975,9 +975,13 @@ static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data) if ((tag == DW_TAG_formal_parameter || tag == DW_TAG_variable) && die_compare_name(die_mem, fvp->name) && - /* Does the DIE have location information or external instance? */ + /* + * Does the DIE have location information or const value + * or external instance? + */ (dwarf_attr(die_mem, DW_AT_external, &attr) || - dwarf_attr(die_mem, DW_AT_location, &attr))) + dwarf_attr(die_mem, DW_AT_location, &attr) || + dwarf_attr(die_mem, DW_AT_const_value, &attr))) return DIE_FIND_CB_END; if (dwarf_haspc(die_mem, fvp->addr)) return DIE_FIND_CB_CONTINUE; diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 76dd349aa48d8..fdafbfcef6871 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c @@ -190,6 +190,9 @@ static int convert_variable_location(Dwarf_Die *vr_die, Dwarf_Addr addr, immediate_value_is_supported()) { Dwarf_Sword snum; + if (!tvar) + return 0; + dwarf_formsdata(&attr, &snum); ret = asprintf(&tvar->value, "\\%ld", (long)snum);