Skip to content

Commit

Permalink
ALSA: aloop: Release cable upon open error path
Browse files Browse the repository at this point in the history
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: 597603d ("ALSA: introduce the snd-aloop module for the PCM loopback")
Cc: <stable@vger.kernel.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
  • Loading branch information
Takashi Iwai committed Jan 5, 2018
1 parent fb51f1c commit 9685347
Showing 1 changed file with 25 additions and 13 deletions.
38 changes: 25 additions & 13 deletions sound/drivers/aloop.c
Original file line number Diff line number Diff line change
Expand Up @@ -658,12 +658,31 @@ static int rule_channels(struct snd_pcm_hw_params *params,
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);

Expand All @@ -681,7 +700,6 @@ static int loopback_open(struct snd_pcm_substream *substream)
if (!cable) {
cable = kzalloc(sizeof(*cable), GFP_KERNEL);
if (!cable) {
kfree(dpcm);
err = -ENOMEM;
goto unlock;
}
Expand Down Expand Up @@ -723,6 +741,10 @@ static int loopback_open(struct snd_pcm_substream *substream)
else
runtime->hw = cable->hw;
unlock:
if (err < 0) {
free_cable(substream);
kfree(dpcm);
}
mutex_unlock(&loopback->cable_lock);
return err;
}
Expand All @@ -731,20 +753,10 @@ static int loopback_close(struct snd_pcm_substream *substream)
{
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;
}
Expand Down

0 comments on commit 9685347

Please sign in to comment.