From 2a3b83695f0b0154304f3d4ff4fb5123687a46c9 Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Mon, 4 May 2026 14:47:12 +0300 Subject: [PATCH 1/3] Audio: Sound Dose: Fix use-after-free in sound_dose_free This patch replaces the rfree() of cd->msg with ipc_msg_free() which properly unlinks the message from the IPC message queue before freeing it. The direct rfree() left a dangling list entry, causing a use-after-free when tb_free() drains the queue via ipc_send_queued_msg(). Signed-off-by: Seppo Ingalsuo --- src/audio/sound_dose/sound_dose.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/audio/sound_dose/sound_dose.c b/src/audio/sound_dose/sound_dose.c index 0e162a783b8a..c28b55baee4d 100644 --- a/src/audio/sound_dose/sound_dose.c +++ b/src/audio/sound_dose/sound_dose.c @@ -327,10 +327,7 @@ __cold static int sound_dose_free(struct processing_module *mod) comp_dbg(mod->dev, "entry"); sound_dose_filters_free(cd); - if (cd->msg) { - rfree(cd->msg->tx_data); - rfree(cd->msg); - } + ipc_msg_free(cd->msg); rfree(cd->abi); rfree(cd); return 0; From 57c1e41422369d85fa2afb669af3595419310da6 Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Tue, 28 Apr 2026 15:01:15 +0300 Subject: [PATCH 2/3] Tools: Testbench: Fix notification pool memory leak In capture direction testbench runs, pipeline_comp_copy() triggers send_process_data_error_notif_msg() which allocates a notification from the pool and queues it to the IPC message list via ipc_msg_send(). On Zephyr targets a work handler calls ipc_send_queued_msg() to process the queue and invoke the free callback. In the testbench no such handler exists, so queued notifications are never freed. Add ipc_notification_pool_free() to notification_pool.c to release all pool items. In tb_free(), drain the IPC message queue by calling ipc_send_queued_msg() in a loop, then call ipc_notification_pool_free() to free the pool before releasing IPC resources. Signed-off-by: Seppo Ingalsuo --- src/include/sof/ipc/notification_pool.h | 11 +++++++++++ src/ipc/notification_pool.c | 19 +++++++++++++++++++ tools/testbench/utils.c | 9 +++++++++ 3 files changed, 39 insertions(+) diff --git a/src/include/sof/ipc/notification_pool.h b/src/include/sof/ipc/notification_pool.h index 0e41a6effcb9..835399307ae2 100644 --- a/src/include/sof/ipc/notification_pool.h +++ b/src/include/sof/ipc/notification_pool.h @@ -23,4 +23,15 @@ */ struct ipc_msg *ipc_notification_pool_get(size_t size); +#if CONFIG_LIBRARY +/** + * @brief Frees all IPC notification messages in the pool. + * + * This function frees all notification messages currently held in + * the pool free list and resets the pool depth counter. It is + * required only in library (testbench) build. + */ +void ipc_notification_pool_free(void); +#endif /* CONFIG_LIBRARY */ + #endif /* __SOF_IPC_NOTIFICATION_POOL_H__ */ diff --git a/src/ipc/notification_pool.c b/src/ipc/notification_pool.c index 7692928d0e8a..5894fc499b99 100644 --- a/src/ipc/notification_pool.c +++ b/src/ipc/notification_pool.c @@ -100,3 +100,22 @@ struct ipc_msg *ipc_notification_pool_get(size_t size) item->msg.tx_size = size; return &item->msg; } + +#if CONFIG_LIBRARY +void ipc_notification_pool_free(void) +{ + struct ipc_notif_pool_item *item; + k_spinlock_key_t key; + + key = k_spin_lock(&pool_free_list_lock); + while (!list_is_empty(&pool_free_list)) { + item = list_first_item(&pool_free_list, struct ipc_notif_pool_item, msg.list); + list_item_del(&item->msg.list); + --pool_depth; + k_spin_unlock(&pool_free_list_lock, key); + rfree(item); + key = k_spin_lock(&pool_free_list_lock); + } + k_spin_unlock(&pool_free_list_lock, key); +} +#endif /* CONFIG_LIBRARY */ diff --git a/tools/testbench/utils.c b/tools/testbench/utils.c index f6efbbcbc387..597e3aaa043d 100644 --- a/tools/testbench/utils.c +++ b/tools/testbench/utils.c @@ -6,6 +6,8 @@ #include #include #include +#include +#include #include #include @@ -211,6 +213,13 @@ void tb_free(struct sof *sof) } free(*arch_schedulers_get()); + /* Drain IPC message queue to free queued notifications */ + while (!list_is_empty(&sof->ipc->msg_list)) + ipc_send_queued_msg(); + + /* Free notification pool items */ + ipc_notification_pool_free(); + /* free IPC data */ iipc = sof->ipc->private; free(sof->ipc->comp_data); From e4aa8937d8305176129d7826f362d4abf1a07494 Mon Sep 17 00:00:00 2001 From: Seppo Ingalsuo Date: Tue, 28 Apr 2026 14:57:36 +0300 Subject: [PATCH 3/3] Audio: MFCC: Fix memory leak in mfcc_free() The mfcc_free_buffers() need to be called before the component data cd is freed. The pointers to buffers are members of cd. Signed-off-by: Seppo Ingalsuo --- src/audio/mfcc/mfcc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/audio/mfcc/mfcc.c b/src/audio/mfcc/mfcc.c index 6a168903edbf..9874edea4be5 100644 --- a/src/audio/mfcc/mfcc.c +++ b/src/audio/mfcc/mfcc.c @@ -98,8 +98,8 @@ static int mfcc_free(struct processing_module *mod) comp_info(mod->dev, "entry"); mod_data_blob_handler_free(mod, cd->model_handler); - mod_free(mod, cd); mfcc_free_buffers(mod); + mod_free(mod, cd); return 0; }