From 7eb2414c39cdcbf1289b5e4d633aa5daa3911283 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 11 Jun 2026 14:30:37 +0100 Subject: [PATCH 1/3] cadence: validate init payload covers the direction field The init path read the direction word at a fixed offset past the codec params without checking the payload was large enough, reading past the mailbox. Require the payload to cover the field. Signed-off-by: Liam Girdwood --- src/audio/module_adapter/module/cadence_ipc4.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/audio/module_adapter/module/cadence_ipc4.c b/src/audio/module_adapter/module/cadence_ipc4.c index 17069b97113a..1d409e4b5a31 100644 --- a/src/audio/module_adapter/module/cadence_ipc4.c +++ b/src/audio/module_adapter/module/cadence_ipc4.c @@ -265,7 +265,14 @@ static int cadence_codec_init(struct processing_module *mod) setup_cfg->avail = true; codec->cfg.avail = false; - /* direction follows the codec params in init data */ + /* direction follows the codec params in init data; make sure the + * payload is large enough to hold it before dereferencing + */ + if (size < (int)(sizeof(struct snd_codec) + sizeof(uint32_t))) { + comp_err(dev, "setup config too small for direction: %d", size); + ret = -EINVAL; + goto free_cfg; + } init_bytes = (uint8_t *)ext_data->module_data; cd->direction = *(uint32_t *)(init_bytes + sizeof(struct snd_codec)); From 6890f78cb930077e1f7cd6b4666a929511aa7a7a Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 11 Jun 2026 14:30:37 +0100 Subject: [PATCH 2/3] waves: check remaining size before reading a tlv header The config parse loop read a parameter header before confirming a whole header remained in the blob, reading past it near the end. Bound the read by the remaining size. Signed-off-by: Liam Girdwood --- src/audio/module_adapter/module/waves/waves.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/audio/module_adapter/module/waves/waves.c b/src/audio/module_adapter/module/waves/waves.c index d328d9e5167f..1727628cd482 100644 --- a/src/audio/module_adapter/module/waves/waves.c +++ b/src/audio/module_adapter/module/waves/waves.c @@ -612,6 +612,15 @@ static int waves_effect_apply_config(struct processing_module *mod) for (index = 0; index < cfg->size && (!ret); param_number++) { uint32_t param_data_size; + /* make sure a whole param header remains before reading + * param->size / param->id below + */ + if (index + header_size > cfg->size) { + comp_err(dev, "module_param header exceeds cfg buffer size: %d", + cfg->size); + return -EINVAL; + } + param = (struct module_param *)((char *)cfg->data + index); param_data_size = param->size - sizeof(param->size) - sizeof(param->id); From 0c0e552d8667a44dfe53dbed5849e8e73a1b7961 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 11 Jun 2026 14:31:58 +0100 Subject: [PATCH 3/3] module_adapter: make fragmented-transfer size per-instance The reassembly size for fragmented runtime-params transfers was a file-scope static shared by every component, so interleaved transfers to different components corrupted each other's state. Move it into per-instance module state. Signed-off-by: Liam Girdwood --- src/audio/module_adapter/module_adapter_ipc3.c | 12 ++++++++---- src/include/module/module/base.h | 6 ++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/audio/module_adapter/module_adapter_ipc3.c b/src/audio/module_adapter/module_adapter_ipc3.c index 74c8f02afa2f..66d312522410 100644 --- a/src/audio/module_adapter/module_adapter_ipc3.c +++ b/src/audio/module_adapter/module_adapter_ipc3.c @@ -184,21 +184,25 @@ static int module_adapter_get_set_params(struct comp_dev *dev, struct sof_ipc_ct const struct module_interface *const interface = mod->dev->drv->adapter_ops; enum module_cfg_fragment_position pos; uint32_t data_offset_size; - static uint32_t size; + /* per-instance reassembly size; a file-scope static would be shared + * across all module_adapter components and corrupted by interleaved + * fragmented transfers + */ + uint32_t *size = &mod->runtime_params_size; comp_dbg(dev, "num_of_elem %d, elem remain %d msg_index %u", cdata->num_elems, cdata->elems_remaining, cdata->msg_index); /* set the fragment position, data offset and config data size */ if (!cdata->msg_index) { - size = cdata->num_elems + cdata->elems_remaining; - data_offset_size = size; + *size = cdata->num_elems + cdata->elems_remaining; + data_offset_size = *size; if (cdata->elems_remaining) pos = MODULE_CFG_FRAGMENT_FIRST; else pos = MODULE_CFG_FRAGMENT_SINGLE; } else { - data_offset_size = size - (cdata->num_elems + cdata->elems_remaining); + data_offset_size = *size - (cdata->num_elems + cdata->elems_remaining); if (cdata->elems_remaining) pos = MODULE_CFG_FRAGMENT_MIDDLE; else diff --git a/src/include/module/module/base.h b/src/include/module/module/base.h index 657673099d60..8a8237666b16 100644 --- a/src/include/module/module/base.h +++ b/src/include/module/module/base.h @@ -118,6 +118,12 @@ struct processing_module { uint32_t deep_buff_bytes; /**< copy start threshold */ uint32_t output_buffer_size; /**< size of local buffer to save produced samples */ + /* total size of a fragmented runtime-params (get/set) transfer, kept + * per instance so concurrent transfers to different components do not + * corrupt each other's reassembly state + */ + uint32_t runtime_params_size; + /* number of sinks / sources and (when in use) input_buffers / input_buffers */ uint32_t num_of_sources; uint32_t num_of_sinks;