]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
perf tools: Guard test_bit from out-of-bounds sample CPU
authorArnaldo Carvalho de Melo <acme@redhat.com>
Thu, 4 Jun 2026 15:55:06 +0000 (12:55 -0300)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Thu, 4 Jun 2026 20:34:52 +0000 (17:34 -0300)
When PERF_SAMPLE_CPU is absent from a perf.data file, sample->cpu is
initialized to (u32)-1 by evsel__parse_sample().  Five call sites pass
this value directly to test_bit(sample->cpu, cpu_bitmap), reading
massively out of bounds past the DECLARE_BITMAP(..., MAX_NR_CPUS)
allocation of 4096 bits.

Add a sample->cpu >= MAX_NR_CPUS guard before each test_bit() call,
matching the existing safe pattern in builtin-kwork.c.  This catches
both the (u32)-1 sentinel and any corrupted CPU value exceeding the
bitmap size.

Fixes: 5d67be97f890 ("perf report/annotate/script: Add option to specify a CPU range")
Cc: Anton Blanchard <anton@samba.org>
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Assisted-by: Claude:claude-opus-4.6
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/builtin-annotate.c
tools/perf/builtin-diff.c
tools/perf/builtin-report.c
tools/perf/builtin-sched.c

index b918f9eed5fd2441fc0988f1d24cc4a75604fa2b..8a0eb30eac24fdbcc8f95c2d90408b611ab69de3 100644 (file)
@@ -295,7 +295,8 @@ static int process_sample_event(const struct perf_tool *tool,
                goto out_put;
        }
 
-       if (ann->cpu_list && !test_bit(sample->cpu, ann->cpu_bitmap))
+       if (ann->cpu_list && (sample->cpu >= MAX_NR_CPUS ||
+                            !test_bit(sample->cpu, ann->cpu_bitmap)))
                goto out_put;
 
        if (!al.filtered &&
index 9592f44b6545bab668ad8a63c2c0ac736dee6195..9fa8e900637b0d71251f2f64d1053194ba110042 100644 (file)
@@ -416,7 +416,8 @@ static int diff__process_sample_event(const struct perf_tool *tool,
                goto out;
        }
 
-       if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) {
+       if (cpu_list && (sample->cpu >= MAX_NR_CPUS ||
+                       !test_bit(sample->cpu, cpu_bitmap))) {
                ret = 0;
                goto out;
        }
index 6f044c3df8937dc564b2704907fdb698381e3bc2..dd1309c320943ea4bd7950418d96467d8e387926 100644 (file)
@@ -298,7 +298,8 @@ static int process_sample_event(const struct perf_tool *tool,
        if (symbol_conf.hide_unresolved && al.sym == NULL)
                goto out_put;
 
-       if (rep->cpu_list && !test_bit(sample->cpu, rep->cpu_bitmap))
+       if (rep->cpu_list && (sample->cpu >= MAX_NR_CPUS ||
+                            !test_bit(sample->cpu, rep->cpu_bitmap)))
                goto out_put;
 
        if (sort__mode == SORT_MODE__BRANCH) {
index 4de2baf03c5036dc93fa43d2f02d544d895e7a3b..e7bd3f331cb8e889846929c996b8ca5b7dc7a38c 100644 (file)
@@ -2192,7 +2192,8 @@ static void timehist_print_sample(struct perf_sched *sched,
        char nstr[30];
        u64 wait_time;
 
-       if (cpu_list && !test_bit(sample->cpu, cpu_bitmap))
+       if (cpu_list && (sample->cpu >= MAX_NR_CPUS ||
+                       !test_bit(sample->cpu, cpu_bitmap)))
                return;
 
        timestamp__scnprintf_usec(t, tstr, sizeof(tstr));
@@ -2871,7 +2872,8 @@ static int timehist_sched_change_event(const struct perf_tool *tool,
        }
 
        if (!sched->idle_hist || thread__tid(thread) == 0) {
-               if (!cpu_list || test_bit(sample->cpu, cpu_bitmap))
+               if (!cpu_list || (sample->cpu < MAX_NR_CPUS &&
+                                test_bit(sample->cpu, cpu_bitmap)))
                        timehist_update_runtime_stats(tr, t, tprev);
 
                if (sched->idle_hist) {