[PATCH v4 6/9] perf ui hists: Fix dso_filter reference leak and exit cleanup

From: Ian Rogers

Date: Thu Jul 09 2026 - 22:54:15 EST


In hists_browser__zoom_map(), the active dso is assigned as a raw
pointer to hists->dso_filter without acquiring a reference using
dso__get(). This creates a potential use-after-free defect if the
underlying dso is released while the filter remains active.

Fix it by properly acquiring a reference via dso__get() when assigning
the filter, and releasing it with dso__put() when clearing it.
Additionally, ensure that both hists->thread_filter and
hists->dso_filter are safely cleared and dropped upon exiting the
browser in evsel__hists_browse() to prevent leaking active references.

Reported-by: sashiko-bot <sashiko-bot@xxxxxxxxxx>
Closes: https://lore.kernel.org/linux-perf-users/20260709170834.52F1A1F000E9@xxxxxxxxxxxxxxx/
Assisted-by: Antigravity:gemini-3.5-flash
Signed-off-by: Ian Rogers <irogers@xxxxxxxxxx>
---
tools/perf/ui/browsers/hists.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 70f8a820d0a0..316db603bf25 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -2640,13 +2640,14 @@ static int hists_browser__zoom_map(struct hist_browser *browser, struct map *map
if (browser->hists->dso_filter) {
pstack__remove(browser->pstack, &browser->hists->dso_filter);
perf_hpp__set_elide(HISTC_DSO, false);
+ dso__put((struct dso *)browser->hists->dso_filter);
browser->hists->dso_filter = NULL;
ui_helpline__pop();
} else {
struct dso *dso = map__dso(map);
ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s DSO\"",
__map__is_kernel(map) ? "the Kernel" : dso__short_name(dso));
- browser->hists->dso_filter = dso;
+ browser->hists->dso_filter = dso__get(dso);
perf_hpp__set_elide(HISTC_DSO, true);
pstack__push(browser->pstack, &browser->hists->dso_filter);
}
@@ -3450,6 +3451,9 @@ static int evsel__hists_browse(struct evsel *evsel, int nr_events, const char *h
}
out_free_stack:
pstack__delete(browser->pstack);
+ thread__zput(hists->thread_filter);
+ dso__put((struct dso *)hists->dso_filter);
+ hists->dso_filter = NULL;
out:
hist_browser__delete(browser);
free_popup_options(options, MAX_OPTIONS);
--
2.55.0.795.g602f6c329a-goog