From 2a8816d64720a2cf919402b0f75e183a7eced636 Mon Sep 17 00:00:00 2001 From: Tomasz Leman Date: Wed, 2 Sep 2026 12:02:07 +0200 Subject: [PATCH] audio: module_adapter: bound large_config fragment reassembly to buffer size md->new_cfg_size, used to bound every SET_LARGE_CONFIG reassembly copy in module_set_configuration, is written in two places: - module_set_large_config, sets it unconditionally on a FIRST fragment - module_set_configuration, sets it while allocating md->runtime_params to that size Nothing keeps the two in sync when a second FIRST fragment arrives mid-reassembly. module_set_large_config allows to overwrite new_cfg_size with a new (larger) value while runtime_params still holds the previous, smaller allocation. A following MIDDLE/LAST fragment then passes the memcpy_s bound check and writes host-controlled mailbox data out of bounds of the heap buffer. Fix it in the reassembly path: - module_set_large_config: reject a FIRST fragment with -EBUSY when a reassembly is already in progress, before overwriting new_cfg_size. - module_set_configuration: commit new_cfg_size only after runtime_params is allocated, so the two always match, and reject an intermediate/last fragment whose host-supplied offset or size does not fit in the buffer, which otherwise underflows the memcpy_s destination bound. Closes #11153 Signed-off-by: Tomasz Leman --- src/audio/module_adapter/module/generic.c | 21 ++++++++++++------- .../module_adapter/module_adapter_ipc4.c | 4 ++++ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/audio/module_adapter/module/generic.c b/src/audio/module_adapter/module/generic.c index 3e46bdac73fd..93b5cbe75e10 100644 --- a/src/audio/module_adapter/module/generic.c +++ b/src/audio/module_adapter/module/generic.c @@ -839,32 +839,33 @@ int module_set_configuration(struct processing_module *mod, * verify input params & allocate memory for the config blob when the first * fragment arrives */ - md->new_cfg_size = data_offset_size; /* Check that there is no previous request in progress */ if (md->runtime_params) { - comp_err(dev, "error: busy with previous request"); + comp_err(dev, "busy with previous request"); return -EBUSY; } - if (!md->new_cfg_size) + if (!data_offset_size) return 0; - if (md->new_cfg_size > CONFIG_MODULE_MAX_BLOB_SIZE) { - comp_err(dev, "error: blob size is too big cfg size %zu, allowed %d", - md->new_cfg_size, CONFIG_MODULE_MAX_BLOB_SIZE); + if (data_offset_size > CONFIG_MODULE_MAX_BLOB_SIZE) { + comp_err(dev, "blob size is too big cfg size %zu, allowed %d", + data_offset_size, CONFIG_MODULE_MAX_BLOB_SIZE); return -EINVAL; } /* Allocate buffer for new params */ md->runtime_params = sof_heap_alloc(sof_sys_user_heap_get(), SOF_MEM_FLAG_USER | SOF_MEM_FLAG_LARGE_BUFFER, - md->new_cfg_size, 0); + data_offset_size, 0); if (!md->runtime_params) { comp_err(dev, "space allocation for new params failed"); return -ENOMEM; } + md->new_cfg_size = data_offset_size; + memset(md->runtime_params, 0, md->new_cfg_size); break; default: @@ -875,6 +876,12 @@ int module_set_configuration(struct processing_module *mod, /* set offset for intermediate and last fragments */ offset = data_offset_size; + if (offset > md->new_cfg_size || + fragment_size > md->new_cfg_size - offset) { + comp_err(dev, "fragment (offset %zu, size %zu) exceeds config buffer %zu", + offset, fragment_size, md->new_cfg_size); + return -EINVAL; + } break; } diff --git a/src/audio/module_adapter/module_adapter_ipc4.c b/src/audio/module_adapter/module_adapter_ipc4.c index da372fc477dc..7fa224a06d6c 100644 --- a/src/audio/module_adapter/module_adapter_ipc4.c +++ b/src/audio/module_adapter/module_adapter_ipc4.c @@ -243,6 +243,10 @@ int module_set_large_config(struct comp_dev *dev, uint32_t param_id, bool first_ fragment_size = MAILBOX_DSPBOX_SIZE; break; case MODULE_CFG_FRAGMENT_FIRST: + if (md->runtime_params) { + comp_err(dev, "FIRST fragment while a request is in progress"); + return -EBUSY; + } md->new_cfg_size = data_offset_size; fragment_size = MAILBOX_DSPBOX_SIZE; break;