]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
perf header: Sanity check HEADER_CPU_TOPOLOGY
authorArnaldo Carvalho de Melo <acme@redhat.com>
Fri, 10 Apr 2026 22:08:56 +0000 (19:08 -0300)
committerNamhyung Kim <namhyung@kernel.org>
Tue, 14 Apr 2026 06:21:53 +0000 (23:21 -0700)
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>
tools/perf/util/header.c

index 4cb748763c8a0741a5d64cf6d5ac8c04f125c2b9..acd6b07528e013a46ab959b303a08f9258d87398 100644 (file)
@@ -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);