ALSA: aloop: Release cable upon open error path
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 <tiwai@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
fa6c1876ec
commit
3d3b2c61e1
@ -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);
|
||||
|
||||
@ -682,7 +701,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;
|
||||
}
|
||||
@ -724,6 +742,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;
|
||||
}
|
||||
@ -732,20 +754,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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user