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>
This commit is contained in:
Tanushree Shah 2026-07-26 00:19:51 +05:30 committed by Namhyung Kim
parent c108c1391b
commit 6c07d49ef3

View File

@ -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;
}
/*