[PATCH 24/28] perf session: Check for decompression buffer size overflow

From: Arnaldo Carvalho de Melo

Date: Sat May 09 2026 - 23:39:21 EST


From: Arnaldo Carvalho de Melo <acme@xxxxxxxxxx>

On 32-bit systems, sizeof(struct decomp) + decomp_len can wrap
size_t when comp_mmap_len is large. The preceding patch caps
comp_mmap_len at ~2 GB, which prevents decomp_len from exceeding
SIZE_MAX after adding decomp_last_rem, but the subsequent addition
of sizeof(struct decomp) could still theoretically overflow on
systems with very small size_t, resulting in a tiny mmap allocation
while zstd receives the original large decomp_len as the
destination size.

Add an explicit overflow check before computing mmap_len as
defense-in-depth.

Reported-by: sashiko-bot@xxxxxxxxxx # Running on a local machine
Cc: Jiri Olsa <jolsa@xxxxxxxxxx>
Cc: Ian Rogers <irogers@xxxxxxxxxx>
Cc: Namhyung Kim <namhyung@xxxxxxxxxx>
Assisted-by: Claude Opus 4.6 (1M context) <noreply@xxxxxxxxxxxxx>
Signed-off-by: Arnaldo Carvalho de Melo <acme@xxxxxxxxxx>
---
tools/perf/util/tool.c | 13 +++++++++++++
1 file changed, 13 insertions(+)

diff --git a/tools/perf/util/tool.c b/tools/perf/util/tool.c
index 96fa6d6c55cdca1e..bb13d526ce4c3382 100644
--- a/tools/perf/util/tool.c
+++ b/tools/perf/util/tool.c
@@ -34,9 +34,22 @@ static int perf_session__process_compressed_event(const struct perf_tool *tool _
if (decomp_last->head > decomp_last->size)
return -1;
decomp_last_rem = decomp_last->size - decomp_last->head;
+ /*
+ * Check before adding: on 32-bit, size_t += u64
+ * silently truncates, bypassing the overflow check
+ * below and producing an undersized buffer.
+ */
+ if (decomp_last_rem > SIZE_MAX - decomp_len - sizeof(struct decomp)) {
+ pr_err("Decompression buffer size overflow\n");
+ return -1;
+ }
decomp_len += decomp_last_rem;
}

+ if (decomp_len > SIZE_MAX - sizeof(struct decomp)) {
+ pr_err("Decompression buffer size overflow\n");
+ return -1;
+ }
mmap_len = sizeof(struct decomp) + decomp_len;
decomp = mmap(NULL, mmap_len, PROT_READ|PROT_WRITE,
MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
--
2.54.0