Skip to content

Commit abf857f

Browse files
committed
audio: eq_fir: Improve robustness for invalid configuration
Harden the EQ FIR setup path against malformed IPC configuration blobs. The blob length returned by comp_get_data_blob() is now stored and checked against the expected range every time a new blob is taken, and the blob's self-declared size is cross-checked against it before use. The per-response walk that previously trusted the FIR length field from the blob now bounds the header and coefficient data against the blob, and rejects lengths that are non-positive, exceed SOF_FIR_MAX_LENGTH or are not a multiple of four. The IPC validator applies the same blob length bounds before calling into eq_fir_init_coef(), so an oversized or truncated blob is rejected up front rather than at prepare or process time. Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
1 parent bd296e4 commit abf857f

2 files changed

Lines changed: 66 additions & 10 deletions

File tree

src/audio/eq_fir/eq_fir.c

Lines changed: 65 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -72,12 +72,13 @@ static void eq_fir_free_delaylines(struct processing_module *mod)
7272
}
7373

7474
static int eq_fir_init_coef(struct comp_dev *dev, struct sof_eq_fir_config *config,
75-
struct fir_state_32x16 *fir, int nch)
75+
size_t config_size, struct fir_state_32x16 *fir, int nch)
7676
{
7777
struct sof_fir_coef_data *lookup[SOF_EQ_FIR_MAX_RESPONSES];
7878
struct sof_fir_coef_data *eq;
7979
int16_t *assign_response;
8080
int16_t *coef_data;
81+
size_t coef_words_max;
8182
size_t size_sum = 0;
8283
int resp = 0;
8384
int i;
@@ -101,6 +102,11 @@ static int eq_fir_init_coef(struct comp_dev *dev, struct sof_eq_fir_config *conf
101102
config->number_of_responses, config->channels_in_config, nch);
102103

103104
/* Sanity checks */
105+
if (config->size != config_size) {
106+
comp_err(dev, "Incorrect configuration blob size");
107+
return -EINVAL;
108+
}
109+
104110
if (nch > PLATFORM_MAX_CHANNELS ||
105111
config->channels_in_config > PLATFORM_MAX_CHANNELS ||
106112
!config->channels_in_config) {
@@ -112,16 +118,45 @@ static int eq_fir_init_coef(struct comp_dev *dev, struct sof_eq_fir_config *conf
112118
return -EINVAL;
113119
}
114120

121+
/* Compute the size of the coefficient area in int16_t words from the
122+
* blob's self-declared size. The blob layout is:
123+
* sizeof(*config) header bytes
124+
* channels_in_config int16_t assign_response[]
125+
* coefficient data[]
126+
*/
127+
if (config->size < sizeof(*config) ||
128+
config->size - sizeof(*config) <
129+
(size_t)config->channels_in_config * sizeof(int16_t)) {
130+
comp_err(dev, "config size %u too small", config->size);
131+
return -EINVAL;
132+
}
133+
coef_words_max = (config->size - sizeof(*config)) / sizeof(int16_t) -
134+
config->channels_in_config;
135+
115136
/* Collect index of response start positions in all_coefficients[] */
116137
j = 0;
117138
assign_response = ASSUME_ALIGNED(&config->data[0], 4);
118-
coef_data = ASSUME_ALIGNED(&config->data[config->channels_in_config],
119-
4);
139+
coef_data = ASSUME_ALIGNED(&config->data[config->channels_in_config], 4);
120140
for (i = 0; i < SOF_EQ_FIR_MAX_RESPONSES; i++) {
121141
if (i < config->number_of_responses) {
142+
/* Header must fit before reading length */
143+
if (j + SOF_FIR_COEF_NHEADER > coef_words_max) {
144+
comp_err(dev, "response %d header out of bounds", i);
145+
return -EINVAL;
146+
}
122147
eq = (struct sof_fir_coef_data *)&coef_data[j];
148+
/* Bound length so it is valid and the coefficient data
149+
* stays within the blob.
150+
*/
151+
if (eq->length <= 0 || eq->length > SOF_FIR_MAX_LENGTH ||
152+
(eq->length & 0x3) ||
153+
j + SOF_FIR_COEF_NHEADER + eq->length > coef_words_max) {
154+
comp_err(dev, "response %d length %d out of bounds",
155+
i, eq->length);
156+
return -EINVAL;
157+
}
123158
lookup[i] = eq;
124-
j += SOF_FIR_COEF_NHEADER + coef_data[j];
159+
j += SOF_FIR_COEF_NHEADER + eq->length;
125160
} else {
126161
lookup[i] = NULL;
127162
}
@@ -209,7 +244,7 @@ static int eq_fir_setup(struct processing_module *mod, int nch)
209244
cd->nch = nch;
210245

211246
/* Set coefficients for each channel EQ from coefficient blob */
212-
delay_size = eq_fir_init_coef(dev, cd->config, cd->fir, nch);
247+
delay_size = eq_fir_init_coef(dev, cd->config, cd->config_size, cd->fir, nch);
213248
if (delay_size < 0)
214249
return delay_size; /* Contains error code */
215250

@@ -234,9 +269,25 @@ static int eq_fir_setup(struct processing_module *mod, int nch)
234269
return 0;
235270
}
236271

272+
static int eq_fir_check_blob_size(struct comp_dev *dev, size_t size)
273+
{
274+
if (size < sizeof(struct sof_eq_fir_config) || size > SOF_EQ_FIR_MAX_SIZE) {
275+
comp_err(dev, "invalid configuration blob, size %zu", size);
276+
return -EINVAL;
277+
}
278+
279+
return 0;
280+
}
281+
237282
static int eq_fir_validator(struct comp_dev *dev, void *new_data, uint32_t new_data_size)
238283
{
239-
return eq_fir_init_coef(dev, new_data, NULL, -1);
284+
int ret;
285+
286+
ret = eq_fir_check_blob_size(dev, new_data_size);
287+
if (ret < 0)
288+
return ret;
289+
290+
return eq_fir_init_coef(dev, new_data, new_data_size, NULL, -1);
240291
}
241292

242293
/*
@@ -332,7 +383,9 @@ static int eq_fir_process(struct processing_module *mod,
332383

333384
/* Check for changed configuration */
334385
if (comp_is_new_data_blob_available(cd->model_handler)) {
335-
cd->config = comp_get_data_blob(cd->model_handler, NULL, NULL);
386+
cd->config = comp_get_data_blob(cd->model_handler, &cd->config_size, NULL);
387+
if (!cd->config || eq_fir_check_blob_size(mod->dev, cd->config_size) < 0)
388+
return -EINVAL;
336389
ret = eq_fir_setup(mod, audio_stream_get_channels(source));
337390
if (ret < 0) {
338391
comp_err(mod->dev, "failed FIR setup");
@@ -384,7 +437,6 @@ static int eq_fir_prepare(struct processing_module *mod,
384437
int channels;
385438
enum sof_ipc_frame frame_fmt;
386439
int ret = 0;
387-
size_t data_size;
388440

389441
comp_dbg(dev, "entry");
390442

@@ -407,8 +459,11 @@ static int eq_fir_prepare(struct processing_module *mod,
407459
frame_fmt = audio_stream_get_frm_fmt(&sourceb->stream);
408460

409461
cd->eq_fir_func = eq_fir_passthrough;
410-
cd->config = comp_get_data_blob(cd->model_handler, &data_size, NULL);
411-
if (cd->config && data_size > 0) {
462+
cd->config = comp_get_data_blob(cd->model_handler, &cd->config_size, NULL);
463+
if (cd->config) {
464+
if (eq_fir_check_blob_size(dev, cd->config_size) < 0)
465+
return -EINVAL;
466+
412467
ret = eq_fir_setup(mod, channels);
413468
if (ret < 0)
414469
comp_err(dev, "eq_fir_setup failed.");

src/audio/eq_fir/eq_fir.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ struct comp_data {
3636
struct comp_data_blob_handler *model_handler;
3737
struct sof_eq_fir_config *config;
3838
int32_t *fir_delay; /**< pointer to allocated RAM */
39+
size_t config_size; /**< configuration size */
3940
size_t fir_delay_size; /**< allocated size */
4041
void (*eq_fir_func)(struct fir_state_32x16 fir[],
4142
struct input_stream_buffer *bsource,

0 commit comments

Comments
 (0)