ASoC: topology: Add missing memory checks
authorAmadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Fri, 27 Mar 2020 20:47:24 +0000 (16:47 -0400)
committerMark Brown <broonie@kernel.org>
Thu, 9 Apr 2020 11:46:03 +0000 (12:46 +0100)
kstrdup is an allocation function and it can fail, so its return value
should be checked and handled appropriately.

In order to check all cases, we need to modify set_stream_info to return
a value, so check that everything went correctly when doing kstrdup().
Later add proper checks and error handlers.

Signed-off-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Reviewed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Link: https://lore.kernel.org/r/20200327204729.397-2-amadeuszx.slawinski@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/soc-topology.c

index 87f75ed..73fc304 100644 (file)
@@ -1766,10 +1766,13 @@ static int soc_tplg_dapm_complete(struct soc_tplg *tplg)
        return 0;
 }
 
-static void set_stream_info(struct snd_soc_pcm_stream *stream,
+static int set_stream_info(struct snd_soc_pcm_stream *stream,
        struct snd_soc_tplg_stream_caps *caps)
 {
        stream->stream_name = kstrdup(caps->name, GFP_KERNEL);
+       if (!stream->stream_name)
+               return -ENOMEM;
+
        stream->channels_min = le32_to_cpu(caps->channels_min);
        stream->channels_max = le32_to_cpu(caps->channels_max);
        stream->rates = le32_to_cpu(caps->rates);
@@ -1777,6 +1780,8 @@ static void set_stream_info(struct snd_soc_pcm_stream *stream,
        stream->rate_max = le32_to_cpu(caps->rate_max);
        stream->formats = le64_to_cpu(caps->formats);
        stream->sig_bits = le32_to_cpu(caps->sig_bits);
+
+       return 0;
 }
 
 static void set_dai_flags(struct snd_soc_dai_driver *dai_drv,
@@ -1812,20 +1817,29 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,
        if (dai_drv == NULL)
                return -ENOMEM;
 
-       if (strlen(pcm->dai_name))
+       if (strlen(pcm->dai_name)) {
                dai_drv->name = kstrdup(pcm->dai_name, GFP_KERNEL);
+               if (!dai_drv->name) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
+       }
        dai_drv->id = le32_to_cpu(pcm->dai_id);
 
        if (pcm->playback) {
                stream = &dai_drv->playback;
                caps = &pcm->caps[SND_SOC_TPLG_STREAM_PLAYBACK];
-               set_stream_info(stream, caps);
+               ret = set_stream_info(stream, caps);
+               if (ret < 0)
+                       goto err;
        }
 
        if (pcm->capture) {
                stream = &dai_drv->capture;
                caps = &pcm->caps[SND_SOC_TPLG_STREAM_CAPTURE];
-               set_stream_info(stream, caps);
+               ret = set_stream_info(stream, caps);
+               if (ret < 0)
+                       goto err;
        }
 
        if (pcm->compress)
@@ -1835,11 +1849,7 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,
        ret = soc_tplg_dai_load(tplg, dai_drv, pcm, NULL);
        if (ret < 0) {
                dev_err(tplg->comp->dev, "ASoC: DAI loading failed\n");
-               kfree(dai_drv->playback.stream_name);
-               kfree(dai_drv->capture.stream_name);
-               kfree(dai_drv->name);
-               kfree(dai_drv);
-               return ret;
+               goto err;
        }
 
        dai_drv->dobj.index = tplg->index;
@@ -1860,6 +1870,14 @@ static int soc_tplg_dai_create(struct soc_tplg *tplg,
                return ret;
        }
 
+       return 0;
+
+err:
+       kfree(dai_drv->playback.stream_name);
+       kfree(dai_drv->capture.stream_name);
+       kfree(dai_drv->name);
+       kfree(dai_drv);
+
        return ret;
 }
 
@@ -1916,11 +1934,20 @@ static int soc_tplg_fe_link_create(struct soc_tplg *tplg,
        if (strlen(pcm->pcm_name)) {
                link->name = kstrdup(pcm->pcm_name, GFP_KERNEL);
                link->stream_name = kstrdup(pcm->pcm_name, GFP_KERNEL);
+               if (!link->name || !link->stream_name) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
        }
        link->id = le32_to_cpu(pcm->pcm_id);
 
-       if (strlen(pcm->dai_name))
+       if (strlen(pcm->dai_name)) {
                link->cpus->dai_name = kstrdup(pcm->dai_name, GFP_KERNEL);
+               if (!link->cpus->dai_name) {
+                       ret = -ENOMEM;
+                       goto err;
+               }
+       }
 
        link->codecs->name = "snd-soc-dummy";
        link->codecs->dai_name = "snd-soc-dummy-dai";
@@ -2436,13 +2463,17 @@ static int soc_tplg_dai_config(struct soc_tplg *tplg,
        if (d->playback) {
                stream = &dai_drv->playback;
                caps = &d->caps[SND_SOC_TPLG_STREAM_PLAYBACK];
-               set_stream_info(stream, caps);
+               ret = set_stream_info(stream, caps);
+               if (ret < 0)
+                       goto err;
        }
 
        if (d->capture) {
                stream = &dai_drv->capture;
                caps = &d->caps[SND_SOC_TPLG_STREAM_CAPTURE];
-               set_stream_info(stream, caps);
+               ret = set_stream_info(stream, caps);
+               if (ret < 0)
+                       goto err;
        }
 
        if (d->flag_mask)
@@ -2454,10 +2485,15 @@ static int soc_tplg_dai_config(struct soc_tplg *tplg,
        ret = soc_tplg_dai_load(tplg, dai_drv, NULL, dai);
        if (ret < 0) {
                dev_err(tplg->comp->dev, "ASoC: DAI loading failed\n");
-               return ret;
+               goto err;
        }
 
        return 0;
+
+err:
+       kfree(dai_drv->playback.stream_name);
+       kfree(dai_drv->capture.stream_name);
+       return ret;
 }
 
 /* load physical DAI elements */