Skip to content

Commit cceaf11

Browse files
committed
selector: re-validate configuration on control set
A new configuration accepted at runtime through the control set path was copied in without the validation done when parameters are applied, so a later out-of-range channel count could overflow the channel table. Validate the blob size and channel fields before accepting it. Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
1 parent 3f7738d commit cceaf11

1 file changed

Lines changed: 60 additions & 0 deletions

File tree

src/audio/selector/selector.c

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,15 +232,75 @@ static int selector_ctrl_set_data(struct comp_dev *dev,
232232
{
233233
struct comp_data *cd = comp_get_drvdata(dev);
234234
struct sof_sel_config *cfg;
235+
uint32_t live_channels;
235236
int ret = 0;
236237

237238
switch (cdata->cmd) {
238239
case SOF_CTRL_CMD_BINARY:
239240
comp_dbg(dev, "SOF_CTRL_CMD_BINARY");
240241

242+
if (cdata->data->size < sizeof(struct sof_sel_config)) {
243+
comp_err(dev, "invalid config blob size %u", cdata->data->size);
244+
return -EINVAL;
245+
}
246+
241247
cfg = (struct sof_sel_config *)
242248
ASSUME_ALIGNED(&cdata->data->data, 4);
243249

250+
/*
251+
* The config validated at .params() time can be replaced here at
252+
* runtime, so re-validate the new channel counts and selected
253+
* channel before accepting them; otherwise an out-of-range value
254+
* later indexes past the source channels in the copy routine.
255+
*/
256+
switch (cfg->in_channels_count) {
257+
case 0:
258+
case SEL_SOURCE_2CH:
259+
case SEL_SOURCE_4CH:
260+
break;
261+
default:
262+
comp_err(dev, "invalid in_channels_count %u",
263+
cfg->in_channels_count);
264+
return -EINVAL;
265+
}
266+
267+
switch (cfg->out_channels_count) {
268+
case 0:
269+
case SEL_SINK_1CH:
270+
case SEL_SINK_2CH:
271+
case SEL_SINK_4CH:
272+
break;
273+
default:
274+
comp_err(dev, "invalid out_channels_count %u",
275+
cfg->out_channels_count);
276+
return -EINVAL;
277+
}
278+
279+
/* sel_channel indexes the source channels, so it must be below
280+
* the source channel count, otherwise the copy routine reads
281+
* past the end of each source frame. Bound it by the maximum
282+
* supported source channel count, and by the actual input count:
283+
* the configured value when fixed (non-zero), or the live source
284+
* stream channel count when the input count varies (zero) and the
285+
* source is already connected.
286+
*/
287+
live_channels = cfg->in_channels_count;
288+
if (!live_channels) {
289+
struct comp_buffer *src =
290+
comp_dev_get_first_data_producer(dev);
291+
292+
if (src)
293+
live_channels =
294+
audio_stream_get_channels(&src->stream);
295+
}
296+
297+
if (cfg->sel_channel >= SEL_SOURCE_4CH ||
298+
(live_channels && cfg->sel_channel >= live_channels)) {
299+
comp_err(dev, "invalid sel_channel %u (in_channels_count %u)",
300+
cfg->sel_channel, cfg->in_channels_count);
301+
return -EINVAL;
302+
}
303+
244304
/* Just set the configuration */
245305
cd->config.in_channels_count = cfg->in_channels_count;
246306
cd->config.out_channels_count = cfg->out_channels_count;

0 commit comments

Comments
 (0)