[PATCH 1/7] ASoC: qcom: audioreach: fix module cfg blob size handling
From: Srinivas Kandagatla
Date: Fri Oct 23 2026 - 13:15:57 EST
From: Ravi Hothi <ravi.hothi@xxxxxxxxxxxxxxxx>
audioreach_get_module_priv_data() passes mod_array->size, a byte count,
as the element count of the __le32 data[] flex array. The allocation and
the copy are four times too large, and the memcpy() can read past the end
of the topology firmware buffer. The size is also never checked against
the private data it must lie within, and a zero size makes the loop spin
forever.
Convert the size to a word count, bound the blob by the remaining private
data and reject a zero size. Also check the returned pointer before
storing it in mod->data, as an error pointer there is dereferenced when
the graph is opened.
Fixes: c7ed4c2debfd ("ASoC: qcom: audioreach: add support for static calibration")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Ravi Hothi <ravi.hothi@xxxxxxxxxxxxxxxx>
Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla@xxxxxxxxxxxxxxxx>
---
sound/soc/qcom/qdsp6/topology.c | 31 ++++++++++++++++++++++++++-----
1 file changed, 26 insertions(+), 5 deletions(-)
diff --git a/sound/soc/qcom/qdsp6/topology.c b/sound/soc/qcom/qdsp6/topology.c
index faafbc5c0ad0..612d8f03e6e9 100644
--- a/sound/soc/qcom/qdsp6/topology.c
+++ b/sound/soc/qcom/qdsp6/topology.c
@@ -312,22 +312,37 @@ audioreach_get_module_priv_data(const struct snd_soc_tplg_private *private)
for (sz = 0; sz < le32_to_cpu(private->size); ) {
const struct snd_soc_tplg_vendor_array *mod_array;
+ u32 array_size;
mod_array = (struct snd_soc_tplg_vendor_array *)((u8 *)private->array + sz);
+ array_size = le32_to_cpu(mod_array->size);
+
if (le32_to_cpu(mod_array->type) == SND_SOC_AR_TPLG_MODULE_CFG_TYPE) {
struct audioreach_module_priv_data *pdata;
+ u32 nwords;
+
+ /* size is the byte count of the __le32 data[] */
+ nwords = array_size / sizeof(__le32);
+
+ /* the blob must lie within the private data */
+ if (sizeof(*pdata) + (u64)array_size >
+ le32_to_cpu(private->size) - sz)
+ return ERR_PTR(-EINVAL);
- pdata = kzalloc_flex(*pdata, data,
- le32_to_cpu(mod_array->size));
+ pdata = kzalloc_flex(*pdata, data, nwords);
if (!pdata)
return ERR_PTR(-ENOMEM);
- memcpy(pdata, ((u8 *)private->data + sz), struct_size(pdata, data,
- le32_to_cpu(mod_array->size)));
+ memcpy(pdata, ((u8 *)private->data + sz),
+ struct_size(pdata, data, nwords));
return pdata;
}
- sz = sz + le32_to_cpu(mod_array->size);
+ /* a zero size would never advance the walk */
+ if (!array_size)
+ return ERR_PTR(-EINVAL);
+
+ sz = sz + array_size;
}
return NULL;
@@ -611,6 +626,12 @@ static int audioreach_widget_load_module_common(struct snd_soc_component *compon
return mod ? PTR_ERR(mod) : -ENODEV;
mod->data = audioreach_get_module_priv_data(&tplg_w->priv);
+ if (IS_ERR(mod->data)) {
+ int rc = PTR_ERR(mod->data);
+
+ mod->data = NULL;
+ return rc;
+ }
dobj = &w->dobj;
dobj->private = mod;
--
2.47.3