From 8c9150a22fcbaed427d040133352e6fab197f47d Mon Sep 17 00:00:00 2001 From: Harsh Raj Singhania Date: Sat, 19 Sep 2026 01:16:23 +0530 Subject: [PATCH] topology: harden binary topology decoder against malformed input The binary topology decoder trusts several length/count fields taken from the input .tplg blob. Three related issues are addressed: - decoder.c: snd_tplg_decode() computed hdr->size + hdr->payload_size in 32-bit, which can wrap and bypass the payload bounds check; do the arithmetic in 64-bit and compute the advance in size_t. - dapm.c: tplg_decode_dapm_widget() dereferenced the control header before validating the remaining size; add size checks before reading the ctl/mixer/enum/bytes headers and compute size2 in size_t. - dapm.c: tplg_decode_dapm_graph() passed an attacker-influenced size to alloca(); use calloc()+free() so oversized input fails gracefully. These only affect the (debug-oriented) decode path when processing untrusted or corrupted topology data. Signed-off-by: Harsh Raj Singhania --- src/topology/dapm.c | 36 ++++++++++++++++++++++++++++++------ src/topology/decoder.c | 4 ++-- 2 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/topology/dapm.c b/src/topology/dapm.c index 04a57ddd1..5fe8c1a13 100644 --- a/src/topology/dapm.c +++ b/src/topology/dapm.c @@ -960,6 +960,11 @@ int tplg_decode_dapm_widget(snd_tplg_t *tplg, for (index = 0; index < w->num_kcontrols; index++) { chdr = bin; + if (size < sizeof(*chdr)) { + snd_error(TOPOLOGY, "dapm widget: truncated kcontrol header"); + err = -EINVAL; + goto retval; + } switch (chdr->type) { case SND_SOC_TPLG_TYPE_MIXER: mt = tplg_calloc(&heap, sizeof(*mt)); @@ -970,7 +975,12 @@ int tplg_decode_dapm_widget(snd_tplg_t *tplg, wt->ctl[index] = (void *)mt; wt->num_ctls++; mc = bin; - size2 = mc->size + mc->priv.size; + if (size < sizeof(*mc)) { + snd_error(TOPOLOGY, "dapm widget: truncated mixer"); + err = -EINVAL; + goto retval; + } + size2 = (size_t)mc->size + (size_t)mc->priv.size; tplg_log(tplg, 'D', pos, "kcontrol mixer size %zd", size2); if (size2 > size) { snd_error(TOPOLOGY, "dapm widget: small mixer size %d", @@ -991,7 +1001,12 @@ int tplg_decode_dapm_widget(snd_tplg_t *tplg, wt->ctl[index] = (void *)et; wt->num_ctls++; ec = bin; - size2 = ec->size + ec->priv.size; + if (size < sizeof(*ec)) { + snd_error(TOPOLOGY, "dapm widget: truncated enum"); + err = -EINVAL; + goto retval; + } + size2 = (size_t)ec->size + (size_t)ec->priv.size; tplg_log(tplg, 'D', pos, "kcontrol enum size %zd", size2); if (size2 > size) { snd_error(TOPOLOGY, "dapm widget: small enum size %d", @@ -1011,7 +1026,12 @@ int tplg_decode_dapm_widget(snd_tplg_t *tplg, wt->ctl[index] = (void *)bt; wt->num_ctls++; bc = bin; - size2 = bc->size + bc->priv.size; + if (size < sizeof(*bc)) { + snd_error(TOPOLOGY, "dapm widget: truncated bytes"); + err = -EINVAL; + goto retval; + } + size2 = (size_t)bc->size + (size_t)bc->priv.size; tplg_log(tplg, 'D', pos, "kcontrol bytes size %zd", size2); if (size2 > size) { snd_error(TOPOLOGY, "dapm widget: small bytes size %d", @@ -1069,12 +1089,14 @@ int tplg_decode_dapm_graph(snd_tplg_t *tplg, return err; asize = sizeof(*gt) + (size / sizeof(*g)) * sizeof(*ge); - gt = alloca(asize); - memset(gt, 0, asize); + gt = calloc(1, asize); + if (gt == NULL) + return -ENOMEM; for (ge = gt->elem; size > 0; ge++) { g = bin; if (size < sizeof(*g)) { snd_error(TOPOLOGY, "dapm graph: small size %d", size); + free(gt); return -EINVAL; } ge->src = g->source; @@ -1089,5 +1111,7 @@ int tplg_decode_dapm_graph(snd_tplg_t *tplg, } t.graph = gt; - return snd_tplg_add_object(tplg, &t); + err = snd_tplg_add_object(tplg, &t); + free(gt); + return err; } diff --git a/src/topology/decoder.c b/src/topology/decoder.c index bf46d406a..b34f9a5d1 100644 --- a/src/topology/decoder.c +++ b/src/topology/decoder.c @@ -81,7 +81,7 @@ int snd_tplg_decode(snd_tplg_t *tplg, void *bin, size_t size, int dflags) return -EINVAL; } - if (size - pos < hdr->size + hdr->payload_size) { + if ((uint64_t)hdr->size + (uint64_t)hdr->payload_size > (uint64_t)(size - pos)) { snd_error(TOPOLOGY, "incomplete payload data to decode"); return -EINVAL; } @@ -116,6 +116,6 @@ int snd_tplg_decode(snd_tplg_t *tplg, void *bin, size_t size, int dflags) err = tptr->decod(tplg, pos, hdr, b + hdr->size, hdr->payload_size); if (err < 0) return err; - b += hdr->size + hdr->payload_size; + b += (size_t)hdr->size + (size_t)hdr->payload_size; } }