Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 14 additions & 7 deletions src/audio/module_adapter/module/generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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;
}
Comment on lines 878 to +884

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is good to add, so we can recover to a sane state.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking about this even before the commit and honestly I don't know. Copilot suggested using free only during middle/last, but during the first message it is possible to request a smaller buffer and attempt to copy a larger chunk of data (which will be correctly rejected but will lead to the same state).

I was wondering whether to reject IPCs where the config size is smaller than or equal to what fits in the mailbox but arrives with the FIRST bit set without FINAL.

If the host sends an incorrect IPC sequence that fails at any point, I would probably leave the teardown on the host side. This does not protect us against a memory leak at all. The host can send such messages to multiple modules, all with the FIRST bit set allocating memory, and nothing will stop it. The BUSY status is returned only if it concerns a specific module instance.

It might be worth taking a closer look at this IPC later, thoroughly describing the possible flows, documenting what is valid and what is not, and how the FW should behave. I think this flow may contain more ambiguities and gaps.

break;
}

Expand Down
4 changes: 4 additions & 0 deletions src/audio/module_adapter/module_adapter_ipc4.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading