From ebdaaf1d1f6b8fdffb9c957f12f364e0e1ab6b1a Mon Sep 17 00:00:00 2001 From: Tomasz Leman Date: Wed, 1 Jul 2026 23:19:30 +0200 Subject: [PATCH] audio: up_down_mixer: fix use-after-free on init allocation failure up_down_mixer_init() called comp_free(dev) when mod_zalloc() failed and then returned -ENOMEM. That is a lifecycle violation: a module's init() callback must never free its own comp_dev. On init failure the module adapter framework already unwinds the component: module_init() -> mod_free_all(mod) module_adapter_new_ext() -> module_adapter_mem_free(mod) (err path) The stray comp_free(dev) ran a second, full teardown (module_adapter_free -> module .free callback + mod_free_all() + module_adapter_mem_free() + freeing dev) that collided with the framework cleanup in two ways: 1. NULL dereference: comp_free() invoked the module .free callback (up_down_mixer_free) before mod->priv.private had been assigned, so module_get_private_data() returned NULL and the callback dereferenced it. This is the SEGV observed first. 2. Use-after-free / double free: comp_free() had already freed (and, under CONFIG_SYS_HEAP_SANITIZER_ASAN, poisoned) the module resources and the comp_dev. Control then returned to module_init(), which called mod_free_all() on that freed memory, after which the module_adapter_new_ext() error path freed it once more via module_adapter_mem_free(). Fix by removing the comp_free(dev) call and simply returning -ENOMEM, which is exactly what every other module does on this path (aria, asrc, copier, crossover, drc, ...): propagate the error and let the adapter framework own the cleanup. As defensive hardening, also guard up_down_mixer_free() against a NULL private pointer. The bug was latent: with the static Zephyr memory pools these small allocations never failed, so the error path was never taken. It became reachable only after the native_sim host-heap change routed module allocations onto the C library allocator, where sustained memory pressure over many iterations eventually makes mod_zalloc() fail. Found by the IPC4 libFuzzer target on native_sim under AddressSanitizer. Signed-off-by: Tomasz Leman --- src/audio/up_down_mixer/up_down_mixer.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/audio/up_down_mixer/up_down_mixer.c b/src/audio/up_down_mixer/up_down_mixer.c index 4a9a644434e7..270c114ee93c 100644 --- a/src/audio/up_down_mixer/up_down_mixer.c +++ b/src/audio/up_down_mixer/up_down_mixer.c @@ -329,6 +329,9 @@ static int up_down_mixer_free(struct processing_module *mod) { struct up_down_mixer_data *cd = module_get_private_data(mod); + if (!cd) + return 0; + mod_free(mod, cd->buf_in); mod_free(mod, cd->buf_out); mod_free(mod, cd); @@ -346,10 +349,8 @@ static int up_down_mixer_init(struct processing_module *mod) int ret; cd = mod_zalloc(mod, sizeof(*cd)); - if (!cd) { - comp_free(dev); + if (!cd) return -ENOMEM; - } mod_data->private = cd;