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; - pdata = kzalloc_flex(*pdata, data, - le32_to_cpu(mod_array->size)); + /* 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, 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;