@@ -231,16 +231,86 @@ static int selector_ctrl_set_data(struct comp_dev *dev,
231231 struct sof_ipc_ctrl_data * cdata )
232232{
233233 struct comp_data * cd = comp_get_drvdata (dev );
234+ struct comp_buffer * src ;
234235 struct sof_sel_config * cfg ;
236+ uint32_t src_channels ;
235237 int ret = 0 ;
236238
237239 switch (cdata -> cmd ) {
238240 case SOF_CTRL_CMD_BINARY :
239241 comp_dbg (dev , "SOF_CTRL_CMD_BINARY" );
240242
243+ if (cdata -> data -> size < sizeof (struct sof_sel_config )) {
244+ comp_err (dev , "invalid config blob size %u" , cdata -> data -> size );
245+ return - EINVAL ;
246+ }
247+
241248 cfg = (struct sof_sel_config * )
242249 ASSUME_ALIGNED (& cdata -> data -> data , 4 );
243250
251+ /*
252+ * The config validated at .params() time can be replaced here at
253+ * runtime, so re-validate the new channel counts and selected
254+ * channel before accepting them; otherwise an out-of-range value
255+ * later indexes past the source channels in the copy routine.
256+ */
257+ switch (cfg -> in_channels_count ) {
258+ case 0 :
259+ case SEL_SOURCE_1CH :
260+ case SEL_SOURCE_2CH :
261+ case SEL_SOURCE_4CH :
262+ break ;
263+ default :
264+ comp_err (dev , "invalid in_channels_count %u" ,
265+ cfg -> in_channels_count );
266+ return - EINVAL ;
267+ }
268+
269+ switch (cfg -> out_channels_count ) {
270+ case 0 :
271+ case SEL_SINK_1CH :
272+ case SEL_SINK_2CH :
273+ case SEL_SINK_4CH :
274+ break ;
275+ default :
276+ comp_err (dev , "invalid out_channels_count %u" ,
277+ cfg -> out_channels_count );
278+ return - EINVAL ;
279+ }
280+
281+ /* sel_channel indexes the source channels, so it must be below
282+ * the source channel count, otherwise the copy routine reads
283+ * past the end of each source frame. The copy routine strides by
284+ * the live producer stream channel count, so when the source is
285+ * already connected that live count is the authority for both the
286+ * selected channel and any fixed input count; before connection
287+ * fall back to the configured input count. Always cap by the
288+ * maximum supported source width.
289+ */
290+ src = comp_dev_get_first_data_producer (dev );
291+ if (src )
292+ src_channels = audio_stream_get_channels (& src -> stream );
293+ else
294+ src_channels = cfg -> in_channels_count ;
295+
296+ /* A fixed (non-zero) input count must not exceed the live source
297+ * width, otherwise sel_channel could be accepted below the
298+ * requested count yet still index past the actual stream.
299+ */
300+ if (src && cfg -> in_channels_count &&
301+ cfg -> in_channels_count > src_channels ) {
302+ comp_err (dev , "in_channels_count %u exceeds source channels %u" ,
303+ cfg -> in_channels_count , src_channels );
304+ return - EINVAL ;
305+ }
306+
307+ if (cfg -> sel_channel >= SEL_SOURCE_4CH ||
308+ (src_channels && cfg -> sel_channel >= src_channels )) {
309+ comp_err (dev , "invalid sel_channel %u (source channels %u)" ,
310+ cfg -> sel_channel , src_channels );
311+ return - EINVAL ;
312+ }
313+
244314 /* Just set the configuration */
245315 cd -> config .in_channels_count = cfg -> in_channels_count ;
246316 cd -> config .out_channels_count = cfg -> out_channels_count ;
0 commit comments