diff --git a/src/audio/smart_amp/smart_amp.c b/src/audio/smart_amp/smart_amp.c index f82e3d2f7360..373ad2ce84a8 100644 --- a/src/audio/smart_amp/smart_amp.c +++ b/src/audio/smart_amp/smart_amp.c @@ -289,7 +289,11 @@ static int smart_amp_get_config(struct processing_module *mod, comp_dbg(dev, "actual blob size = %zu, expected blob size = %zu", bs, sizeof(struct sof_smart_amp_config)); - if (bs == 0 || bs > size) + /* bs is the host-set config.size and is used as the memcpy source + * length from the fixed-size sad->config, so bound it by the struct + * size as well as the destination buffer + */ + if (bs == 0 || bs > size || bs > sizeof(struct sof_smart_amp_config)) return -EINVAL; ret = memcpy_s(cdata->data->data, size, &sad->config, bs); @@ -521,8 +525,15 @@ static int smart_amp_ff_process(struct processing_module *mod, return 0; } - if (frames > SMART_AMP_FF_BUF_DB_SZ) { - comp_err(dev, "feed forward frame size overflow: %u", frames); + /* + * The remap functions write frames * ff_mod.channels samples into + * ff_mod.buf, which holds SMART_AMP_FF_BUF_DB_SZ samples. Bound the + * total sample count, not just the frame count, so an unexpected + * channel count cannot overflow the buffer. + */ + if ((uint64_t)frames * sad->ff_mod.channels > SMART_AMP_FF_BUF_DB_SZ) { + comp_err(dev, "feed forward frame size overflow: %u frames, %u ch", + frames, sad->ff_mod.channels); sad->ff_mod.consumed = frames; return -EINVAL; } @@ -556,8 +567,10 @@ static int smart_amp_fb_process(struct processing_module *mod, return 0; } - if (frames > SMART_AMP_FB_BUF_DB_SZ) { - comp_err(dev, "feedback frame size overflow: %u", frames); + /* bound total samples (frames * channels) against the buffer size */ + if ((uint64_t)frames * sad->fb_mod.channels > SMART_AMP_FB_BUF_DB_SZ) { + comp_err(dev, "feedback frame size overflow: %u frames, %u ch", + frames, sad->fb_mod.channels); sad->fb_mod.consumed = frames; return -EINVAL; } diff --git a/src/audio/smart_amp/smart_amp_generic.c b/src/audio/smart_amp/smart_amp_generic.c index 91223eb398bd..ffee36f5d5e7 100644 --- a/src/audio/smart_amp/smart_amp_generic.c +++ b/src/audio/smart_amp/smart_amp_generic.c @@ -35,7 +35,8 @@ static void remap_s32_to_s32(struct smart_amp_mod_stream *src_mod, uint32_t fram n = MIN(num_samples_remaining, nmax); for (ch = 0; ch < src_mod->channels; ch++) { - if (chan_map[ch] == -1) + /* skip unmapped (-1) and out-of-range source channels */ + if (chan_map[ch] < 0 || chan_map[ch] >= src_ch) continue; mod_ptr = mod_ptr_base + ch; @@ -103,7 +104,8 @@ static void remap_s16_to_s16(struct smart_amp_mod_stream *src_mod, uint32_t fram n = MIN(num_samples_remaining, nmax); for (ch = 0; ch < src_mod->channels; ch++) { - if (chan_map[ch] == -1) + /* skip unmapped (-1) and out-of-range source channels */ + if (chan_map[ch] < 0 || chan_map[ch] >= src_ch) continue; mod_ptr = mod_ptr_base + ch; @@ -147,7 +149,8 @@ static void remap_s16_to_b32(struct smart_amp_mod_stream *src_mod, uint32_t fram n = MIN(num_samples_remaining, nmax); for (ch = 0; ch < src_mod->channels; ch++) { - if (chan_map[ch] == -1) + /* skip unmapped (-1) and out-of-range source channels */ + if (chan_map[ch] < 0 || chan_map[ch] >= src_ch) continue; mod_ptr = mod_ptr_base + ch; diff --git a/src/audio/smart_amp/smart_amp_maxim_dsm.c b/src/audio/smart_amp/smart_amp_maxim_dsm.c index b9289861aa8d..2a74e16fe2b2 100644 --- a/src/audio/smart_amp/smart_amp_maxim_dsm.c +++ b/src/audio/smart_amp/smart_amp_maxim_dsm.c @@ -325,6 +325,17 @@ static int maxim_dsm_get_param(struct smart_amp_mod_struct_t *hspk, return -EINVAL; } + /* Host controls msg_index and therefore data_pos; make sure the + * fragment stays inside caldata->data to avoid leaking adjacent + * heap back to the host. + */ + if (caldata->data_pos >= caldata->data_size || + bs > caldata->data_size - caldata->data_pos) { + comp_err(dev, "[DSM] invalid data_pos %u, size %zu, total %u", + caldata->data_pos, bs, caldata->data_size); + return -EINVAL; + } + /* copy required size of data */ ret = memcpy_s(cdata->data->data, size, (char *)caldata->data + caldata->data_pos, diff --git a/src/samples/audio/smart_amp_test_ipc3.c b/src/samples/audio/smart_amp_test_ipc3.c index 3e69bb5f308e..a3dc939a509a 100644 --- a/src/samples/audio/smart_amp_test_ipc3.c +++ b/src/samples/audio/smart_amp_test_ipc3.c @@ -518,6 +518,16 @@ static int smart_amp_prepare(struct comp_dev *dev) sad->in_channels = audio_stream_get_channels(&sad->source_buf->stream); + /* out_channels bounds the processing loop that indexes the + * PLATFORM_MAX_CHANNELS-sized channel map, so reject a larger count + */ + if (sad->out_channels > PLATFORM_MAX_CHANNELS || + sad->in_channels > PLATFORM_MAX_CHANNELS) { + comp_err(dev, "invalid channel count, in %u out %u", + sad->in_channels, sad->out_channels); + return -EINVAL; + } + if (sad->feedback_buf) { audio_stream_set_channels(&sad->feedback_buf->stream, sad->config.feedback_channels);