ASoC: SOF: validate topology volume range before allocation

SOF treats the topology mixer min and max values as non-negative indices
into its volume table. It stores them in signed fields, allocates max + 1
entries through an int argument, and later indexes the table with the
stored range.

An inverted range is invalid, while a maximum at or above INT_MAX cannot
be represented safely after the increment or in the signed fields.
Validate the complete range before storing it or allocating the table.

Fixes: 311ce4fe76 ("ASoC: SOF: Add support for loading topologies")
Assisted-by: Codex:gpt-5
Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
Acked-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
Link: https://patch.msgid.link/20260814081238.25434-1-pengpeng@iscas.ac.cn
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Pengpeng Hou 2026-08-14 16:12:38 +08:00 committed by Mark Brown
parent ac47e22fcf
commit a698e4a60f
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0

View File

@ -846,6 +846,7 @@ static int sof_control_load_volume(struct snd_soc_component *scomp,
struct snd_soc_tplg_mixer_control *mc =
container_of(hdr, struct snd_soc_tplg_mixer_control, hdr);
int tlv[SOF_TLV_ITEMS];
u32 min, max;
unsigned int mask;
int ret;
@ -853,6 +854,11 @@ static int sof_control_load_volume(struct snd_soc_component *scomp,
if (le32_to_cpu(mc->num_channels) > SND_SOC_TPLG_MAX_CHAN)
return -EINVAL;
min = le32_to_cpu(mc->min);
max = le32_to_cpu(mc->max);
if (min > max || max >= INT_MAX)
return -EINVAL;
/*
* If control has more than 2 channels we need to override the info. This is because even if
* ASoC layer has defined topology's max channel count to SND_SOC_TPLG_MAX_CHAN = 8, the
@ -863,12 +869,12 @@ static int sof_control_load_volume(struct snd_soc_component *scomp,
kc->info = snd_sof_volume_info;
scontrol->comp_id = sdev->next_comp_id;
scontrol->min_volume_step = le32_to_cpu(mc->min);
scontrol->max_volume_step = le32_to_cpu(mc->max);
scontrol->min_volume_step = min;
scontrol->max_volume_step = max;
scontrol->num_channels = le32_to_cpu(mc->num_channels);
scontrol->max = le32_to_cpu(mc->max);
if (le32_to_cpu(mc->max) == 1)
scontrol->max = max;
if (max == 1)
goto skip;
/* extract tlv data */
@ -878,7 +884,7 @@ static int sof_control_load_volume(struct snd_soc_component *scomp,
}
/* set up volume table */
ret = set_up_volume_table(scontrol, tlv, le32_to_cpu(mc->max) + 1);
ret = set_up_volume_table(scontrol, tlv, max + 1);
if (ret < 0) {
dev_err(scomp->dev, "error: setting up volume table\n");
return ret;
@ -911,7 +917,7 @@ static int sof_control_load_volume(struct snd_soc_component *scomp,
return 0;
err:
if (le32_to_cpu(mc->max) > 1)
if (max > 1)
kfree(scontrol->volume_table);
return ret;