Skip to content

Commit d50363b

Browse files
singalsulgirdwood
authored andcommitted
audio: eq_iir: add 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: the size envelope, channel and response counts, each response header and biquad section bounds, and the assign_response[] entries reachable by the per-channel loop. The layout walk is factored into a shared helper that eq_iir_init_coef() also reuses at setup time, so IPC-time and prepare-time agree on structural validity; the assign_response[] check is exclusive to the IPC path, where the full table must be validated without knowing the stream channel count. The validator is installed in eq_iir_init() when the model handler is created, so every blob swap is covered - including any received while the component is in READY. The ad-hoc size helper and its runtime callers are removed since the validator now covers the size envelope in one place. Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
1 parent bb6b4b8 commit d50363b

3 files changed

Lines changed: 124 additions & 44 deletions

File tree

‎src/audio/eq_iir/eq_iir.c‎

Lines changed: 12 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ static int eq_iir_init(struct processing_module *mod)
6363
return -ENOMEM;
6464
}
6565

66+
/* Reject malformed blobs at IPC time so a bad run-time update cannot
67+
* replace the working configuration.
68+
*/
69+
comp_data_blob_set_validator(cd->model_handler, eq_iir_validate_config);
70+
6671
for (i = 0; i < PLATFORM_MAX_CHANNELS; i++)
6772
iir_reset_df1(&cd->iir[i]);
6873

@@ -107,16 +112,6 @@ static int eq_iir_get_config(struct processing_module *mod,
107112
return comp_data_blob_get_cmd(cd->model_handler, cdata, fragment_size);
108113
}
109114

110-
static int eq_iir_check_blob_size(struct comp_dev *dev, size_t size)
111-
{
112-
if (size < sizeof(struct sof_eq_iir_config) || size > SOF_EQ_IIR_MAX_SIZE) {
113-
comp_err(dev, "invalid configuration blob, size %zu", size);
114-
return -EINVAL;
115-
}
116-
117-
return 0;
118-
}
119-
120115
static int eq_iir_process(struct processing_module *mod,
121116
struct input_stream_buffer *input_buffers, int num_input_buffers,
122117
struct output_stream_buffer *output_buffers, int num_output_buffers)
@@ -127,11 +122,15 @@ static int eq_iir_process(struct processing_module *mod,
127122
uint32_t frame_count = input_buffers[0].size;
128123
int ret;
129124

130-
/* Check for changed configuration */
125+
/* Check for changed configuration. The IPC-time validator installed
126+
* in eq_iir_init() has already structurally validated the blob, so
127+
* only NULL needs to be guarded here.
128+
*/
131129
if (comp_is_new_data_blob_available(cd->model_handler)) {
132130
cd->config = comp_get_data_blob(cd->model_handler, &cd->config_size, NULL);
133-
if (!cd->config || eq_iir_check_blob_size(mod->dev, cd->config_size) < 0)
131+
if (!cd->config)
134132
return -EINVAL;
133+
135134
ret = eq_iir_new_blob(mod, audio_stream_get_frm_fmt(source),
136135
audio_stream_get_frm_fmt(sink),
137136
audio_stream_get_channels(source));
@@ -203,9 +202,7 @@ static int eq_iir_prepare(struct processing_module *mod,
203202
eq_iir_set_passthrough_func(cd, source_format, sink_format);
204203

205204
/* Initialize EQ */
206-
if (cd->config && cd->config_size > 0) {
207-
if (eq_iir_check_blob_size(dev, cd->config_size) < 0)
208-
return -EINVAL;
205+
if (cd->config) {
209206
ret = eq_iir_new_blob(mod, source_format, sink_format, channels);
210207
if (ret)
211208
return ret;

‎src/audio/eq_iir/eq_iir.h‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,5 +71,7 @@ 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, void *new_data, uint32_t new_data_size);
75+
7476
void eq_iir_free_delaylines(struct processing_module *mod);
7577
#endif /* __SOF_AUDIO_EQ_IIR_EQ_IIR_H__ */

‎src/audio/eq_iir/eq_iir_generic.c‎

Lines changed: 110 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,26 @@ static int eq_iir_blob_words_max(struct comp_dev *dev,
211211
return 0;
212212
}
213213

214+
/**
215+
* @brief Parse one response header from the coefficient blob.
216+
*
217+
* Reads the response at word offset *j in @p coef_data, checks that both
218+
* the fixed header and the following biquad sections fit inside the
219+
* @p coef_words_max blob budget, and advances *j past this response so
220+
* the next call continues where this one left off. On success @p *eq_out
221+
* is set to point at the in-place header; callers that only want to walk
222+
* the blob for validation can discard that pointer.
223+
*
224+
* @param dev Component device, used for error logging.
225+
* @param idx Response index, used in error messages.
226+
* @param coef_data Base of the coefficient word array in the blob.
227+
* @param coef_words_max Total words available in @p coef_data.
228+
* @param j In/out cursor in words; advanced past this response.
229+
* @param eq_out Out; pointer to the parsed response header.
230+
*
231+
* @return 0 on success, -EINVAL if the header or sections would run off
232+
* the end of the blob or num_sections exceeds the platform limit.
233+
*/
214234
static int eq_iir_init_response(struct comp_dev *dev, int idx,
215235
int32_t *coef_data, uint32_t coef_words_max,
216236
uint32_t *j, struct sof_eq_iir_header **eq_out)
@@ -239,59 +259,120 @@ static int eq_iir_init_response(struct comp_dev *dev, int idx,
239259
return 0;
240260
}
241261

242-
static int eq_iir_init_coef(struct processing_module *mod, int nch)
262+
/* Validate the config blob layout and, if lookup is non-NULL, populate it
263+
* with pointers to each response header. Pass lookup = NULL to validate only.
264+
*/
265+
static int eq_iir_walk_config(struct comp_dev *dev,
266+
struct sof_eq_iir_config *config,
267+
size_t config_size,
268+
struct sof_eq_iir_header **lookup)
243269
{
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];
248270
struct sof_eq_iir_header *eq;
249271
uint32_t coef_words_max;
250-
int32_t *assign_response;
251272
int32_t *coef_data;
252-
int size_sum = 0;
253-
int resp = 0;
273+
int ret;
254274
int i;
255275
uint32_t j;
256-
int s;
257-
int ret;
258-
259-
comp_info(mod->dev, "%u responses, %u channels, stream %d channels",
260-
config->number_of_responses, config->channels_in_config, nch);
261276

262-
/* Sanity checks */
263-
if (nch > PLATFORM_MAX_CHANNELS ||
264-
config->channels_in_config > PLATFORM_MAX_CHANNELS ||
277+
if (config->channels_in_config > PLATFORM_MAX_CHANNELS ||
265278
!config->channels_in_config) {
266-
comp_err(mod->dev, "invalid channels count");
279+
comp_err(dev, "invalid channels_in_config %u", config->channels_in_config);
267280
return -EINVAL;
268281
}
269282
if (config->number_of_responses > SOF_EQ_IIR_MAX_RESPONSES) {
270-
comp_err(mod->dev, "# of resp exceeds max");
283+
comp_err(dev, "# of resp %u exceeds max", config->number_of_responses);
271284
return -EINVAL;
272285
}
273286

274-
ret = eq_iir_blob_words_max(mod->dev, config, cd->config_size, &coef_words_max);
287+
ret = eq_iir_blob_words_max(dev, config, config_size, &coef_words_max);
275288
if (ret < 0)
276289
return ret;
277290

278-
/* Collect index of response start positions in all_coefficients[] */
279291
j = 0;
280-
assign_response = ASSUME_ALIGNED(&config->data[0], 4);
281292
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;
293+
if (lookup)
294+
memset(lookup, 0, SOF_EQ_IIR_MAX_RESPONSES * sizeof(*lookup));
295+
296+
for (i = 0; i < config->number_of_responses; i++) {
297+
/* Bounds-check response i, advance the walk cursor j past it,
298+
* and get a pointer to its in-place header. Stored in lookup[]
299+
* for later use, or discarded when we are walking the blob
300+
* only to validate it.
301+
*/
302+
ret = eq_iir_init_response(dev, i, coef_data, coef_words_max, &j, &eq);
303+
if (ret < 0)
304+
return ret;
305+
if (lookup)
288306
lookup[i] = eq;
289-
} else {
290-
lookup[i] = NULL;
307+
}
308+
309+
return 0;
310+
}
311+
312+
int eq_iir_validate_config(struct comp_dev *dev, void *new_data, uint32_t new_data_size)
313+
{
314+
struct sof_eq_iir_config *config = new_data;
315+
int32_t *assign_response;
316+
int32_t resp;
317+
int ret;
318+
int i;
319+
320+
if (new_data_size < sizeof(struct sof_eq_iir_config) ||
321+
new_data_size > SOF_EQ_IIR_MAX_SIZE) {
322+
comp_err(dev, "invalid configuration blob, size %u", new_data_size);
323+
return -EINVAL;
324+
}
325+
326+
ret = eq_iir_walk_config(dev, config, new_data_size, NULL);
327+
if (ret < 0)
328+
return ret;
329+
330+
/* Validate every assign_response[] entry that the per-channel loop in
331+
* eq_iir_init_coef() could pick up. Entries beyond channels_in_config
332+
* reuse the last assigned value, so checking [0, channels_in_config)
333+
* covers all reachable nch.
334+
*/
335+
assign_response = ASSUME_ALIGNED(&config->data[0], 4);
336+
for (i = 0; i < config->channels_in_config; i++) {
337+
resp = assign_response[i];
338+
if (resp >= 0 && resp >= config->number_of_responses) {
339+
comp_err(dev, "assign_response[%d] = %d exceeds %u",
340+
i, resp, config->number_of_responses);
341+
return -EINVAL;
291342
}
292343
}
293344

345+
return 0;
346+
}
347+
348+
static int eq_iir_init_coef(struct processing_module *mod, int nch)
349+
{
350+
struct comp_data *cd = module_get_private_data(mod);
351+
struct sof_eq_iir_config *config = cd->config;
352+
struct iir_state_df1 *iir = cd->iir;
353+
struct sof_eq_iir_header *lookup[SOF_EQ_IIR_MAX_RESPONSES];
354+
struct sof_eq_iir_header *eq;
355+
int32_t *assign_response;
356+
int size_sum = 0;
357+
int resp = 0;
358+
int i;
359+
int s;
360+
int ret;
361+
362+
comp_info(mod->dev, "%u responses, %u channels, stream %d channels",
363+
config->number_of_responses, config->channels_in_config, nch);
364+
365+
if (nch > PLATFORM_MAX_CHANNELS) {
366+
comp_err(mod->dev, "invalid stream channels %d", nch);
367+
return -EINVAL;
368+
}
369+
370+
ret = eq_iir_walk_config(mod->dev, config, cd->config_size, lookup);
371+
if (ret < 0)
372+
return ret;
373+
294374
/* Initialize 1st phase */
375+
assign_response = ASSUME_ALIGNED(&config->data[0], 4);
295376
for (i = 0; i < nch; i++) {
296377
/* Check for not reading past blob response to channel assign
297378
* map. The previous channel response is assigned for any

0 commit comments

Comments
 (0)