[PATCH] perf machine: Fix NULL deref in machine__is_lock_function()
From: Gu Bin
Date: Thu Nov 05 2026 - 01:50:30 EST
machine__is_lock_function() looks up __sched_text_start and, if found,
assumes the remaining scheduler/lock text symbols are present too: it
dereferences sym->start for __sched_text_end, __lock_text_start and
__lock_text_end without a NULL check, under a "should not fail from
here" comment.
That assumption has already been broken in practice: on s390,
__sched_text_end shared its address with __cpuidle_text_start and
was dropped by symbols__fixup_duplicate(), causing a SIGSEGV in
"perf lock contention".
commit d8d85ce86dc8 ("perf lock contention: Fix core dump related to
not finding the "__sched_text_end" symbol on s/390") worked around
that particular case by keeping duplicate symbols via
symbol_conf.allow_aliases. The symbols can also be absent when the
kernel image has no lock text, or when the symbol table is otherwise
incomplete.
NULL-check each of the four lookups and share the existing failure
handling through a fail label that records the "failed to get kernel
symbols" state (machine->sched.text_start = 1), so the initialization
is only cached as complete when every lookup succeeded and later calls
bail out early without retrying the symbol lookups.
Fixes: 0d2997f750d1 ("perf lock: Look up callchain for the contended locks")
Signed-off-by: Gu Bin <gubin@xxxxxxxxxxxxxxxxxxxx>
---
tools/perf/util/machine.c | 18 +++++++++++++-----
1 file changed, 13 insertions(+), 5 deletions(-)
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 076d167380f2..5eb5efa4eb90 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -3324,22 +3324,25 @@ bool machine__is_lock_function(struct machine *machine, u64 addr)
struct map *kmap;
struct symbol *sym = machine__find_kernel_symbol_by_name(machine, "__sched_text_start", &kmap);
- if (!sym) {
- /* to avoid retry */
- machine->sched.text_start = 1;
- return false;
- }
+ if (!sym)
+ goto fail;
machine->sched.text_start = map__unmap_ip(kmap, sym->start);
/* should not fail from here */
sym = machine__find_kernel_symbol_by_name(machine, "__sched_text_end", &kmap);
+ if (!sym)
+ goto fail;
machine->sched.text_end = map__unmap_ip(kmap, sym->start);
sym = machine__find_kernel_symbol_by_name(machine, "__lock_text_start", &kmap);
+ if (!sym)
+ goto fail;
machine->lock.text_start = map__unmap_ip(kmap, sym->start);
sym = machine__find_kernel_symbol_by_name(machine, "__lock_text_end", &kmap);
+ if (!sym)
+ goto fail;
machine->lock.text_end = map__unmap_ip(kmap, sym->start);
sym = machine__find_kernel_symbol_by_name(machine, "__traceiter_contention_begin", &kmap);
@@ -3380,6 +3383,11 @@ bool machine__is_lock_function(struct machine *machine, u64 addr)
}
return false;
+
+fail:
+ /* failed to get kernel symbols, to avoid retry */
+ machine->sched.text_start = 1;
+ return false;
}
int machine__hit_all_dsos(struct machine *machine)
--
2.55.0.windows.3