3.18-stable review patch.  If anyone has any objections, please let me know.

------------------

From: Takashi Iwai <ti...@suse.de>

commit 9685347aa0a5c2869058ca6ab79fd8e93084a67f upstream.

The aloop runtime object and its assignment in the cable are left even
when opening a substream fails.  This doesn't mean any memory leak,
but it still keeps the invalid pointer that may be referred by the
another side of the cable spontaneously, which is a potential Oops
cause.

Clean up the cable assignment and the empty cable upon the error path
properly.

Fixes: 597603d615d2 ("ALSA: introduce the snd-aloop module for the PCM 
loopback")
Signed-off-by: Takashi Iwai <ti...@suse.de>
Signed-off-by: Greg Kroah-Hartman <gre...@linuxfoundation.org>

---
 sound/drivers/aloop.c |   38 +++++++++++++++++++++++++-------------
 1 file changed, 25 insertions(+), 13 deletions(-)

--- a/sound/drivers/aloop.c
+++ b/sound/drivers/aloop.c
@@ -659,12 +659,31 @@ static int rule_channels(struct snd_pcm_
        return snd_interval_refine(hw_param_interval(params, rule->var), &t);
 }
 
+static void free_cable(struct snd_pcm_substream *substream)
+{
+       struct loopback *loopback = substream->private_data;
+       int dev = get_cable_index(substream);
+       struct loopback_cable *cable;
+
+       cable = loopback->cables[substream->number][dev];
+       if (!cable)
+               return;
+       if (cable->streams[!substream->stream]) {
+               /* other stream is still alive */
+               cable->streams[substream->stream] = NULL;
+       } else {
+               /* free the cable */
+               loopback->cables[substream->number][dev] = NULL;
+               kfree(cable);
+       }
+}
+
 static int loopback_open(struct snd_pcm_substream *substream)
 {
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct loopback *loopback = substream->private_data;
        struct loopback_pcm *dpcm;
-       struct loopback_cable *cable;
+       struct loopback_cable *cable = NULL;
        int err = 0;
        int dev = get_cable_index(substream);
 
@@ -683,7 +702,6 @@ static int loopback_open(struct snd_pcm_
        if (!cable) {
                cable = kzalloc(sizeof(*cable), GFP_KERNEL);
                if (!cable) {
-                       kfree(dpcm);
                        err = -ENOMEM;
                        goto unlock;
                }
@@ -725,6 +743,10 @@ static int loopback_open(struct snd_pcm_
        else
                runtime->hw = cable->hw;
  unlock:
+       if (err < 0) {
+               free_cable(substream);
+               kfree(dpcm);
+       }
        mutex_unlock(&loopback->cable_lock);
        return err;
 }
@@ -733,20 +755,10 @@ static int loopback_close(struct snd_pcm
 {
        struct loopback *loopback = substream->private_data;
        struct loopback_pcm *dpcm = substream->runtime->private_data;
-       struct loopback_cable *cable;
-       int dev = get_cable_index(substream);
 
        loopback_timer_stop(dpcm);
        mutex_lock(&loopback->cable_lock);
-       cable = loopback->cables[substream->number][dev];
-       if (cable->streams[!substream->stream]) {
-               /* other stream is still alive */
-               cable->streams[substream->stream] = NULL;
-       } else {
-               /* free the cable */
-               loopback->cables[substream->number][dev] = NULL;
-               kfree(cable);
-       }
+       free_cable(substream);
        mutex_unlock(&loopback->cable_lock);
        return 0;
 }


Reply via email to