ASoC: topology: Fix route memory corruption

Merge series from Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>:

Originally reported here:
https://github.com/thesofproject/avs-topology-xml/issues/22#issuecomment-2127892605
There is various level of failure there, first of all when topology
loads routes, it points directly into FW file, but it may be freed after
topology load. After fixing the above, when avs driver parses topology
it should allocate its own memory, as target strings can be shorter than
needed. Also clean up soc_tplg_dapm_graph_elems_load() a bit.
This commit is contained in:
Mark Brown 2024-06-11 12:28:22 +01:00
commit b9dd212b14
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
2 changed files with 38 additions and 24 deletions

View File

@ -1545,8 +1545,8 @@ static int avs_route_load(struct snd_soc_component *comp, int index,
{
struct snd_soc_acpi_mach *mach = dev_get_platdata(comp->card->dev);
size_t len = SNDRV_CTL_ELEM_ID_NAME_MAXLEN;
char buf[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
int ssp_port, tdm_slot;
char *buf;
/* See parse_link_formatted_string() for dynamic naming when(s). */
if (!avs_mach_singular_ssp(mach))
@ -1557,13 +1557,24 @@ static int avs_route_load(struct snd_soc_component *comp, int index,
return 0;
tdm_slot = avs_mach_ssp_tdm(mach, ssp_port);
buf = devm_kzalloc(comp->card->dev, len, GFP_KERNEL);
if (!buf)
return -ENOMEM;
avs_ssp_sprint(buf, len, route->source, ssp_port, tdm_slot);
strscpy((char *)route->source, buf, len);
route->source = buf;
buf = devm_kzalloc(comp->card->dev, len, GFP_KERNEL);
if (!buf)
return -ENOMEM;
avs_ssp_sprint(buf, len, route->sink, ssp_port, tdm_slot);
strscpy((char *)route->sink, buf, len);
route->sink = buf;
if (route->control) {
buf = devm_kzalloc(comp->card->dev, len, GFP_KERNEL);
if (!buf)
return -ENOMEM;
avs_ssp_sprint(buf, len, route->control, ssp_port, tdm_slot);
strscpy((char *)route->control, buf, len);
route->control = buf;
}
return 0;

View File

@ -1021,6 +1021,7 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg,
struct snd_soc_tplg_hdr *hdr)
{
struct snd_soc_dapm_context *dapm = &tplg->comp->dapm;
const size_t maxlen = SNDRV_CTL_ELEM_ID_NAME_MAXLEN;
struct snd_soc_tplg_dapm_graph_elem *elem;
struct snd_soc_dapm_route *route;
int count, i;
@ -1044,31 +1045,33 @@ static int soc_tplg_dapm_graph_elems_load(struct soc_tplg *tplg,
tplg->pos += sizeof(struct snd_soc_tplg_dapm_graph_elem);
/* validate routes */
if (strnlen(elem->source, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
SNDRV_CTL_ELEM_ID_NAME_MAXLEN) {
ret = -EINVAL;
break;
}
if (strnlen(elem->sink, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
SNDRV_CTL_ELEM_ID_NAME_MAXLEN) {
ret = -EINVAL;
break;
}
if (strnlen(elem->control, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
SNDRV_CTL_ELEM_ID_NAME_MAXLEN) {
if ((strnlen(elem->source, maxlen) == maxlen) ||
(strnlen(elem->sink, maxlen) == maxlen) ||
(strnlen(elem->control, maxlen) == maxlen)) {
ret = -EINVAL;
break;
}
route->source = elem->source;
route->sink = elem->sink;
route->source = devm_kmemdup(tplg->dev, elem->source,
min(strlen(elem->source), maxlen),
GFP_KERNEL);
route->sink = devm_kmemdup(tplg->dev, elem->sink,
min(strlen(elem->sink), maxlen),
GFP_KERNEL);
if (!route->source || !route->sink) {
ret = -ENOMEM;
break;
}
/* set to NULL atm for tplg users */
route->connected = NULL;
if (strnlen(elem->control, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) == 0)
route->control = NULL;
else
route->control = elem->control;
if (strnlen(elem->control, maxlen) != 0) {
route->control = devm_kmemdup(tplg->dev, elem->control,
min(strlen(elem->control), maxlen),
GFP_KERNEL);
if (!route->control) {
ret = -ENOMEM;
break;
}
}
/* add route dobj to dobj_list */
route->dobj.type = SND_SOC_DOBJ_GRAPH;