diff options
| author | Tanushree Shah <tshah@linux.ibm.com> | 2026-07-26 00:19:51 +0530 |
|---|---|---|
| committer | Namhyung Kim <namhyung@kernel.org> | 2026-08-07 09:43:36 -0700 |
| commit | 6c07d49ef3beb87436475e8489e45d46e8579001 (patch) | |
| tree | f2b4c0eb69ec96361b5db9f5ff6e24a0811fcbb3 /tools | |
| parent | c108c1391be0826920991d24532fbae8f6373ddc (diff) | |
perf trace-event: Avoid double free and leak in trace_event__cleanup()/trace_event__init()
trace_event__cleanup() frees t->pevent but never clears the
pointer. It can be called twice on the same trace_event: once
from trace_report()'s error path, and again from
perf_session__delete() during session teardown, resulting in a
double free / use-after-free.
Separately, trace_event__init() overwrites t->pevent/t->plugin_list
without releasing any existing handle, leaking memory if it's
called more than once on the same struct. eg. via a perf.data
file with multiple PERF_RECORD_HEADER_TRACING_DATA headers.
Guard against re-entry by returning early if t->pevent is already
NULL, and clear it after cleanup so a repeat call is a safe no-op.
Call trace_event__cleanup() at the start of trace_event__init(),
so a repeated init releases any existing handle before allocating
a new one.
Signed-off-by: Tanushree Shah <tshah@linux.ibm.com>
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/perf/util/trace-event.c | 11 |
1 files changed, 10 insertions, 1 deletions
diff --git a/tools/perf/util/trace-event.c b/tools/perf/util/trace-event.c index 6a8c66c64b70..000c1e1d68c1 100644 --- a/tools/perf/util/trace-event.c +++ b/tools/perf/util/trace-event.c @@ -26,7 +26,11 @@ static bool tevent_initialized; int trace_event__init(struct trace_event *t) { - struct tep_handle *pevent = tep_alloc(); + struct tep_handle *pevent; + + trace_event__cleanup(t); + + pevent = tep_alloc(); if (pevent) { t->plugin_list = tep_load_plugins(pevent); @@ -63,8 +67,13 @@ int trace_event__register_resolver(struct machine *machine, void trace_event__cleanup(struct trace_event *t) { + if (!t->pevent) + return; + tep_unload_plugins(t->plugin_list, t->pevent); tep_free(t->pevent); + t->pevent = NULL; + t->plugin_list = NULL; } /* |
