From 2e3a715d4612ee286eef0ecededccdfc3650da3d Mon Sep 17 00:00:00 2001 From: Tomasz Leman Date: Wed, 5 Aug 2026 15:12:42 +0200 Subject: [PATCH] ipc4: helper: unlock module instance verbs on native_sim ipc4_get_comp_drv() returned NULL unconditionally on native_sim because the RIMAGE_MANIFEST guard (Intel ADSP ACE/CAVS only) was the sole path to a driver UUID lookup. Every INIT_INSTANCE call therefore failed with IPC4_MOD_NOT_INITIALIZED before creating any comp_dev, making the entire module instance verb surface (CONFIG_GET/SET, LARGE_CONFIG on real modules, BIND, UNBIND, DELETE_INSTANCE) unreachable from the fuzzer. Add a CONFIG_ARCH_POSIX_LIBFUZZER branch that mirrors the existing IPC3 whitebox hack in posix/ipc.c: treat module_id as a 1-based index into the runtime comp_driver list. module_id 0 (BaseFW, handled separately and having no create callback) is excluded. Drivers without an ops.create callback are skipped during the index walk so the fuzzer's module_id space only maps to instantiable components, otherwise a module_id that lands on such a driver would cause a NULL function pointer call. Return the resolved driver directly instead of a redundant UUID re-lookup. The change is inactive in all non-fuzz builds. Measured impact (UBSan IPC4, seed=1, 20 s, small corpus): cov ~558 -> ~3974 (~7x lift from previously dead module instance paths) Signed-off-by: Tomasz Leman --- src/ipc/ipc4/helper.c | 47 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/ipc/ipc4/helper.c b/src/ipc/ipc4/helper.c index fd8bd8bf3dbc..162620423be1 100644 --- a/src/ipc/ipc4/helper.c +++ b/src/ipc/ipc4/helper.c @@ -1361,6 +1361,53 @@ __cold const struct comp_driver *ipc4_get_comp_drv(uint32_t module_id) #ifdef RIMAGE_MANIFEST desc = (const struct sof_man_fw_desc *)IMR_BOOT_LDR_MANIFEST_BASE; +#elif defined(CONFIG_ARCH_POSIX_LIBFUZZER) + /* + * native_sim fuzz builds have no rimage manifest so ipc4_get_comp_drv() + * would always return NULL, making every module instance verb + * (INIT_INSTANCE, CONFIG_GET/SET, LARGE_CONFIG, BIND, UNBIND, + * DELETE_INSTANCE) unreachable from the fuzzer. + * + * Mirror the IPC3 whitebox hack in posix/ipc.c: treat module_id as a + * 1-based index into the runtime comp_driver list. module_id 0 (BaseFW) + * has no comp_driver entry and is handled separately above via + * ipc4_get_drv(); non-zero ids map to registered drivers so the fuzzer + * can create real module instances with valid driver UUIDs. + */ + if (module_id) { + struct comp_driver_list *dlist = comp_drivers_get(); + struct list_item *iter; + uint32_t idx = 0; + + list_for_item(iter, &dlist->list) { + struct comp_driver_info *inf = + container_of(iter, struct comp_driver_info, list); + + /* Only count drivers that can be instantiated — + * skip BaseFW and other query-only entries that + * have no create op. + */ + if (!inf->drv->ops.create) + continue; + + /* + * A real signed manifest only lists module-adapter + * modules. The internal gateway drivers (SOF_COMP_HOST, + * SOF_COMP_DAI) are registered for IPC3 but are never + * IPC4 modules: on the IPC4 path they receive no params() + * pass and cannot be configured (e.g. their DMA buffer is + * never allocated). Skip non-module-adapter drivers here + * so the fuzzer's module_id space matches a real manifest + * and cannot map to an unconfigurable component. + */ + if (inf->drv->type != SOF_COMP_MODULE_ADAPTER) + continue; + + if (++idx == module_id) + return inf->drv; + } + } + return NULL; #else /* Non-rimage platforms have no component facility yet. * This needs to move to the platform layer.