Skip to content

Commit 70f36e5

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 70f36e5

5 files changed

Lines changed: 102 additions & 14 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: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -180,20 +180,77 @@ 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+
uint32_t *coef_words_max)
186+
{
187+
size_t payload_bytes;
188+
189+
/* Compute the size of the coefficient area in int32_t words from the
190+
* blob's self-declared size. The blob layout is:
191+
* sizeof(*config) header bytes
192+
* channels_in_config int32_t assign_response[]
193+
* coefficient data[]
194+
* channels_in_config is bounded above, so the multiply fits in size_t.
195+
*/
196+
if (config->size < sizeof(*config)) {
197+
comp_err(dev, "config size %u too small", config->size);
198+
return -EINVAL;
199+
}
200+
payload_bytes = config->size - sizeof(*config);
201+
if (payload_bytes % sizeof(int32_t) ||
202+
payload_bytes < (size_t)config->channels_in_config * sizeof(int32_t)) {
203+
comp_err(dev, "config size %u misaligned or too small", config->size);
204+
return -EINVAL;
205+
}
206+
*coef_words_max = payload_bytes / sizeof(int32_t) - config->channels_in_config;
207+
return 0;
208+
}
209+
210+
static int eq_iir_init_response(struct comp_dev *dev, int idx,
211+
int32_t *coef_data, uint32_t coef_words_max,
212+
uint32_t *j, struct sof_eq_iir_header **eq_out)
213+
{
214+
struct sof_eq_iir_header *eq;
215+
uint32_t header_end = *j + SOF_EQ_IIR_NHEADER;
216+
uint32_t section_end;
217+
218+
/* Header must fit before reading num_sections */
219+
if (header_end > coef_words_max) {
220+
comp_err(dev, "response %d header out of bounds", idx);
221+
return -EINVAL;
222+
}
223+
eq = (struct sof_eq_iir_header *)&coef_data[*j];
224+
/* Bound num_sections so the multiply cannot overflow and the section
225+
* data stays within the blob.
226+
*/
227+
section_end = header_end + (uint32_t)SOF_EQ_IIR_NBIQUAD * eq->num_sections;
228+
if (eq->num_sections > SOF_EQ_IIR_BIQUADS_MAX || section_end > coef_words_max) {
229+
comp_err(dev, "response %d num_sections %u out of bounds",
230+
idx, eq->num_sections);
231+
return -EINVAL;
232+
}
233+
*eq_out = eq;
234+
*j = section_end;
235+
return 0;
236+
}
237+
183238
static int eq_iir_init_coef(struct processing_module *mod, int nch)
184239
{
185240
struct comp_data *cd = module_get_private_data(mod);
186241
struct sof_eq_iir_config *config = cd->config;
187242
struct iir_state_df1 *iir = cd->iir;
188243
struct sof_eq_iir_header *lookup[SOF_EQ_IIR_MAX_RESPONSES];
189244
struct sof_eq_iir_header *eq;
245+
uint32_t coef_words_max;
190246
int32_t *assign_response;
191247
int32_t *coef_data;
192248
int size_sum = 0;
193249
int resp = 0;
194250
int i;
195-
int j;
251+
uint32_t j;
196252
int s;
253+
int ret;
197254

198255
comp_info(mod->dev, "%u responses, %u channels, stream %d channels",
199256
config->number_of_responses, config->channels_in_config, nch);
@@ -210,17 +267,21 @@ static int eq_iir_init_coef(struct processing_module *mod, int nch)
210267
return -EINVAL;
211268
}
212269

270+
ret = eq_iir_blob_words_max(mod->dev, config, &coef_words_max);
271+
if (ret < 0)
272+
return ret;
273+
213274
/* Collect index of response start positions in all_coefficients[] */
214275
j = 0;
215276
assign_response = ASSUME_ALIGNED(&config->data[0], 4);
216-
coef_data = ASSUME_ALIGNED(&config->data[config->channels_in_config],
217-
4);
277+
coef_data = ASSUME_ALIGNED(&config->data[config->channels_in_config], 4);
218278
for (i = 0; i < SOF_EQ_IIR_MAX_RESPONSES; i++) {
219279
if (i < config->number_of_responses) {
220-
eq = (struct sof_eq_iir_header *)&coef_data[j];
280+
ret = eq_iir_init_response(mod->dev, i, coef_data,
281+
coef_words_max, &j, &eq);
282+
if (ret < 0)
283+
return ret;
221284
lookup[i] = eq;
222-
j += SOF_EQ_IIR_NHEADER
223-
+ SOF_EQ_IIR_NBIQUAD * eq->num_sections;
224285
} else {
225286
lookup[i] = NULL;
226287
}
@@ -315,6 +376,11 @@ int eq_iir_setup(struct processing_module *mod, int nch)
315376
struct comp_data *cd = module_get_private_data(mod);
316377
int delay_size;
317378

379+
if (cd->config->size != cd->config_size) {
380+
comp_err(mod->dev, "Incorrect configuration blob size");
381+
return -EINVAL;
382+
}
383+
318384
/* Free existing IIR channels data if it was allocated */
319385
eq_iir_free_delaylines(mod);
320386

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)