Skip to content

Commit 9685347

Browse files
committed
ALSA: aloop: Release cable upon open error path
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: <[email protected]> Signed-off-by: Takashi Iwai <[email protected]>
1 parent fb51f1c commit 9685347

File tree

1 file changed

+25
-13
lines changed

1 file changed

+25
-13
lines changed

sound/drivers/aloop.c

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -658,12 +658,31 @@ static int rule_channels(struct snd_pcm_hw_params *params,
658658
return snd_interval_refine(hw_param_interval(params, rule->var), &t);
659659
}
660660

661+
static void free_cable(struct snd_pcm_substream *substream)
662+
{
663+
struct loopback *loopback = substream->private_data;
664+
int dev = get_cable_index(substream);
665+
struct loopback_cable *cable;
666+
667+
cable = loopback->cables[substream->number][dev];
668+
if (!cable)
669+
return;
670+
if (cable->streams[!substream->stream]) {
671+
/* other stream is still alive */
672+
cable->streams[substream->stream] = NULL;
673+
} else {
674+
/* free the cable */
675+
loopback->cables[substream->number][dev] = NULL;
676+
kfree(cable);
677+
}
678+
}
679+
661680
static int loopback_open(struct snd_pcm_substream *substream)
662681
{
663682
struct snd_pcm_runtime *runtime = substream->runtime;
664683
struct loopback *loopback = substream->private_data;
665684
struct loopback_pcm *dpcm;
666-
struct loopback_cable *cable;
685+
struct loopback_cable *cable = NULL;
667686
int err = 0;
668687
int dev = get_cable_index(substream);
669688

@@ -681,7 +700,6 @@ static int loopback_open(struct snd_pcm_substream *substream)
681700
if (!cable) {
682701
cable = kzalloc(sizeof(*cable), GFP_KERNEL);
683702
if (!cable) {
684-
kfree(dpcm);
685703
err = -ENOMEM;
686704
goto unlock;
687705
}
@@ -723,6 +741,10 @@ static int loopback_open(struct snd_pcm_substream *substream)
723741
else
724742
runtime->hw = cable->hw;
725743
unlock:
744+
if (err < 0) {
745+
free_cable(substream);
746+
kfree(dpcm);
747+
}
726748
mutex_unlock(&loopback->cable_lock);
727749
return err;
728750
}
@@ -731,20 +753,10 @@ static int loopback_close(struct snd_pcm_substream *substream)
731753
{
732754
struct loopback *loopback = substream->private_data;
733755
struct loopback_pcm *dpcm = substream->runtime->private_data;
734-
struct loopback_cable *cable;
735-
int dev = get_cable_index(substream);
736756

737757
loopback_timer_stop(dpcm);
738758
mutex_lock(&loopback->cable_lock);
739-
cable = loopback->cables[substream->number][dev];
740-
if (cable->streams[!substream->stream]) {
741-
/* other stream is still alive */
742-
cable->streams[substream->stream] = NULL;
743-
} else {
744-
/* free the cable */
745-
loopback->cables[substream->number][dev] = NULL;
746-
kfree(cable);
747-
}
759+
free_cable(substream);
748760
mutex_unlock(&loopback->cable_lock);
749761
return 0;
750762
}

0 commit comments

Comments
 (0)