* [PATCH v1] perf machine: Add session back pointer to fix out of bounds read
@ 2026-09-18 6:26 Ian Rogers
0 siblings, 0 replies; only message in thread
From: Ian Rogers @ 2026-09-18 6:26 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo, Namhyung Kim
Cc: Peter Zijlstra, Ingo Molnar, Jiri Olsa, Adrian Hunter,
James Clark, linux-perf-users, linux-kernel, Ian Rogers
thread__e_machine_endian() decides whether a thread is live, and so
whether to read /proc/pid/exe rather than fall back to the perf.data
environment, by recovering the session from the machine:
session = container_of(machine->machines, struct perf_session,
machines);
is_live = !session->data;
That only holds when the struct machines is the one embedded in a struct
perf_session. It is not the only one. aslr_tool keeps its own in struct
aslr_tool, and hists_cumulate, hists_filter, hists_link, hists_output
and thread-maps-share each put one on the stack. For those the
container_of subtracts offsetof(struct perf_session, machines) from an
address that was never inside a session, and the following load of
session->data reads outside the object, which is what ASan reports.
Replace the derivation with an explicit link. machines__init() takes the
owning session, or NULL when the machines is standalone, and
thread__e_machine_endian() reads it back through machines__session().
A NULL session is treated as live. The tests use synthetic pids that
have no /proc entry, so the read fails there and the e_machine falls
back to EM_HOST as before, rather than being decided by whatever the
out of bounds read happened to return. perf inject registers its
session with the aslr tool once the session exists, before any event is
processed, so that tool keeps reporting file based threads as not live.
Fixes: 70351029b556 ("perf thread: Add support for reading the e_machine type for a thread")
Assisted-by: Antigravity:gemini-3.1-pro
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/builtin-inject.c | 3 +++
tools/perf/tests/hists_cumulate.c | 2 +-
tools/perf/tests/hists_filter.c | 2 +-
tools/perf/tests/hists_link.c | 2 +-
tools/perf/tests/hists_output.c | 2 +-
tools/perf/tests/thread-maps-share.c | 3 ++-
tools/perf/util/aslr.c | 10 +++++++++-
tools/perf/util/aslr.h | 2 ++
tools/perf/util/machine.c | 3 ++-
tools/perf/util/machine.h | 10 +++++++++-
tools/perf/util/session.c | 2 +-
tools/perf/util/thread.c | 8 +++-----
12 files changed, 35 insertions(+), 14 deletions(-)
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index 70bbfad5653e..1446e5c0f63e 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -2880,6 +2880,9 @@ int cmd_inject(int argc, const char **argv)
goto out_close_output;
}
+ if (inject.aslr)
+ aslr_tool__register_session(tool, inject.session);
+
if (zstd_init(&(inject.session->zstd_data), 0) < 0)
pr_warning("Decompression initialization failed.\n");
diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c
index 9356451a172e..c4a11a3255bc 100644
--- a/tools/perf/tests/hists_cumulate.c
+++ b/tools/perf/tests/hists_cumulate.c
@@ -723,7 +723,7 @@ static int test__hists_cumulate(struct test_suite *test __maybe_unused, int subt
goto out;
err = TEST_FAIL;
- if (machines__init(&machines))
+ if (machines__init(&machines, /*session=*/NULL))
goto out;
/* setup threads/dso/map/symbols also */
diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c
index f9eaa511487b..6c7e4cdc71a7 100644
--- a/tools/perf/tests/hists_filter.c
+++ b/tools/perf/tests/hists_filter.c
@@ -131,7 +131,7 @@ static int test__hists_filter(struct test_suite *test __maybe_unused, int subtes
goto out;
err = TEST_FAIL;
- if (machines__init(&machines))
+ if (machines__init(&machines, /*session=*/NULL))
goto out;
/* setup threads/dso/map/symbols also */
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c
index d88591bcbe50..cd32c8277627 100644
--- a/tools/perf/tests/hists_link.c
+++ b/tools/perf/tests/hists_link.c
@@ -303,7 +303,7 @@ static int test__hists_link(struct test_suite *test __maybe_unused, int subtest
goto out;
err = TEST_FAIL;
- if (machines__init(&machines))
+ if (machines__init(&machines, /*session=*/NULL))
goto out;
/* setup threads/dso/map/symbols also */
diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c
index f58c8d18fe33..35d230a83e43 100644
--- a/tools/perf/tests/hists_output.c
+++ b/tools/perf/tests/hists_output.c
@@ -610,7 +610,7 @@ static int test__hists_output(struct test_suite *test __maybe_unused, int subtes
goto out;
err = TEST_FAIL;
- if (machines__init(&machines))
+ if (machines__init(&machines, /*session=*/NULL))
goto out;
/* setup threads/dso/map/symbols also */
diff --git a/tools/perf/tests/thread-maps-share.c b/tools/perf/tests/thread-maps-share.c
index 0431bff31b3a..4a0bbf715acb 100644
--- a/tools/perf/tests/thread-maps-share.c
+++ b/tools/perf/tests/thread-maps-share.c
@@ -27,7 +27,8 @@ static int test__thread_maps_share(struct test_suite *test __maybe_unused, int s
* other group (pid: 4, tids: 4, 5)
*/
- TEST_ASSERT_VAL("failed to init machines", machines__init(&machines) == 0);
+ TEST_ASSERT_VAL("failed to init machines",
+ machines__init(&machines, /*session=*/NULL) == 0);
machine = &machines.host;
/* create process with 4 threads */
diff --git a/tools/perf/util/aslr.c b/tools/perf/util/aslr.c
index 027695d96779..76eba1a23bc7 100644
--- a/tools/perf/util/aslr.c
+++ b/tools/perf/util/aslr.c
@@ -1243,7 +1243,7 @@ static int aslr_tool__init(struct aslr_tool *aslr, struct perf_tool *delegate)
delegate_tool__init(&aslr->tool, delegate);
aslr->tool.tool.ordered_events = true;
- if (machines__init(&aslr->machines))
+ if (machines__init(&aslr->machines, /*session=*/NULL))
return -ENOMEM;
hashmap__init(&aslr->remap_addresses,
@@ -1343,6 +1343,14 @@ void aslr_tool__delete(struct perf_tool *tool)
free(aslr);
}
+void aslr_tool__register_session(struct perf_tool *tool, struct perf_session *session)
+{
+ struct delegate_tool *del_tool = container_of(tool, struct delegate_tool, tool);
+ struct aslr_tool *aslr = container_of(del_tool, struct aslr_tool, tool);
+
+ aslr->machines.session = session;
+}
+
int aslr_tool__cache_orig_attrs(struct perf_tool *tool, struct evsel *evsel)
{
struct delegate_tool *del_tool = container_of(tool, struct delegate_tool, tool);
diff --git a/tools/perf/util/aslr.h b/tools/perf/util/aslr.h
index 522e31c8e2c0..9cc14f0263db 100644
--- a/tools/perf/util/aslr.h
+++ b/tools/perf/util/aslr.h
@@ -28,6 +28,7 @@
PERF_SAMPLE_CODE_PAGE_SIZE | \
PERF_SAMPLE_AUX)
+struct perf_session;
struct perf_tool;
struct evsel;
struct evlist;
@@ -36,6 +37,7 @@ union perf_event;
struct perf_tool *aslr_tool__new(struct perf_tool *delegate);
void aslr_tool__delete(struct perf_tool *tool);
+void aslr_tool__register_session(struct perf_tool *tool, struct perf_session *session);
void aslr_tool__strip_attr_event(union perf_event *event, struct evlist *evlist);
int aslr_tool__cache_orig_attrs(struct perf_tool *tool, struct evsel *evsel);
void aslr_tool__strip_evlist(const struct perf_tool *tool, struct evlist *evlist);
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index a1288fbed833..1d9d3bf57720 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -233,10 +233,11 @@ void machine__delete(struct machine *machine)
}
}
-int machines__init(struct machines *machines)
+int machines__init(struct machines *machines, struct perf_session *session)
{
int err = machine__init(&machines->host, "", HOST_KERNEL_ID);
+ machines->session = session;
machines->host.machines = machines;
machines->guests = RB_ROOT_CACHED;
return err;
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index 26f9827062f5..973a59f7c26a 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -15,6 +15,7 @@ struct dso;
struct dso_id;
struct evsel;
struct perf_sample;
+struct perf_session;
struct symbol;
struct target;
struct thread;
@@ -148,13 +149,20 @@ int machine__process_event(struct machine *machine, union perf_event *event,
typedef void (*machine__process_t)(struct machine *machine, void *data);
struct machines {
+ /** @session: back link to owning session if there is one. */
+ struct perf_session *session;
struct machine host;
struct rb_root_cached guests;
};
-int machines__init(struct machines *machines);
+int machines__init(struct machines *machines, struct perf_session *session);
void machines__exit(struct machines *machines);
+static inline struct perf_session *machines__session(struct machines *machines)
+{
+ return machines->session;
+}
+
void machines__process_guests(struct machines *machines,
machine__process_t process, void *data);
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index a5b596cd14be..85ae20ccb489 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -161,7 +161,7 @@ struct perf_session *__perf_session__new(struct perf_data *data,
session->active_decomp = &session->decomp_data;
INIT_LIST_HEAD(&session->auxtrace_index);
perf_env__init(&session->header.env);
- if (machines__init(&session->machines))
+ if (machines__init(&session->machines, session))
goto out_delete;
ordered_events__init(&session->ordered_events,
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index f0d3773d87db..8b8ca94e89ea 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -531,12 +531,10 @@ uint16_t thread__e_machine_endian(struct thread *thread, struct machine *machine
bool is_live = machine->machines == NULL;
if (!is_live) {
- /* Check if the session has a data file. */
- struct perf_session *session = container_of(machine->machines,
- struct perf_session,
- machines);
+ /* Check if the session has a data file (assume no session is a test). */
+ struct perf_session *session = machines__session(machine->machines);
- is_live = !session->data;
+ is_live = !session || !session->data;
}
/* Read from /proc/pid/exe if live. */
if (is_live) {
--
2.55.0.1082.g2b9226bbc0-goog
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2026-09-18 6:26 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-18 6:26 [PATCH v1] perf machine: Add session back pointer to fix out of bounds read Ian Rogers
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®