Subject: [PATCH 5.4 254/434] perf tools: Splice events onto evlist even on error

From: Greg Kroah-Hartman <[email-masked]>
Date: Sun, 29 Dec 2019 18:25:07 +0100

From: Ian Rogers <[email-masked]>

[ Upstream commit 8e8714c3d157568b7a769917a5e05573bbaf5af0 ]

If event parsing fails the event list is leaked, instead splice the list
onto the out result and let the caller cleanup.

An example input for parse_events found by libFuzzer that reproduces
this memory leak is 'm{'.

Signed-off-by: Ian Rogers <[email-masked]>
Acked-by: Jiri Olsa <[email-masked]>
Cc: Adrian Hunter <[email-masked]>
Cc: Alexander Shishkin <[email-masked]>
Cc: Alexei Starovoitov <[email-masked]>
Cc: Andi Kleen <[email-masked]>
Cc: Daniel Borkmann <[email-masked]>
Cc: Jin Yao <[email-masked]>
Cc: John Garry <[email-masked]>
Cc: Kan Liang <[email-masked]>
Cc: Mark Rutland <[email-masked]>
Cc: Martin KaFai Lau <[email-masked]>
Cc: Namhyung Kim <[email-masked]>
Cc: Peter Zijlstra <[email-masked]>
Cc: Song Liu <[email-masked]>
Cc: Stephane Eranian <[email-masked]>
Cc: Yonghong Song <[email-masked]>
Cc: [email-masked]
Cc: [email-masked]
Cc: [email-masked]
Link: http://lore.kernel.org/lkml/[email-masked]
Signed-off-by: Arnaldo Carvalho de Melo <[email-masked]>
Signed-off-by: Sasha Levin <[email-masked]>
---
 tools/perf/util/parse-events.c | 17 +++++++++++------
 1 file changed, 11 insertions(+), 6 deletions(-)

diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index b5e2adef49de..d5ea043d3fc4 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -1927,15 +1927,20 @@ int parse_events(struct evlist *evlist, const char *str,
 
 	ret = parse_events__scanner(str, &parse_state, PE_START_EVENTS);
 	perf_pmu__parse_cleanup();
+
+	if (!ret && list_empty(&parse_state.list)) {
+		WARN_ONCE(true, "WARNING: event parser found nothing\n");
+		return -1;
+	}
+
+	/*
+	 * Add list to the evlist even with errors to allow callers to clean up.
+	 */
+	perf_evlist__splice_list_tail(evlist, &parse_state.list);
+
 	if (!ret) {
 		struct evsel *last;
 
-		if (list_empty(&parse_state.list)) {
-			WARN_ONCE(true, "WARNING: event parser found nothing\n");
-			return -1;
-		}
-
-		perf_evlist__splice_list_tail(evlist, &parse_state.list);
 		evlist->nr_groups += parse_state.nr_groups;
 		last = evlist__last(evlist);
 		last->cmdline_group_boundary = true;
-- 
2.20.1