perf session: Check for decompression buffer size overflow

On 32-bit systems, sizeof(struct decomp) + decomp_len can wrap
size_t when comp_mmap_len is large.  The preceding patch validates
comp_mmap_len alignment but does not cap the upper bound, so two
additions can still overflow:

1. decomp_len += decomp_last_rem: on 32-bit, adding a u64 to
   size_t silently truncates, producing a corrupted decomp_len
   that would bypass the subsequent overflow check and result
   in an undersized buffer allocation.

2. sizeof(struct decomp) + decomp_len: the final addition could
   overflow on systems with small size_t.

Add explicit overflow checks before each addition as
defense-in-depth.

Reported-by: sashiko-bot@kernel.org # Running on a local machine
Reviewed-by: Ian Rogers <irogers@google.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Assisted-by: Claude:claude-opus-4.6-1m
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
Arnaldo Carvalho de Melo 2026-05-02 14:51:05 -03:00
parent 6e803f1e01
commit d88e954c82

View File

@ -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);