Skip to content

Commit d7f2304

Browse files
committed
audio: eq_iir: Improve robustness for invalid configuration
Harden the EQ IIR 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 num_sections from the blob now bounds the header and biquad data against the blob, so a bad length can no longer push the lookup pointer past the allocation. The df1 and df2t delay-size helpers also gained a range check on num_sections_in_series, which strides the delay line and was previously unchecked. Signed-off-by: Seppo Ingalsuo <seppo.ingalsuo@linux.intel.com>
1 parent bd296e4 commit d7f2304

5 files changed

Lines changed: 105 additions & 15 deletions

File tree

src/audio/eq_iir/eq_iir.c

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,16 @@ static int eq_iir_get_config(struct processing_module *mod,
107107
return comp_data_blob_get_cmd(cd->model_handler, cdata, fragment_size);
108108
}
109109

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+
110120
static int eq_iir_process(struct processing_module *mod,
111121
struct input_stream_buffer *input_buffers, int num_input_buffers,
112122
struct output_stream_buffer *output_buffers, int num_output_buffers)
@@ -119,7 +129,9 @@ static int eq_iir_process(struct processing_module *mod,
119129

120130
/* Check for changed configuration */
121131
if (comp_is_new_data_blob_available(cd->model_handler)) {
122-
cd->config = comp_get_data_blob(cd->model_handler, NULL, NULL);
132+
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)
134+
return -EINVAL;
123135
ret = eq_iir_new_blob(mod, audio_stream_get_frm_fmt(source),
124136
audio_stream_get_frm_fmt(sink),
125137
audio_stream_get_channels(source));
@@ -158,7 +170,6 @@ static int eq_iir_prepare(struct processing_module *mod,
158170
struct comp_dev *dev = mod->dev;
159171
enum sof_ipc_frame source_format;
160172
enum sof_ipc_frame sink_format;
161-
size_t data_size;
162173
int channels;
163174
int ret = 0;
164175

@@ -183,7 +194,7 @@ static int eq_iir_prepare(struct processing_module *mod,
183194
source_format = audio_stream_get_frm_fmt(&sourceb->stream);
184195
sink_format = audio_stream_get_frm_fmt(&sinkb->stream);
185196

186-
cd->config = comp_get_data_blob(cd->model_handler, &data_size, NULL);
197+
cd->config = comp_get_data_blob(cd->model_handler, &cd->config_size, NULL);
187198

188199
/* Initialize EQ */
189200
comp_info(dev, "source_format=%d, sink_format=%d",
@@ -192,7 +203,9 @@ static int eq_iir_prepare(struct processing_module *mod,
192203
eq_iir_set_passthrough_func(cd, source_format, sink_format);
193204

194205
/* Initialize EQ */
195-
if (cd->config && data_size > 0) {
206+
if (cd->config && cd->config_size > 0) {
207+
if (eq_iir_check_blob_size(dev, cd->config_size) < 0)
208+
return -EINVAL;
196209
ret = eq_iir_new_blob(mod, source_format, sink_format, channels);
197210
if (ret)
198211
return ret;

src/audio/eq_iir/eq_iir.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ struct comp_data {
3939
struct comp_data_blob_handler *model_handler;
4040
struct sof_eq_iir_config *config;
4141
int32_t *iir_delay; /**< pointer to allocated RAM */
42+
size_t config_size; /**< configuration size */
4243
size_t iir_delay_size; /**< allocated size */
4344
eq_iir_func eq_iir_func; /**< processing function */
4445
};

src/audio/eq_iir/eq_iir_generic.c

Lines changed: 75 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -180,20 +180,81 @@ void eq_iir_s32_default(struct processing_module *mod, struct input_stream_buffe
180180
}
181181
#endif /* CONFIG_FORMAT_S32LE */
182182

183+
static int eq_iir_blob_words_max(struct comp_dev *dev,
184+
const struct sof_eq_iir_config *config,
185+
size_t blob_size,
186+
uint32_t *coef_words_max)
187+
{
188+
size_t payload_bytes;
189+
190+
/* Compute the size of the coefficient area in int32_t words from the
191+
* framework-reported blob size. The blob layout is:
192+
* sizeof(*config) header bytes
193+
* channels_in_config int32_t assign_response[]
194+
* coefficient data[]
195+
* channels_in_config is bounded above, so the multiply fits in size_t.
196+
* The blob's self-declared config->size is cross-checked against the
197+
* authoritative blob_size so all later parsing stays within the buffer.
198+
*/
199+
if (blob_size < sizeof(*config) || config->size != blob_size) {
200+
comp_err(dev, "blob size %zu / header size %u mismatch or too small",
201+
blob_size, config->size);
202+
return -EINVAL;
203+
}
204+
payload_bytes = blob_size - sizeof(*config);
205+
if (payload_bytes % sizeof(int32_t) ||
206+
payload_bytes < (size_t)config->channels_in_config * sizeof(int32_t)) {
207+
comp_err(dev, "blob size %zu misaligned or too small", blob_size);
208+
return -EINVAL;
209+
}
210+
*coef_words_max = payload_bytes / sizeof(int32_t) - config->channels_in_config;
211+
return 0;
212+
}
213+
214+
static int eq_iir_init_response(struct comp_dev *dev, int idx,
215+
int32_t *coef_data, uint32_t coef_words_max,
216+
uint32_t *j, struct sof_eq_iir_header **eq_out)
217+
{
218+
struct sof_eq_iir_header *eq;
219+
uint32_t header_end = *j + SOF_EQ_IIR_NHEADER;
220+
uint32_t section_end;
221+
222+
/* Header must fit before reading num_sections */
223+
if (header_end > coef_words_max) {
224+
comp_err(dev, "response %d header out of bounds", idx);
225+
return -EINVAL;
226+
}
227+
eq = (struct sof_eq_iir_header *)&coef_data[*j];
228+
/* Bound num_sections so the multiply cannot overflow and the section
229+
* data stays within the blob.
230+
*/
231+
section_end = header_end + (uint32_t)SOF_EQ_IIR_NBIQUAD * eq->num_sections;
232+
if (eq->num_sections > SOF_EQ_IIR_BIQUADS_MAX || section_end > coef_words_max) {
233+
comp_err(dev, "response %d num_sections %u out of bounds",
234+
idx, eq->num_sections);
235+
return -EINVAL;
236+
}
237+
*eq_out = eq;
238+
*j = section_end;
239+
return 0;
240+
}
241+
183242
static int eq_iir_init_coef(struct processing_module *mod, int nch)
184243
{
185244
struct comp_data *cd = module_get_private_data(mod);
186245
struct sof_eq_iir_config *config = cd->config;
187246
struct iir_state_df1 *iir = cd->iir;
188247
struct sof_eq_iir_header *lookup[SOF_EQ_IIR_MAX_RESPONSES];
189248
struct sof_eq_iir_header *eq;
249+
uint32_t coef_words_max;
190250
int32_t *assign_response;
191251
int32_t *coef_data;
192252
int size_sum = 0;
193253
int resp = 0;
194254
int i;
195-
int j;
255+
uint32_t j;
196256
int s;
257+
int ret;
197258

198259
comp_info(mod->dev, "%u responses, %u channels, stream %d channels",
199260
config->number_of_responses, config->channels_in_config, nch);
@@ -210,17 +271,21 @@ static int eq_iir_init_coef(struct processing_module *mod, int nch)
210271
return -EINVAL;
211272
}
212273

274+
ret = eq_iir_blob_words_max(mod->dev, config, cd->config_size, &coef_words_max);
275+
if (ret < 0)
276+
return ret;
277+
213278
/* Collect index of response start positions in all_coefficients[] */
214279
j = 0;
215280
assign_response = ASSUME_ALIGNED(&config->data[0], 4);
216-
coef_data = ASSUME_ALIGNED(&config->data[config->channels_in_config],
217-
4);
281+
coef_data = ASSUME_ALIGNED(&config->data[config->channels_in_config], 4);
218282
for (i = 0; i < SOF_EQ_IIR_MAX_RESPONSES; i++) {
219283
if (i < config->number_of_responses) {
220-
eq = (struct sof_eq_iir_header *)&coef_data[j];
284+
ret = eq_iir_init_response(mod->dev, i, coef_data,
285+
coef_words_max, &j, &eq);
286+
if (ret < 0)
287+
return ret;
221288
lookup[i] = eq;
222-
j += SOF_EQ_IIR_NHEADER
223-
+ SOF_EQ_IIR_NBIQUAD * eq->num_sections;
224289
} else {
225290
lookup[i] = NULL;
226291
}
@@ -318,7 +383,10 @@ int eq_iir_setup(struct processing_module *mod, int nch)
318383
/* Free existing IIR channels data if it was allocated */
319384
eq_iir_free_delaylines(mod);
320385

321-
/* Set coefficients for each channel EQ from coefficient blob */
386+
/* Set coefficients for each channel EQ from coefficient blob.
387+
* eq_iir_init_coef() / eq_iir_blob_words_max() perform all blob size
388+
* sanity checks, including config->size vs cd->config_size.
389+
*/
322390
delay_size = eq_iir_init_coef(mod, nch);
323391
if (delay_size < 0)
324392
return delay_size; /* Contains error code */

src/math/iir_df1.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,13 @@
1616

1717
int iir_delay_size_df1(struct sof_eq_iir_header *config)
1818
{
19-
int n = config->num_sections; /* One section uses two unit delays */
19+
uint32_t n = config->num_sections; /* One section uses four unit delays */
2020

21-
if (n > SOF_EQ_IIR_BIQUADS_MAX || n < 1)
21+
if (!n || n > SOF_EQ_IIR_BIQUADS_MAX)
22+
return -EINVAL;
23+
24+
if (!config->num_sections_in_series ||
25+
config->num_sections_in_series > n)
2226
return -EINVAL;
2327

2428
return 4 * n * sizeof(int32_t);

src/math/iir_df2t.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,13 @@
1616

1717
int iir_delay_size_df2t(struct sof_eq_iir_header *config)
1818
{
19-
int n = config->num_sections; /* One section uses two unit delays */
19+
uint32_t n = config->num_sections; /* One section uses two unit delays */
2020

21-
if (n > SOF_EQ_IIR_BIQUADS_MAX || n < 1)
21+
if (!n || n > SOF_EQ_IIR_BIQUADS_MAX)
22+
return -EINVAL;
23+
24+
if (!config->num_sections_in_series ||
25+
config->num_sections_in_series > n)
2226
return -EINVAL;
2327

2428
return 2 * n * sizeof(int64_t);

0 commit comments

Comments
 (0)