]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
perf timechart: Bounds check CPU
authorIan Rogers <irogers@google.com>
Wed, 20 May 2026 19:05:35 +0000 (12:05 -0700)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Wed, 20 May 2026 19:39:41 +0000 (16:39 -0300)
Prevent out-of-bounds writes/reads in CPU state tracking arrays by enforcing
strict MAX_CPUS bounds checks in timechart's tracepoint handlers.

Ensure that cpu_id retrieved from idle/frequency and sched tracepoints is less
than MAX_CPUS before indexing into cpus_cstate_state, cpus_cstate_start_times,
and similar tracking arrays. Also, fix an off-by-one error in the CPU iteration
loop inside end_sample_processing() by changing the loop condition from
'cpu <= tchart->numcpus' to 'cpu < tchart->numcpus'.

Signed-off-by: Ian Rogers <irogers@google.com>
Acked-by: Namhyung Kim <namhyung@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Albert Ou <aou@eecs.berkeley.edu>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexandre Ghiti <alex@ghiti.fr>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Andrew Jones <ajones@ventanamicro.com>
Cc: Anup Patel <anup@brainfault.org>
Cc: Athira Rajeev <atrajeev@linux.ibm.com>
Cc: Blake Jones <blakejones@google.com>
Cc: Chen Ni <nichen@iscas.ac.cn>
Cc: Chun-Tse Shao <ctshao@google.com>
Cc: Dapeng Mi <dapeng1.mi@linux.intel.com>
Cc: Derek Foreman <derek.foreman@collabora.com>
Cc: Dmitriy Vyukov <dvyukov@google.com>
Cc: Dr. David Alan Gilbert <linux@treblig.org>
Cc: Howard Chu <howardchu95@gmail.com>
Cc: Hrishikesh Suresh <hrishikesh123s@gmail.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@linaro.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Krzysztof Ɓopatowski <krzysztof.m.lopatowski@gmail.com>
Cc: Leo Yan <leo.yan@arm.com>
Cc: Palmer Dabbelt <palmer@dabbelt.com>
Cc: Paul Walmsley <pjw@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Quan Zhou <zhouquan@iscas.ac.cn>
Cc: Ravi Bangoria <ravi.bangoria@amd.com>
Cc: Swapnil Sapkal <swapnil.sapkal@amd.com>
Cc: Thomas Falcon <thomas.falcon@intel.com>
Cc: Tianyou Li <tianyou.li@intel.com>
Cc: Yujie Liu <yujie.liu@intel.com>
Cc: tanze <tanze@kylinos.cn>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/builtin-timechart.c

index d2e15d02304ea1ab154065104db64cca4146ff07..630756bebe3242dc5ef6cbae6953b55c68d8a2e0 100644 (file)
@@ -605,6 +605,10 @@ process_sample_cpu_idle(struct timechart *tchart __maybe_unused,
        u32 state  = perf_sample__intval(sample, "state");
        u32 cpu_id = perf_sample__intval(sample, "cpu_id");
 
+       if (cpu_id >= MAX_CPUS) {
+               pr_debug("Out-of-bounds cpu_id %u\n", cpu_id);
+               return -1;
+       }
        if (state == (u32)PWR_EVENT_EXIT)
                c_state_end(tchart, cpu_id, sample->time);
        else
@@ -620,6 +624,10 @@ process_sample_cpu_frequency(struct timechart *tchart,
        u32 state  = perf_sample__intval(sample, "state");
        u32 cpu_id = perf_sample__intval(sample, "cpu_id");
 
+       if (cpu_id >= MAX_CPUS) {
+               pr_debug("Out-of-bounds cpu_id %u\n", cpu_id);
+               return -1;
+       }
        p_state_change(tchart, cpu_id, sample->time, state);
        return 0;
 }
@@ -633,6 +641,10 @@ process_sample_sched_wakeup(struct timechart *tchart,
        int waker = perf_sample__intval(sample, "common_pid");
        int wakee = perf_sample__intval(sample, "pid");
 
+       if (sample->cpu >= MAX_CPUS) {
+               pr_debug("Out-of-bounds cpu %u\n", sample->cpu);
+               return -1;
+       }
        sched_wakeup(tchart, sample->cpu, sample->time, waker, wakee, flags, backtrace);
        return 0;
 }
@@ -646,6 +658,10 @@ process_sample_sched_switch(struct timechart *tchart,
        int next_pid   = perf_sample__intval(sample, "next_pid");
        u64 prev_state = perf_sample__intval(sample, "prev_state");
 
+       if (sample->cpu >= MAX_CPUS) {
+               pr_debug("Out-of-bounds cpu %u\n", sample->cpu);
+               return -1;
+       }
        sched_switch(tchart, sample->cpu, sample->time, prev_pid, next_pid,
                     prev_state, backtrace);
        return 0;
@@ -660,6 +676,10 @@ process_sample_power_start(struct timechart *tchart __maybe_unused,
        u64 cpu_id = perf_sample__intval(sample, "cpu_id");
        u64 value  = perf_sample__intval(sample, "value");
 
+       if (cpu_id >= MAX_CPUS) {
+               pr_debug("Out-of-bounds cpu_id %llu\n", (unsigned long long)cpu_id);
+               return -1;
+       }
        c_state_start(cpu_id, sample->time, value);
        return 0;
 }
@@ -669,6 +689,10 @@ process_sample_power_end(struct timechart *tchart,
                         struct perf_sample *sample,
                         const char *backtrace __maybe_unused)
 {
+       if (sample->cpu >= MAX_CPUS) {
+               pr_debug("Out-of-bounds cpu %u\n", sample->cpu);
+               return -1;
+       }
        c_state_end(tchart, sample->cpu, sample->time);
        return 0;
 }
@@ -681,6 +705,10 @@ process_sample_power_frequency(struct timechart *tchart,
        u64 cpu_id = perf_sample__intval(sample, "cpu_id");
        u64 value  = perf_sample__intval(sample, "value");
 
+       if (cpu_id >= MAX_CPUS) {
+               pr_debug("Out-of-bounds cpu_id %llu\n", (unsigned long long)cpu_id);
+               return -1;
+       }
        p_state_change(tchart, cpu_id, sample->time, value);
        return 0;
 }
@@ -692,10 +720,9 @@ process_sample_power_frequency(struct timechart *tchart,
  */
 static void end_sample_processing(struct timechart *tchart)
 {
-       u64 cpu;
-       struct power_event *pwr;
+       for (u64 cpu = 0; cpu < tchart->numcpus; cpu++) {
+               struct power_event *pwr;
 
-       for (cpu = 0; cpu <= tchart->numcpus; cpu++) {
                /* C state */
 #if 0
                pwr = zalloc(sizeof(*pwr));
@@ -1515,6 +1542,8 @@ static int process_header(struct perf_file_section *section __maybe_unused,
        switch (feat) {
        case HEADER_NRCPUS:
                tchart->numcpus = ph->env.nr_cpus_avail;
+               if (tchart->numcpus > MAX_CPUS)
+                       tchart->numcpus = MAX_CPUS;
                break;
 
        case HEADER_CPU_TOPOLOGY: