Skip to content

Commit 0068678

Browse files
lrgirdwokv2019i
authored andcommitted
volume: bound init payload reads against its actual size
Init read the per-channel config[] array using the stream channel count without checking the payload was large enough, reading past the mailbox. The payload comes in two forms: an all-channels entry (channel_id set to ALL_CHANNELS_MASK) that carries a single config applied to every channel, or one config entry per channel. The per-channel loop always indexed config[channel], so the common all-channels payload (one entry) was read out of bounds for every channel beyond the first; the result was then discarded, masking the over-read. Require at least one entry before dereferencing config[0] to detect the form, require one entry per channel only for the per-channel form, and index config[] by the selected entry so no read goes past the payload. Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
1 parent 10d5b62 commit 0068678

1 file changed

Lines changed: 24 additions & 6 deletions

File tree

src/audio/volume/volume_ipc4.c

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ int volume_init(struct processing_module *mod)
115115
uint32_t channels_count;
116116
uint8_t channel_cfg;
117117
uint8_t channel;
118+
bool all_channels;
118119
uint32_t instance_id = IPC4_INST_ID(dev_comp_id(dev));
119120

120121
if (instance_id >= IPC4_MAX_PEAK_VOL_REG_SLOTS) {
@@ -127,6 +128,26 @@ int volume_init(struct processing_module *mod)
127128
return -EINVAL;
128129
}
129130

131+
/* The payload must hold at least one config entry, which is read below
132+
* to detect the all-channels form.
133+
*/
134+
if (cfg->size < sizeof(*vol) + sizeof(vol->config[0])) {
135+
comp_err(dev, "Invalid init payload size %zu", cfg->size);
136+
return -EINVAL;
137+
}
138+
139+
/* In the all-channels form a single entry applies to every channel;
140+
* otherwise the payload must hold one entry per channel as they are
141+
* each read below.
142+
*/
143+
all_channels = vol->config[0].channel_id == IPC4_ALL_CHANNELS_MASK;
144+
if (!all_channels &&
145+
cfg->size < sizeof(*vol) + channels_count * sizeof(vol->config[0])) {
146+
comp_err(dev, "Invalid init payload size %zu for %u channels",
147+
cfg->size, channels_count);
148+
return -EINVAL;
149+
}
150+
130151
cd = mod_zalloc(mod, sizeof(struct vol_data));
131152
if (!cd)
132153
return -ENOMEM;
@@ -156,16 +177,13 @@ int volume_init(struct processing_module *mod)
156177
md->private = cd;
157178

158179
for (channel = 0; channel < channels_count; channel++) {
159-
if (vol->config[0].channel_id == IPC4_ALL_CHANNELS_MASK)
160-
channel_cfg = 0;
161-
else
162-
channel_cfg = channel;
180+
channel_cfg = all_channels ? 0 : channel;
163181

164182
target_volume[channel] =
165-
convert_volume_ipc4_to_ipc3(dev, vol->config[channel].target_volume);
183+
convert_volume_ipc4_to_ipc3(dev, vol->config[channel_cfg].target_volume);
166184

167185
set_volume_ipc4(cd, channel,
168-
target_volume[channel_cfg],
186+
target_volume[channel],
169187
vol->config[channel_cfg].curve_type,
170188
vol->config[channel_cfg].curve_duration);
171189

0 commit comments

Comments
 (0)