summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@redhat.com>2026-04-11 01:08:56 +0300
committerNamhyung Kim <namhyung@kernel.org>2026-04-14 09:21:53 +0300
commit22a2e2b29217455cf337c765fc26ad2f55d7291a (patch)
tree83ec51531e86dc5fef1f50d8d10f669b5ee8fa4f
parent376ce5a9f706a75815c8281861b66060438798d1 (diff)
downloadlinux-22a2e2b29217455cf337c765fc26ad2f55d7291a.tar.xz
perf header: Sanity check HEADER_CPU_TOPOLOGY
Add validation to process_cpu_topology() to harden against malformed perf.data files: - Verify nr_cpus_avail was initialized (HEADER_NRCPUS processed first) - Bounds check sibling counts (cores, threads, dies) against nr_cpus_avail - Fix two bare 'return -1' that leaked env->cpu by using 'goto free_cpu' Cc: Jiri Olsa <jolsa@kernel.org> Cc: Ian Rogers <irogers@google.com> Assisted-by: Claude Code:claude-opus-4-6 Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Namhyung Kim <namhyung@kernel.org>
-rw-r--r--tools/perf/util/header.c27
1 files changed, 25 insertions, 2 deletions
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 4cb748763c8a..acd6b07528e0 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -2861,6 +2861,11 @@ static int process_cpu_topology(struct feat_fd *ff, void *data __maybe_unused)
int cpu_nr = env->nr_cpus_avail;
u64 size = 0;
+ if (cpu_nr == 0) {
+ pr_err("Invalid HEADER_CPU_TOPOLOGY: missing HEADER_NRCPUS\n");
+ return -1;
+ }
+
env->cpu = calloc(cpu_nr, sizeof(*env->cpu));
if (!env->cpu)
return -1;
@@ -2868,6 +2873,12 @@ static int process_cpu_topology(struct feat_fd *ff, void *data __maybe_unused)
if (do_read_u32(ff, &nr))
goto free_cpu;
+ if (nr > (u32)cpu_nr) {
+ pr_err("Invalid HEADER_CPU_TOPOLOGY: nr_sibling_cores (%u) > nr_cpus_avail (%d)\n",
+ nr, cpu_nr);
+ goto free_cpu;
+ }
+
env->nr_sibling_cores = nr;
size += sizeof(u32);
if (strbuf_init(&sb, 128) < 0)
@@ -2887,7 +2898,13 @@ static int process_cpu_topology(struct feat_fd *ff, void *data __maybe_unused)
env->sibling_cores = strbuf_detach(&sb, NULL);
if (do_read_u32(ff, &nr))
- return -1;
+ goto free_cpu;
+
+ if (nr > (u32)cpu_nr) {
+ pr_err("Invalid HEADER_CPU_TOPOLOGY: nr_sibling_threads (%u) > nr_cpus_avail (%d)\n",
+ nr, cpu_nr);
+ goto free_cpu;
+ }
env->nr_sibling_threads = nr;
size += sizeof(u32);
@@ -2936,7 +2953,13 @@ static int process_cpu_topology(struct feat_fd *ff, void *data __maybe_unused)
return 0;
if (do_read_u32(ff, &nr))
- return -1;
+ goto free_cpu;
+
+ if (nr > (u32)cpu_nr) {
+ pr_err("Invalid HEADER_CPU_TOPOLOGY: nr_sibling_dies (%u) > nr_cpus_avail (%d)\n",
+ nr, cpu_nr);
+ goto free_cpu;
+ }
env->nr_sibling_dies = nr;
size += sizeof(u32);