Thread (2 messages) 2 messages, 2 authors, 2d ago
WARM2d

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

From: Daniel Golle <daniel@makrotopia.org>
Date: 2026-07-18 17:35:00
Also in: linux-mediatek, linux-sound, lkml
Subsystem: sound, sound - soc layer / dynamic audio power management (asoc), the rest · Maintainers: Jaroslav Kysela, Takashi Iwai, Liam Girdwood, Mark Brown, Linus Torvalds

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
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help