@@ -231,16 +231,85 @@ 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_2CH :
260+ case SEL_SOURCE_4CH :
261+ break ;
262+ default :
263+ comp_err (dev , "invalid in_channels_count %u" ,
264+ cfg -> in_channels_count );
265+ return - EINVAL ;
266+ }
267+
268+ switch (cfg -> out_channels_count ) {
269+ case 0 :
270+ case SEL_SINK_1CH :
271+ case SEL_SINK_2CH :
272+ case SEL_SINK_4CH :
273+ break ;
274+ default :
275+ comp_err (dev , "invalid out_channels_count %u" ,
276+ cfg -> out_channels_count );
277+ return - EINVAL ;
278+ }
279+
280+ /* sel_channel indexes the source channels, so it must be below
281+ * the source channel count, otherwise the copy routine reads
282+ * past the end of each source frame. The copy routine strides by
283+ * the live producer stream channel count, so when the source is
284+ * already connected that live count is the authority for both the
285+ * selected channel and any fixed input count; before connection
286+ * fall back to the configured input count. Always cap by the
287+ * maximum supported source width.
288+ */
289+ src = comp_dev_get_first_data_producer (dev );
290+ if (src )
291+ src_channels = audio_stream_get_channels (& src -> stream );
292+ else
293+ src_channels = cfg -> in_channels_count ;
294+
295+ /* A fixed (non-zero) input count must not exceed the live source
296+ * width, otherwise sel_channel could be accepted below the
297+ * requested count yet still index past the actual stream.
298+ */
299+ if (src && cfg -> in_channels_count &&
300+ cfg -> in_channels_count > src_channels ) {
301+ comp_err (dev , "in_channels_count %u exceeds source channels %u" ,
302+ cfg -> in_channels_count , src_channels );
303+ return - EINVAL ;
304+ }
305+
306+ if (cfg -> sel_channel >= SEL_SOURCE_4CH ||
307+ (src_channels && cfg -> sel_channel >= src_channels )) {
308+ comp_err (dev , "invalid sel_channel %u (source channels %u)" ,
309+ cfg -> sel_channel , src_channels );
310+ return - EINVAL ;
311+ }
312+
244313 /* Just set the configuration */
245314 cd -> config .in_channels_count = cfg -> in_channels_count ;
246315 cd -> config .out_channels_count = cfg -> out_channels_count ;
0 commit comments