Skip to content

Commit fc63c5e

Browse files
committed
audio: eq_fir: Improve robustness for invalid configuration
Validate the IPC configuration blob to prevent out-of-bounds reads when walking FIR coefficient sections: - Store the blob length in struct comp_data and bound it to [sizeof(*cd->config), SOF_EQ_FIR_MAX_SIZE] in eq_fir_prepare() and on the runtime new-blob path in eq_fir_process(). - Pass the size into eq_fir_init_coef() and cross-check it against config->size; reject blobs too small to hold the assign_response vector. - Derive a per-blob coef_words_max budget from config->size and, for each response, check the FIR header fits before reading eq->length, then reject lengths that are non-positive, exceed SOF_FIR_MAX_LENGTH, are not a multiple of 4, or overrun the blob. - eq_fir_validator() now forwards new_data_size for the size match. Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
1 parent bd296e4 commit fc63c5e

2 files changed

Lines changed: 58 additions & 10 deletions

File tree

src/audio/eq_fir/eq_fir.c

Lines changed: 57 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

@@ -236,7 +271,7 @@ static int eq_fir_setup(struct processing_module *mod, int nch)
236271

237272
static int eq_fir_validator(struct comp_dev *dev, void *new_data, uint32_t new_data_size)
238273
{
239-
return eq_fir_init_coef(dev, new_data, NULL, -1);
274+
return eq_fir_init_coef(dev, new_data, new_data_size, NULL, -1);
240275
}
241276

242277
/*
@@ -332,7 +367,13 @@ static int eq_fir_process(struct processing_module *mod,
332367

333368
/* Check for changed configuration */
334369
if (comp_is_new_data_blob_available(cd->model_handler)) {
335-
cd->config = comp_get_data_blob(cd->model_handler, NULL, NULL);
370+
cd->config = comp_get_data_blob(cd->model_handler, &cd->config_size, NULL);
371+
if (!cd->config || cd->config_size < sizeof(*cd->config) ||
372+
cd->config_size > SOF_EQ_FIR_MAX_SIZE) {
373+
comp_err(mod->dev, "invalid configuration blob, size %zu",
374+
cd->config_size);
375+
return -EINVAL;
376+
}
336377
ret = eq_fir_setup(mod, audio_stream_get_channels(source));
337378
if (ret < 0) {
338379
comp_err(mod->dev, "failed FIR setup");
@@ -384,7 +425,6 @@ static int eq_fir_prepare(struct processing_module *mod,
384425
int channels;
385426
enum sof_ipc_frame frame_fmt;
386427
int ret = 0;
387-
size_t data_size;
388428

389429
comp_dbg(dev, "entry");
390430

@@ -407,8 +447,15 @@ static int eq_fir_prepare(struct processing_module *mod,
407447
frame_fmt = audio_stream_get_frm_fmt(&sourceb->stream);
408448

409449
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) {
450+
cd->config = comp_get_data_blob(cd->model_handler, &cd->config_size, NULL);
451+
if (cd->config) {
452+
if (cd->config_size < sizeof(*cd->config) ||
453+
cd->config_size > SOF_EQ_FIR_MAX_SIZE) {
454+
comp_err(dev, "invalid configuration blob, size %zu",
455+
cd->config_size);
456+
comp_set_state(dev, COMP_TRIGGER_RESET);
457+
return -EINVAL;
458+
}
412459
ret = eq_fir_setup(mod, channels);
413460
if (ret < 0)
414461
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)