diff --git a/src/audio/volume/volume_ipc3.c b/src/audio/volume/volume_ipc3.c index 6a88b68e6ae8..053b41e32152 100644 --- a/src/audio/volume/volume_ipc3.c +++ b/src/audio/volume/volume_ipc3.c @@ -157,8 +157,8 @@ int volume_init(struct processing_module *mod) break; default: comp_err(dev, "invalid ramp type %d", vol->ramp); - mod_free(mod, cd); mod_free(mod, cd->vol); + mod_free(mod, cd); return -EINVAL; } diff --git a/src/audio/volume/volume_ipc4.c b/src/audio/volume/volume_ipc4.c index 57a5f427903e..e111752d2b78 100644 --- a/src/audio/volume/volume_ipc4.c +++ b/src/audio/volume/volume_ipc4.c @@ -115,6 +115,7 @@ int volume_init(struct processing_module *mod) uint32_t channels_count; uint8_t channel_cfg; uint8_t channel; + bool all_channels; uint32_t instance_id = IPC4_INST_ID(dev_comp_id(dev)); if (instance_id >= IPC4_MAX_PEAK_VOL_REG_SLOTS) { @@ -127,6 +128,26 @@ int volume_init(struct processing_module *mod) return -EINVAL; } + /* The payload must hold at least one config entry, which is read below + * to detect the all-channels form. + */ + if (cfg->size < sizeof(*vol) + sizeof(vol->config[0])) { + comp_err(dev, "Invalid init payload size %zu", cfg->size); + return -EINVAL; + } + + /* In the all-channels form a single entry applies to every channel; + * otherwise the payload must hold one entry per channel as they are + * each read below. + */ + all_channels = vol->config[0].channel_id == IPC4_ALL_CHANNELS_MASK; + if (!all_channels && + cfg->size < sizeof(*vol) + channels_count * sizeof(vol->config[0])) { + comp_err(dev, "Invalid init payload size %zu for %u channels", + cfg->size, channels_count); + return -EINVAL; + } + cd = mod_zalloc(mod, sizeof(struct vol_data)); if (!cd) return -ENOMEM; @@ -156,16 +177,13 @@ int volume_init(struct processing_module *mod) md->private = cd; for (channel = 0; channel < channels_count; channel++) { - if (vol->config[0].channel_id == IPC4_ALL_CHANNELS_MASK) - channel_cfg = 0; - else - channel_cfg = channel; + channel_cfg = all_channels ? 0 : channel; target_volume[channel] = - convert_volume_ipc4_to_ipc3(dev, vol->config[channel].target_volume); + convert_volume_ipc4_to_ipc3(dev, vol->config[channel_cfg].target_volume); set_volume_ipc4(cd, channel, - target_volume[channel_cfg], + target_volume[channel], vol->config[channel_cfg].curve_type, vol->config[channel_cfg].curve_duration); @@ -268,8 +286,10 @@ static int volume_set_attenuation(struct processing_module *mod, const uint8_t * struct comp_dev *dev = mod->dev; uint32_t attenuation; - /* only support attenuation in format of 32bit */ - if (data_size > sizeof(uint32_t)) { + /* only support attenuation in format of 32bit; the payload is + * dereferenced as a uint32_t below so it must be exactly that size + */ + if (data_size != (int)sizeof(uint32_t)) { comp_err(dev, "attenuation data size %d is incorrect", data_size); return -EINVAL; }