diff --git a/src/audio/selector/selector.c b/src/audio/selector/selector.c index 6afc92d8bdfc..d81212bd506b 100644 --- a/src/audio/selector/selector.c +++ b/src/audio/selector/selector.c @@ -238,9 +238,55 @@ static int selector_ctrl_set_data(struct comp_dev *dev, case SOF_CTRL_CMD_BINARY: comp_dbg(dev, "SOF_CTRL_CMD_BINARY"); + if (cdata->data->size < sizeof(struct sof_sel_config)) { + comp_err(dev, "invalid config blob size %u", cdata->data->size); + return -EINVAL; + } + cfg = (struct sof_sel_config *) ASSUME_ALIGNED(&cdata->data->data, 4); + /* + * The config validated at .params() time can be replaced here at + * runtime, so re-validate the new channel counts and selected + * channel before accepting them; otherwise an out-of-range value + * later overflows the channel coefficient table during process(). + */ + switch (cfg->in_channels_count) { + case 0: + case SEL_SOURCE_2CH: + case SEL_SOURCE_4CH: + break; + default: + comp_err(dev, "invalid in_channels_count %u", + cfg->in_channels_count); + return -EINVAL; + } + + switch (cfg->out_channels_count) { + case 0: + case SEL_SINK_1CH: + case SEL_SINK_2CH: + case SEL_SINK_4CH: + break; + default: + comp_err(dev, "invalid out_channels_count %u", + cfg->out_channels_count); + return -EINVAL; + } + + /* sel_channel indexes the source channels: bound it by the + * absolute maximum, and (when the input count is fixed, i.e. + * non-zero) by the configured input channel count too + */ + if (cfg->sel_channel >= SEL_SOURCE_CHANNELS_MAX || + (cfg->in_channels_count && + cfg->sel_channel >= cfg->in_channels_count)) { + comp_err(dev, "invalid sel_channel %u (in_channels_count %u)", + cfg->sel_channel, cfg->in_channels_count); + return -EINVAL; + } + /* Just set the configuration */ cd->config.in_channels_count = cfg->in_channels_count; cd->config.out_channels_count = cfg->out_channels_count;