From 85212b5ea1ecdeda87b64fd6b8e874c2ec3271c6 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 23 Jul 2026 15:41:55 +0100 Subject: [PATCH 1/3] schedule: zephyr_ll: fix NULL pointer dereference and race conditions during task free When a task is freed by zephyr_ll_task_free(), zephyr_ll_run() can still hold a reference to the task's pdata structure across the LL lock boundary. Re-fetching task->priv_data under zephyr_ll_lock() prevents evaluating pdata->freeing on a stale/freed pointer. Additionally, add NULL checks for pdata in zephyr_ll_task_done() and task/pdata in zephyr_ll_task_free(). Signed-off-by: Liam Girdwood --- src/schedule/zephyr_ll.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/schedule/zephyr_ll.c b/src/schedule/zephyr_ll.c index 9950c8c2050b..427512375942 100644 --- a/src/schedule/zephyr_ll.c +++ b/src/schedule/zephyr_ll.c @@ -132,7 +132,7 @@ static void zephyr_ll_task_done(struct zephyr_ll *sch, task->state = SOF_TASK_STATE_FREE; - if (pdata->freeing) + if (pdata && pdata->freeing) /* * zephyr_ll_task_free() is trying to free this task. Complete * it and signal the semaphore to let the function proceed @@ -297,8 +297,9 @@ static void zephyr_ll_run(void *data) #ifndef CONFIG_SOF_USERSPACE_LL zephyr_ll_lock(sch, &flags); #endif + pdata = task->priv_data; - if (pdata->freeing || state == SOF_TASK_STATE_COMPLETED) { + if (!pdata || pdata->freeing || state == SOF_TASK_STATE_COMPLETED) { zephyr_ll_task_done(sch, task); } else { /* @@ -457,9 +458,16 @@ static int zephyr_ll_task_free(void *data, struct task *task) { struct zephyr_ll *sch = data; uint32_t flags; - struct zephyr_ll_pdata *pdata = task->priv_data; + struct zephyr_ll_pdata *pdata; bool must_wait, on_list = true; + if (!task) + return 0; + + pdata = task->priv_data; + if (!pdata) + return 0; + zephyr_ll_assert_core(sch); #ifndef CONFIG_SOF_USERSPACE_LL From 39b0f2df4e790a58f0b422f000115bc68f7deb9f Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 23 Jul 2026 15:41:56 +0100 Subject: [PATCH 2/3] schedule: zephyr_dp: validate module and task pointers in scheduler_dp_thread_ipc Move task_dp_pdata assignment after checking pmod and validate pmod->dev, pmod->dev->task, and pmod->dev->task->priv_data pointers before dereferencing to prevent NULL pointer crashes. Signed-off-by: Liam Girdwood --- src/schedule/zephyr_dp_schedule_application.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/schedule/zephyr_dp_schedule_application.c b/src/schedule/zephyr_dp_schedule_application.c index 791e16ab190d..79783ed52463 100644 --- a/src/schedule/zephyr_dp_schedule_application.c +++ b/src/schedule/zephyr_dp_schedule_application.c @@ -154,7 +154,6 @@ static void ipc_thread_unflatten_run(struct processing_module *pmod, struct ipc4 int scheduler_dp_thread_ipc(struct processing_module *pmod, unsigned int cmd, const union scheduler_dp_thread_ipc_param *param) { - struct task_dp_pdata *pdata = pmod->dev->task->priv_data; int ret; if (!pmod) { @@ -162,6 +161,13 @@ int scheduler_dp_thread_ipc(struct processing_module *pmod, unsigned int cmd, return -EINVAL; } + if (!pmod->dev || !pmod->dev->task || !pmod->dev->task->priv_data) { + tr_err(&dp_tr, "no thread task or pdata"); + return -EINVAL; + } + + struct task_dp_pdata *pdata = pmod->dev->task->priv_data; + if (cmd == SOF_IPC4_MOD_INIT_INSTANCE) { /* Wait for the DP thread to start */ ret = k_sem_take(&dp_sync[pmod->dev->task->core], DP_THREAD_IPC_TIMEOUT); From ef18334021f9f9b53a34c48e01bacb148caaa87a Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 23 Jul 2026 15:41:58 +0100 Subject: [PATCH 3/3] audio: chain_dma: prevent NULL pointer dereference in chain_task_run Validate cd, cd->dma_buffer, cd->chan_link, and cd->chan_host at the start of chain_task_run() to handle stream teardown cleanly when buffers or channels are freed before task completion. Signed-off-by: Liam Girdwood --- src/audio/chain_dma.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/audio/chain_dma.c b/src/audio/chain_dma.c index e7207e636ee8..f5919a0621db 100644 --- a/src/audio/chain_dma.c +++ b/src/audio/chain_dma.c @@ -168,6 +168,9 @@ static enum task_state chain_task_run(void *data) uint32_t link_type; int ret; + if (!cd || !cd->dma_buffer || !cd->chan_link || !cd->chan_host) + return SOF_TASK_STATE_COMPLETED; + /* Link DMA can return -EPIPE and current status if xrun occurs, then it is not critical * and flow shall continue. Other error values will be treated as critical. */