]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
perf sched: Replace BUG_ON and add NULL checks in replay event helpers
authorArnaldo Carvalho de Melo <acme@redhat.com>
Fri, 5 Jun 2026 14:26:28 +0000 (11:26 -0300)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Fri, 5 Jun 2026 22:17:31 +0000 (19:17 -0300)
get_new_event() has three issues:

1. The zalloc() result is dereferenced without a NULL check, crashing
   on allocation failure.

2. BUG_ON(!task->atoms) kills the process when realloc() fails.
   Since perf.data is untrusted input, this should be a graceful error.

3. The realloc pattern assigns directly to task->atoms, losing the old
   pointer on failure.  task->nr_events is also incremented before the
   realloc, leaving corrupted state on failure.

Fix get_new_event() to:
  - Check the zalloc() result before dereferencing
  - Use a temporary for realloc() to avoid losing the old pointer
  - Increment nr_events only after successful realloc
  - Return NULL instead of calling BUG_ON on failure

Also fix add_sched_event_wakeup() where zalloc() for wait_sem is
passed to sem_init() without a NULL check.

Update all callers (add_sched_event_run, add_sched_event_wakeup,
add_sched_event_sleep) to handle NULL returns by returning early.
The replay may produce incomplete output on OOM but will not crash.

Fixes: ec156764d424 ("perf sched: Import schedbench.c")
Reported-by: sashiko-bot <sashiko-bot@kernel.org>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Assisted-by: Claude:claude-opus-4.6
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/builtin-sched.c

index 732c65008a8a524013d6724a7c6250925b7c18f6..b7ccdc6a985d1c7ba32e3a44d330c18429fe628a 100644 (file)
@@ -365,14 +365,25 @@ get_new_event(struct task_desc *task, u64 timestamp)
        struct sched_atom *event = zalloc(sizeof(*event));
        unsigned long idx = task->nr_events;
        size_t size;
+       struct sched_atom **atoms_p;
+
+       if (event == NULL) {
+               pr_err("ERROR: sched: failed to allocate event\n");
+               return NULL;
+       }
 
        event->timestamp = timestamp;
        event->nr = idx;
 
+       size = sizeof(struct sched_atom *) * (task->nr_events + 1);
+       atoms_p = realloc(task->atoms, size);
+       if (!atoms_p) {
+               pr_err("ERROR: sched: failed to grow atoms array\n");
+               free(event);
+               return NULL;
+       }
+       task->atoms = atoms_p;
        task->nr_events++;
-       size = sizeof(struct sched_atom *) * task->nr_events;
-       task->atoms = realloc(task->atoms, size);
-       BUG_ON(!task->atoms);
 
        task->atoms[idx] = event;
 
@@ -403,6 +414,8 @@ static void add_sched_event_run(struct perf_sched *sched, struct task_desc *task
        }
 
        event = get_new_event(task, timestamp);
+       if (event == NULL)
+               return;
 
        event->type = SCHED_EVENT_RUN;
        event->duration = duration;
@@ -416,6 +429,8 @@ static void add_sched_event_wakeup(struct perf_sched *sched, struct task_desc *t
        struct sched_atom *event, *wakee_event;
 
        event = get_new_event(task, timestamp);
+       if (event == NULL)
+               return;
        event->type = SCHED_EVENT_WAKEUP;
        event->wakee = wakee;
 
@@ -430,6 +445,10 @@ static void add_sched_event_wakeup(struct perf_sched *sched, struct task_desc *t
        }
 
        wakee_event->wait_sem = zalloc(sizeof(*wakee_event->wait_sem));
+       if (!wakee_event->wait_sem) {
+               pr_err("ERROR: sched: failed to allocate semaphore\n");
+               return;
+       }
        sem_init(wakee_event->wait_sem, 0, 0);
        event->wait_sem = wakee_event->wait_sem;
 
@@ -441,6 +460,9 @@ static void add_sched_event_sleep(struct perf_sched *sched, struct task_desc *ta
 {
        struct sched_atom *event = get_new_event(task, timestamp);
 
+       if (event == NULL)
+               return;
+
        event->type = SCHED_EVENT_SLEEP;
 
        sched->nr_sleep_events++;