Skip to content

Commit 4ebae2c

Browse files
committed
audio: crossover: Improve robustness for invalid configuration
crossover_validate_config() was only run on the initial blob in crossover_prepare(). Runtime IPC updates fetched in crossover_process_audio_stream() were applied without revalidation, so a bad blob could drive crossover_setup() with an out-of-range num_sinks. Validate the new blob before crossover_setup() runs. Also extend the validator to cross-check config->size against the size reported by the framework and to require enough payload for the LR4 biquads that crossover_init_coef_ch() reads (1 pair for 2-way, 3 pairs for 3-way and 4-way). Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
1 parent 0d9b5ec commit 4ebae2c

1 file changed

Lines changed: 72 additions & 12 deletions

File tree

src/audio/crossover/crossover.c

Lines changed: 72 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -350,16 +350,40 @@ static int crossover_free(struct processing_module *mod)
350350
* \brief Verifies that the config is formatted correctly.
351351
*
352352
* The function can only be called after the buffers have been initialized.
353+
*
354+
* \param[in] mod Processing module owning the configuration. The blob
355+
* under validation is read from the module's private data
356+
* (\c cd->config); callers must store it there beforehand.
357+
* \param[in] new_size Size in bytes reported by the framework for the blob;
358+
* must match the size field embedded in the blob header.
359+
* \return 0 on success, negative errno on invalid configuration.
353360
*/
354-
static int crossover_validate_config(struct processing_module *mod,
355-
struct sof_crossover_config *config)
361+
static int crossover_validate_config(struct processing_module *mod, size_t new_size)
356362
{
363+
struct comp_data *cd = module_get_private_data(mod);
364+
struct sof_crossover_config *config = cd->config;
357365
struct comp_dev *dev = mod->dev;
358-
uint32_t size = config->size;
366+
size_t required_size;
359367
int32_t num_assigned_sinks;
368+
int32_t num_lr4s;
369+
uint32_t size;
370+
371+
if (!config) {
372+
comp_err(dev, "NULL config blob");
373+
return -EINVAL;
374+
}
360375

361-
if (size > SOF_CROSSOVER_MAX_SIZE || !size) {
362-
comp_err(dev, "size %d is invalid", size);
376+
/* Reject truncated blobs before touching config->size: the framework-
377+
* reported new_size must cover at least the fixed header.
378+
*/
379+
if (new_size < sizeof(*config)) {
380+
comp_err(dev, "size u smaller than header %u", (uint32_t)new_size);
381+
return -EINVAL;
382+
}
383+
384+
size = config->size;
385+
if (size > SOF_CROSSOVER_MAX_SIZE || size != new_size) {
386+
comp_err(dev, "size %u is invalid", size);
363387
return -EINVAL;
364388
}
365389

@@ -370,6 +394,17 @@ static int crossover_validate_config(struct processing_module *mod,
370394
return -EINVAL;
371395
}
372396

397+
/* Each channel reads 2 * num_lr4s biquads from config->coef[]; the
398+
* runtime uses 1 LR4 pair for 2-way and 3 LR4 pairs otherwise.
399+
* See tune/sof_crossover_generate_config.m script.
400+
*/
401+
num_lr4s = (config->num_sinks == CROSSOVER_2WAY_NUM_SINKS) ? 1 : 3;
402+
required_size = sizeof(*config) + (size_t)num_lr4s * 2 * sizeof(struct sof_eq_iir_biquad);
403+
if (size < required_size) {
404+
comp_err(dev, "size %u too small for num_sinks %u", size, config->num_sinks);
405+
return -EINVAL;
406+
}
407+
373408
/* Align the crossover's sinks, to their respective configuration in
374409
* the config.
375410
*/
@@ -448,14 +483,36 @@ static int crossover_process_audio_stream(struct processing_module *mod,
448483
uint32_t frames = input_buffers[0].size;
449484
uint32_t frame_bytes = audio_stream_frame_bytes(input_buffers[0].data);
450485
uint32_t processed_bytes;
486+
struct sof_crossover_config *prev_config;
487+
uint32_t prev_num_sinks;
488+
size_t cfg_size;
451489
int ret;
452490
int i;
453491

454492
comp_dbg(dev, "entry");
455493

456494
/* Check for changed configuration */
457495
if (comp_is_new_data_blob_available(cd->model_handler)) {
458-
cd->config = comp_get_data_blob(cd->model_handler, NULL, NULL);
496+
prev_config = cd->config;
497+
prev_num_sinks = prev_config ? prev_config->num_sinks : 0;
498+
499+
cd->config = comp_get_data_blob(cd->model_handler, &cfg_size, NULL);
500+
ret = crossover_validate_config(mod, cfg_size);
501+
if (ret < 0)
502+
return ret;
503+
504+
/* num_sinks must not change at runtime: cd->crossover_split was
505+
* selected for the previous count, and a smaller value would
506+
* cause the split function to write past the sink array.
507+
* Reject the blob; the previous config and split stay in use.
508+
*/
509+
if (prev_num_sinks && cd->config->num_sinks != prev_num_sinks) {
510+
comp_err(dev, "runtime num_sinks change %u -> %u not supported",
511+
prev_num_sinks, cd->config->num_sinks);
512+
cd->config = prev_config;
513+
return -EINVAL;
514+
}
515+
459516
ret = crossover_setup(mod, audio_stream_get_channels(source));
460517
if (ret < 0) {
461518
comp_err(dev, "failed Crossover setup");
@@ -513,6 +570,7 @@ static int crossover_prepare(struct processing_module *mod,
513570
struct comp_buffer *source, *sink;
514571
size_t data_size;
515572
int channels;
573+
int ret;
516574

517575
comp_info(dev, "entry");
518576

@@ -545,12 +603,14 @@ static int crossover_prepare(struct processing_module *mod,
545603

546604
cd->config = comp_get_data_blob(cd->model_handler, &data_size, NULL);
547605

548-
/* Initialize Crossover */
549-
if (cd->config &&
550-
(!data_size || crossover_validate_config(mod, cd->config) < 0)) {
551-
/* If the configuration is invalid fail the prepare */
552-
comp_err(dev, "invalid binary config format");
553-
return -EINVAL;
606+
/* A NULL cd->config is a supported operating mode: the component runs
607+
* in passthrough (see the else-branch below), so only validate when a
608+
* blob is actually present.
609+
*/
610+
if (cd->config) {
611+
ret = crossover_validate_config(mod, data_size);
612+
if (ret < 0)
613+
return ret;
554614
}
555615

556616
if (cd->config) {

0 commit comments

Comments
 (0)