volume: validate host-supplied config and fix init error path#10919
volume: validate host-supplied config and fix init error path#10919lgirdwood wants to merge 3 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Hardens the volume component against malformed host-supplied IPC payloads and fixes a use-after-free in an IPC3 init error path.
Changes:
- Add IPC4 init payload size validation before iterating per-channel config.
- Tighten attenuation control payload validation to require exactly 32 bits.
- Fix IPC3 init error cleanup order to avoid dereferencing freed memory.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| src/audio/volume/volume_ipc4.c | Adds IPC4 init/config size validation and tightens attenuation payload size checks. |
| src/audio/volume/volume_ipc3.c | Adjusts error-path frees to avoid a use-after-free during init failure. |
| if (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; | ||
| } |
There was a problem hiding this comment.
No overflow here: channels_count is validated to be in [1, SOF_IPC_MAX_CHANNELS] (== 8) a few lines above, before this size check, so channels_count * sizeof(vol->config[0]) is bounded by 8 * a small struct and can't overflow size_t.
| if (data_size < (int)sizeof(uint32_t) || data_size > sizeof(uint32_t)) { | ||
| comp_err(dev, "attenuation data size %d is incorrect", data_size); | ||
| return -EINVAL; | ||
| } |
There was a problem hiding this comment.
Addressed — the check is now a single data_size != (int)sizeof(uint32_t), with the cast keeping both sides signed (no signed/unsigned comparison).
| mod_free(mod, cd); | ||
| /* free cd->vol before cd: freeing cd first would leave the | ||
| * following cd->vol read dereferencing freed memory | ||
| */ |
There was a problem hiding this comment.
please remove the obvious comment
| /* 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) || data_size > sizeof(uint32_t)) { |
There was a problem hiding this comment.
ehm, data_size != sizeof(uint32_t)?
There was a problem hiding this comment.
Done — simplified to a single data_size != (int)sizeof(uint32_t) check. (Cast to int to keep it a clean signed comparison, since data_size is int — also addresses the signed/unsigned note.)
On an invalid ramp type the init error path freed the component data then read a field from it. Free the dependent allocation before the component data and stop dereferencing it afterwards. Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Init read a per-channel config array sized by the channel count from the init payload without checking the payload was large enough, reading past the mailbox. Require the payload to cover the base config and all per-channel entries. Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
The attenuation setter only rejected oversized payloads, then dereferenced the data as a 32-bit value; a shorter payload read past the mailbox. Require exactly a 32-bit payload. Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
Hardening of host-supplied data in the volume component, plus an error-path
fix:
freed and then dereferenced)
config array before iterating it
No functional change for valid configurations.