[PATCH] ASoC: topology: Guard against out-of-range mixer control shift

Daniel Golle posted 1 patch 6 days, 10 hours ago
sound/soc/soc-topology.c | 10 ++++++++++
1 file changed, 10 insertions(+)
[PATCH] ASoC: topology: Guard against out-of-range mixer control shift
Posted by Daniel Golle 6 days, 10 hours ago
soc_tplg_control_dmixer_create() copies the per-channel "shift" field from
the topology file verbatim into struct soc_mixer_control. That value is
later used as a shift amount in soc_get_volsw() / soc_put_volsw() (e.g.
"reg_val >> shift" and "mask << shift"). Topology data is loaded from an
untrusted firmware file, and a shift >= 32 (the width of the register
value) is undefined behaviour when applied.

This is not hypothetical: mediatek/sof-tplg/sof-mt8186.tplg from
linux-firmware contains a control whose channel shift is 0x01000000, so
every read of that control (e.g. from alsamixer) emits:

  UBSAN: shift-out-of-bounds in sound/soc/soc-ops.c:117:21
  shift exponent 16777216 is too large for 32-bit type 'unsigned int'

tplg_chan_get_shift() can also return -EINVAL when no matching channel is
found, which becomes a large value once stored in the unsigned shift
field; the same guard covers that case.

Clamp an out-of-range shift to 0 and warn, so the rest of the card stays
usable instead of failing the whole topology load.

Fixes: 8a9782346dcc ("ASoC: topology: Add topology core")
Cc: stable@vger.kernel.org
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
---
 sound/soc/soc-topology.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c
index 35cbe29d2275..dd94eb9460d3 100644
--- a/sound/soc/soc-topology.c
+++ b/sound/soc/soc-topology.c
@@ -672,6 +672,16 @@ static int soc_tplg_control_dmixer_create(struct soc_tplg *tplg, struct snd_kcon
 	sm->shift = tplg_chan_get_shift(tplg, mc->channel, SNDRV_CHMAP_FL);
 	sm->rshift = tplg_chan_get_shift(tplg, mc->channel, SNDRV_CHMAP_FR);
 
+	if (sm->shift >= 32 || sm->rshift >= 32) {
+		dev_warn(tplg->dev,
+			 "ASoC: out-of-range shift for control %s, clamping to 0\n",
+			 mc->hdr.name);
+		if (sm->shift >= 32)
+			sm->shift = 0;
+		if (sm->rshift >= 32)
+			sm->rshift = 0;
+	}
+
 	sm->max = le32_to_cpu(mc->max);
 	sm->min = le32_to_cpu(mc->min);
 	sm->invert = le32_to_cpu(mc->invert);

base-commit: 0718283ab28bc3907e10b61a6b4be6fefa1cbb2f
-- 
2.55.0
Re: [PATCH] ASoC: topology: Guard against out-of-range mixer control shift
Posted by Mark Brown 6 days, 8 hours ago
On Sat, Jul 18, 2026 at 06:34:42PM +0100, Daniel Golle wrote:
> soc_tplg_control_dmixer_create() copies the per-channel "shift" field from
> the topology file verbatim into struct soc_mixer_control. That value is
> later used as a shift amount in soc_get_volsw() / soc_put_volsw() (e.g.

>  	sm->shift = tplg_chan_get_shift(tplg, mc->channel, SNDRV_CHMAP_FL);
>  	sm->rshift = tplg_chan_get_shift(tplg, mc->channel, SNDRV_CHMAP_FR);
>  
> +	if (sm->shift >= 32 || sm->rshift >= 32) {

Won't this break for mono controls - the right shift lookup will return
a negative error code?