From: Arnaldo Carvalho de Melo Date: Mon, 8 Jun 2026 00:04:50 +0000 (-0300) Subject: perf symbols: Fix signed overflow in sysfs__read_build_id() size check X-Git-Url: http://git.ipfire.org/index.cgi?a=commitdiff_plain;h=6eaa8ee3e2abe5112e80e94c27196bb175689469;p=thirdparty%2Fkernel%2Flinux.git perf symbols: Fix signed overflow in sysfs__read_build_id() size check sysfs__read_build_id() reads ELF note headers from sysfs files. The note's namesz and descsz fields are used to compute the skip size: int n = namesz + descsz; if (n > (int)sizeof(bf)) Both namesz and descsz are size_t from NOTE_ALIGN() of 32-bit note header fields. Their sum can exceed INT_MAX, overflowing the signed int n to a negative value. The check n > sizeof(bf) then evaluates false (negative < positive in signed comparison), and read(fd, bf, n) reinterprets the negative n as a huge size_t count — the kernel writes up to MAX_RW_COUNT bytes into the 8192-byte stack buffer. In practice the overflow is bounded by the sysfs file's actual size, so a real sysfs notes file won't trigger it organically. But crafted input (e.g. via a mounted debugfs/sysfs image) could. Fix by validating namesz and descsz individually against the buffer size before summing, and change n to size_t to avoid the signed overflow entirely. Fixes: f1617b40596cb341 ("perf symbols: Record the build_ids of kernel modules too") Reported-by: sashiko-bot Cc: Namhyung Kim Assisted-by: Claude:claude-opus-4.6 Signed-off-by: Arnaldo Carvalho de Melo --- diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index c2bdfd0003df2..8fb25a5692b56 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c @@ -964,14 +964,17 @@ int sysfs__read_build_id(const char *filename, struct build_id *bid) } else if (read(fd, bf, descsz) != (ssize_t)descsz) break; } else { - int n = namesz + descsz; + size_t n; - if (n > (int)sizeof(bf)) { + /* int sum of namesz+descsz can overflow negative, bypassing size check */ + if (namesz > sizeof(bf) || descsz > sizeof(bf) - namesz) { n = sizeof(bf); pr_debug("%s: truncating reading of build id in sysfs file %s: n_namesz=%u, n_descsz=%u.\n", __func__, filename, nhdr.n_namesz, nhdr.n_descsz); + } else { + n = namesz + descsz; } - if (read(fd, bf, n) != n) + if (read(fd, bf, n) != (ssize_t)n) break; } }