@@ -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+ }
375+
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+ }
360383
361- if (size > SOF_CROSSOVER_MAX_SIZE || !size ) {
362- comp_err (dev , "size %d is invalid" , size );
384+ size = config -> size ;
385+ if (size > SOF_CROSSOVER_MAX_SIZE || !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,37 @@ 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+ if (crossover_validate_config (mod , cfg_size ) < 0 ) {
501+ comp_err (dev , "invalid runtime config blob" );
502+ return - EINVAL ;
503+ }
504+
505+ /* num_sinks must not change at runtime: cd->crossover_split was
506+ * selected for the previous count, and a smaller value would
507+ * cause the split function to write past the sink array.
508+ * Reject the blob; the previous config and split stay in use.
509+ */
510+ if (prev_num_sinks && cd -> config -> num_sinks != prev_num_sinks ) {
511+ comp_err (dev , "runtime num_sinks change %u -> %u not supported" ,
512+ prev_num_sinks , cd -> config -> num_sinks );
513+ cd -> config = prev_config ;
514+ return - EINVAL ;
515+ }
516+
459517 ret = crossover_setup (mod , audio_stream_get_channels (source ));
460518 if (ret < 0 ) {
461519 comp_err (dev , "failed Crossover setup" );
@@ -545,10 +603,11 @@ 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 */
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 && crossover_validate_config (mod , data_size ) < 0 ) {
552611 comp_err (dev , "invalid binary config format" );
553612 return - EINVAL ;
554613 }
0 commit comments