Skip to content

Commit db4e659

Browse files
committed
audio: eq_iir: register IPC-time blob validator
Hook an eq_iir blob validator into the model handler so a corrupted run-time configuration update is rejected before it can replace the working blob. Playback or capture then continues with the previously set coefficients instead of being interrupted by a bad IPC. The validator parses the blob layout end to end: channel and response counts, each response header and biquad section bounds, and the assign_response[] entries reachable by the per-channel loop. The walk is factored into a shared helper that eq_iir_init_coef() also reuses at setup time, so IPC-time and prepare-time use exactly the same checks. Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
1 parent 8efd7e3 commit db4e659

3 files changed

Lines changed: 107 additions & 29 deletions

File tree

src/audio/eq_iir/eq_iir.c

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,17 @@ static int eq_iir_check_blob_size(struct comp_dev *dev, size_t size)
117117
return 0;
118118
}
119119

120+
static int eq_iir_validator(struct comp_dev *dev, void *new_data, uint32_t new_data_size)
121+
{
122+
int ret;
123+
124+
ret = eq_iir_check_blob_size(dev, new_data_size);
125+
if (ret < 0)
126+
return ret;
127+
128+
return eq_iir_validate_config(dev, new_data, new_data_size);
129+
}
130+
120131
static int eq_iir_process(struct processing_module *mod,
121132
struct input_stream_buffer *input_buffers, int num_input_buffers,
122133
struct output_stream_buffer *output_buffers, int num_output_buffers)
@@ -127,7 +138,11 @@ static int eq_iir_process(struct processing_module *mod,
127138
uint32_t frame_count = input_buffers[0].size;
128139
int ret;
129140

130-
/* Check for changed configuration */
141+
/* Check for changed configuration. Note that the IPC-time validator set
142+
* in eq_iir_prepare() already runs eq_iir_check_blob_size() and
143+
* eq_iir_validate_config() on every blob, so the next check is not
144+
* mandatory.
145+
*/
131146
if (comp_is_new_data_blob_available(cd->model_handler)) {
132147
cd->config = comp_get_data_blob(cd->model_handler, &cd->config_size, NULL);
133148
if (!cd->config || eq_iir_check_blob_size(mod->dev, cd->config_size) < 0)
@@ -216,6 +231,11 @@ static int eq_iir_prepare(struct processing_module *mod,
216231
ret = -EINVAL;
217232
}
218233

234+
/* Reject malformed blobs at IPC time so a bad run-time update cannot
235+
* replace the working configuration.
236+
*/
237+
comp_data_blob_set_validator(cd->model_handler, eq_iir_validator);
238+
219239
return ret;
220240
}
221241

@@ -224,6 +244,8 @@ static int eq_iir_reset(struct processing_module *mod)
224244
struct comp_data *cd = module_get_private_data(mod);
225245
int i;
226246

247+
comp_data_blob_set_validator(cd->model_handler, NULL);
248+
227249
eq_iir_free_delaylines(mod);
228250

229251
cd->eq_iir_func = NULL;

src/audio/eq_iir/eq_iir.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,5 +71,9 @@ void eq_iir_pass(struct processing_module *mod, struct input_stream_buffer *bsou
7171

7272
int eq_iir_setup(struct processing_module *mod, int nch);
7373

74+
int eq_iir_validate_config(struct comp_dev *dev,
75+
struct sof_eq_iir_config *config,
76+
size_t config_size);
77+
7478
void eq_iir_free_delaylines(struct processing_module *mod);
7579
#endif /* __SOF_AUDIO_EQ_IIR_EQ_IIR_H__ */

src/audio/eq_iir/eq_iir_generic.c

Lines changed: 80 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -239,59 +239,111 @@ static int eq_iir_init_response(struct comp_dev *dev, int idx,
239239
return 0;
240240
}
241241

242-
static int eq_iir_init_coef(struct processing_module *mod, int nch)
242+
/* Validate the config blob layout and, if lookup is non-NULL, populate it
243+
* with pointers to each response header. Pass lookup = NULL to validate only.
244+
*/
245+
static int eq_iir_walk_config(struct comp_dev *dev,
246+
struct sof_eq_iir_config *config,
247+
size_t config_size,
248+
struct sof_eq_iir_header **lookup)
243249
{
244-
struct comp_data *cd = module_get_private_data(mod);
245-
struct sof_eq_iir_config *config = cd->config;
246-
struct iir_state_df1 *iir = cd->iir;
247-
struct sof_eq_iir_header *lookup[SOF_EQ_IIR_MAX_RESPONSES];
248250
struct sof_eq_iir_header *eq;
249251
uint32_t coef_words_max;
250-
int32_t *assign_response;
251252
int32_t *coef_data;
252-
int size_sum = 0;
253-
int resp = 0;
253+
int ret;
254254
int i;
255255
uint32_t j;
256-
int s;
257-
int ret;
258256

259-
comp_info(mod->dev, "%u responses, %u channels, stream %d channels",
260-
config->number_of_responses, config->channels_in_config, nch);
261-
262-
/* Sanity checks */
263-
if (nch > PLATFORM_MAX_CHANNELS ||
264-
config->channels_in_config > PLATFORM_MAX_CHANNELS ||
257+
if (config->channels_in_config > PLATFORM_MAX_CHANNELS ||
265258
!config->channels_in_config) {
266-
comp_err(mod->dev, "invalid channels count");
259+
comp_err(dev, "invalid channels_in_config %u", config->channels_in_config);
267260
return -EINVAL;
268261
}
269262
if (config->number_of_responses > SOF_EQ_IIR_MAX_RESPONSES) {
270-
comp_err(mod->dev, "# of resp exceeds max");
263+
comp_err(dev, "# of resp %u exceeds max", config->number_of_responses);
271264
return -EINVAL;
272265
}
273266

274-
ret = eq_iir_blob_words_max(mod->dev, config, cd->config_size, &coef_words_max);
267+
ret = eq_iir_blob_words_max(dev, config, config_size, &coef_words_max);
275268
if (ret < 0)
276269
return ret;
277270

278-
/* Collect index of response start positions in all_coefficients[] */
279271
j = 0;
280-
assign_response = ASSUME_ALIGNED(&config->data[0], 4);
281272
coef_data = ASSUME_ALIGNED(&config->data[config->channels_in_config], 4);
282-
for (i = 0; i < SOF_EQ_IIR_MAX_RESPONSES; i++) {
283-
if (i < config->number_of_responses) {
284-
ret = eq_iir_init_response(mod->dev, i, coef_data,
285-
coef_words_max, &j, &eq);
286-
if (ret < 0)
287-
return ret;
273+
for (i = 0; i < config->number_of_responses; i++) {
274+
ret = eq_iir_init_response(dev, i, coef_data, coef_words_max, &j, &eq);
275+
if (ret < 0)
276+
return ret;
277+
if (lookup)
288278
lookup[i] = eq;
289-
} else {
279+
}
280+
if (lookup) {
281+
for (; i < SOF_EQ_IIR_MAX_RESPONSES; i++)
290282
lookup[i] = NULL;
283+
}
284+
285+
return 0;
286+
}
287+
288+
int eq_iir_validate_config(struct comp_dev *dev,
289+
struct sof_eq_iir_config *config,
290+
size_t config_size)
291+
{
292+
int32_t *assign_response;
293+
int32_t resp;
294+
int ret;
295+
int i;
296+
297+
ret = eq_iir_walk_config(dev, config, config_size, NULL);
298+
if (ret < 0)
299+
return ret;
300+
301+
/* Validate every assign_response[] entry that the per-channel loop in
302+
* eq_iir_init_coef() could pick up. Entries beyond channels_in_config
303+
* reuse the last assigned value, so checking [0, channels_in_config)
304+
* covers all reachable nch.
305+
*/
306+
assign_response = ASSUME_ALIGNED(&config->data[0], 4);
307+
for (i = 0; i < config->channels_in_config; i++) {
308+
resp = assign_response[i];
309+
if (resp >= 0 && resp >= config->number_of_responses) {
310+
comp_err(dev, "assign_response[%d] = %d exceeds %u",
311+
i, resp, config->number_of_responses);
312+
return -EINVAL;
291313
}
292314
}
293315

316+
return 0;
317+
}
318+
319+
static int eq_iir_init_coef(struct processing_module *mod, int nch)
320+
{
321+
struct comp_data *cd = module_get_private_data(mod);
322+
struct sof_eq_iir_config *config = cd->config;
323+
struct iir_state_df1 *iir = cd->iir;
324+
struct sof_eq_iir_header *lookup[SOF_EQ_IIR_MAX_RESPONSES];
325+
struct sof_eq_iir_header *eq;
326+
int32_t *assign_response;
327+
int size_sum = 0;
328+
int resp = 0;
329+
int i;
330+
int s;
331+
int ret;
332+
333+
comp_info(mod->dev, "%u responses, %u channels, stream %d channels",
334+
config->number_of_responses, config->channels_in_config, nch);
335+
336+
if (nch > PLATFORM_MAX_CHANNELS) {
337+
comp_err(mod->dev, "invalid stream channels %d", nch);
338+
return -EINVAL;
339+
}
340+
341+
ret = eq_iir_walk_config(mod->dev, config, cd->config_size, lookup);
342+
if (ret < 0)
343+
return ret;
344+
294345
/* Initialize 1st phase */
346+
assign_response = ASSUME_ALIGNED(&config->data[0], 4);
295347
for (i = 0; i < nch; i++) {
296348
/* Check for not reading past blob response to channel assign
297349
* map. The previous channel response is assigned for any

0 commit comments

Comments
 (0)