ASoC: topology: Check PCM and DAI name strings before use

Topology objects store several PCM and DAI names in fixed-size UAPI
arrays. Other topology parser paths validate these fields with bounded
strnlen() checks before using them as C strings, but the PCM and DAI
paths still pass some fixed-size arrays directly to strlen(),
devm_kstrdup(), DAI lookup, and diagnostic prints.

A malformed topology blob with a non-NUL-terminated PCM, DAI, or stream
capability name can therefore make the parser read past the end of the
fixed-size field.

Reject unterminated PCM and DAI name fields before consuming them as C
strings.

Fixes: 64527e8a35 ("ASoC: topology: Add FE DAIs dynamically")
Fixes: acfc7d46cd ("ASoC: topology: Add FE DAI links dynamically")
Fixes: 0038be9a84 ("ASoC: topology: Add support for configuring existing BE DAIs")
Signed-off-by: Cássio Gabriel <cassiogabrielcontato@gmail.com>
Link: https://patch.msgid.link/20260604-asoc-topology-check-pcm-dai-names-v1-1-e1b0f6f7c2ce@gmail.com
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Cássio Gabriel 2026-06-04 00:10:58 -03:00 committed by Mark Brown
parent 890b61d3a8
commit b7e44d1986
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0

View File

@ -1326,9 +1326,24 @@ static int soc_tplg_dapm_complete(struct soc_tplg *tplg)
return ret;
}
static int soc_tplg_check_name(const char *name)
{
if (strnlen(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN) ==
SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
return -EINVAL;
return 0;
}
static int set_stream_info(struct soc_tplg *tplg, struct snd_soc_pcm_stream *stream,
struct snd_soc_tplg_stream_caps *caps)
{
int ret;
ret = soc_tplg_check_name(caps->name);
if (ret)
return ret;
stream->stream_name = devm_kstrdup(tplg->dev, caps->name, GFP_KERNEL);
if (!stream->stream_name)
return -ENOMEM;
@ -1380,7 +1395,11 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,
if (dai_drv == NULL)
return -ENOMEM;
if (strlen(pcm->dai_name)) {
ret = soc_tplg_check_name(pcm->dai_name);
if (ret)
goto err;
if (pcm->dai_name[0]) {
dai_drv->name = devm_kstrdup(tplg->dev, pcm->dai_name, GFP_KERNEL);
if (!dai_drv->name) {
ret = -ENOMEM;
@ -1486,7 +1505,11 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg,
if (tplg->ops)
link->dobj.unload = tplg->ops->link_unload;
if (strlen(pcm->pcm_name)) {
ret = soc_tplg_check_name(pcm->pcm_name);
if (ret)
goto err;
if (pcm->pcm_name[0]) {
link->name = devm_kstrdup(tplg->dev, pcm->pcm_name, GFP_KERNEL);
link->stream_name = devm_kstrdup(tplg->dev, pcm->pcm_name, GFP_KERNEL);
if (!link->name || !link->stream_name) {
@ -1496,7 +1519,11 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg,
}
link->id = le32_to_cpu(pcm->pcm_id);
if (strlen(pcm->dai_name)) {
ret = soc_tplg_check_name(pcm->dai_name);
if (ret)
goto err;
if (pcm->dai_name[0]) {
link->cpus->dai_name = devm_kstrdup(tplg->dev, pcm->dai_name, GFP_KERNEL);
if (!link->cpus->dai_name) {
ret = -ENOMEM;
@ -1848,6 +1875,10 @@ static int soc_tplg_dai_config(struct soc_tplg *tplg,
memset(&dai_component, 0, sizeof(dai_component));
ret = soc_tplg_check_name(d->dai_name);
if (ret)
return ret;
dai_component.dai_name = d->dai_name;
dai = snd_soc_find_dai(&dai_component);
if (!dai) {