audio: tdfb: Improve robustness for invalid configuration#10877
Conversation
There was a problem hiding this comment.
Pull request overview
This PR hardens the TDFB (time-domain fixed beamformer) module against malformed configuration blobs and malformed IPC3 control payloads, aiming to prevent invalid offset arithmetic and out-of-bounds accesses when parsing untrusted inputs.
Changes:
- Track and validate configuration blob size end-to-end (
cd->config_size) and add multiple config field validity checks (e.g.,angle_enum_mult,filter_index, negative channel selects). - Add IPC3 GET handler validation for
cdata->num_elemsto avoid overrunning the control payload. - Increase the stack array used in theoretical time-difference calculation to support up to
SOF_TDFB_MAX_MICROPHONES.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| src/audio/tdfb/tdfb.c | Adds blob-size tracking and additional config sanity checks during coefficient init and runtime blob updates. |
| src/audio/tdfb/tdfb_ipc3.c | Rejects invalid num_elems values in IPC3 GET handling to prevent payload overruns. |
| src/audio/tdfb/tdfb_direction.c | Enlarges a local array to support up to 16 microphone locations. |
| src/audio/tdfb/tdfb_comp.h | Adds config_size field to persist blob size for validation. |
Add validity checks against malformed configuration blobs and IPC control payloads: - Bound the blob length reported by comp_get_data_blob() to [sizeof(*cd->config), SOF_TDFB_MAX_SIZE] in both tdfb_prepare and the runtime new-blob path; store it in cd->config_size and require config->size to match in tdfb_init_coef. - Bump SOF_TDFB_MAX_SIZE 4096 -> 16384 to match the topology budget. - Tie SOF_TDFB_MAX_MICROPHONES to PLATFORM_MAX_CHANNELS so num_mic_locations cannot exceed the per-channel direction state arrays in tdfb_comp.h. - Reject num_angles == 0, angle_enum_mult == 0, negative or out-of-range filter_index, and negative input_channel_select[]. - Check cdata->num_elems vs. SOF_IPC_MAX_CHANNELS in the IPC3 GET handler. Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Comments suppressed due to low confidence (1)
src/audio/tdfb/tdfb.c:380
tdfb_filter_seek()walksnum_filterscoefficient blocks by reading eachsof_fir_coef_data->lengthfrom the blob, but it has no bounds checking againstconfig->size/cd->config_size. With a malformed blob (e.g., a large length), this can advancecoefppast the end of the allocation and then dereference out-of-bounds in the next iteration, before the later end-of-blob size check runs.
/* Skip filter coefficients */
num_filters = config->num_filters * (config->num_angles + config->beam_off_defined);
coefp = tdfb_filter_seek(config, num_filters);
| if (!config->angle_enum_mult) { | ||
| comp_err(dev, "invalid angle_enum_mult"); | ||
| return -EINVAL; | ||
| } |
There was a problem hiding this comment.
With negative multiplier it's possible to generate a descending angle scale. It could be useful, no need to limit the usage. The angles are negative and positive any way via the angle offset parameter.
| if (config->size != cd->config_size) { | ||
| comp_err(dev, "Incorrect configuration blob size"); | ||
| return -EINVAL; | ||
| } |
There was a problem hiding this comment.
Since the blobs are created with a tool (not manually) the size mismatch is very unlikely. No need for more details.
| if (comp_is_new_data_blob_available(cd->model_handler)) { | ||
| cd->config = comp_get_data_blob(cd->model_handler, NULL, NULL); | ||
| cd->config = comp_get_data_blob(cd->model_handler, &cd->config_size, NULL); | ||
| if (!cd->config || cd->config_size < sizeof(*cd->config) || | ||
| cd->config_size > SOF_TDFB_MAX_SIZE) { | ||
| comp_err(dev, "invalid configuration blob, size %zu", cd->config_size); | ||
| return -EINVAL; | ||
| } |
There was a problem hiding this comment.
I propose to add the blob validator later. I have started the work but it won't be ready before summer vacations that this PR targets for.
| struct tdfb_comp_data *cd = module_get_private_data(mod); | ||
|
|
||
| if (cdata->num_elems == 0 || cdata->num_elems > SOF_IPC_MAX_CHANNELS) | ||
| return -EINVAL; |
There was a problem hiding this comment.
only bytes controls will have num_elems as 0 as the hos does not know the size, for any other controls the host sets num_elems: data->num_elems = scontrol->num_channels;, the num_channels comes from topology and only checked against SND_SOC_TPLG_MAX_CHAN, no check for 0 anywhere, not even in core, a control is allowed to have 0 channels?
There was a problem hiding this comment.
I'm not even sure the num_elems strictly means number of stream channels. It might be e.g. graphical EQ bands number that could be larger than max. channels count, e.g. 10 vs. 8. Can the cdata buffer allocation be too small for the num_elems ever?
There was a problem hiding this comment.
it is allocated based on the num_channels:
https://github.com/thesofproject/linux/blob/topic/sof-dev/sound/soc/sof/ipc4-control.c#L214
There was a problem hiding this comment.
With current implementation of the control the components generally can decide the usage, the control can be per channel, or as "mono" a control for all channels, or with non-associated to channels something else like the graphical EQ bands controls. In this case with the current IIR implementation, the SOF_IPC_MAX_CHANNELS check isn't limiting any functionality so it can be kept.
There was a problem hiding this comment.
atm, lets keep the validation in the module for valid channel count in kcontrols as they will be different.
Add several validity checks against malformed configuration blobs and malformed IPC control payloads.