mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
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: 597603d615
("ALSA: introduce the snd-aloop module for the PCM loopback")
Cc: <stable@vger.kernel.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
parent
fb51f1cd06
commit
9685347aa0
1 changed files with 25 additions and 13 deletions
|
@ -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);
|
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)
|
static int loopback_open(struct snd_pcm_substream *substream)
|
||||||
{
|
{
|
||||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||||
struct loopback *loopback = substream->private_data;
|
struct loopback *loopback = substream->private_data;
|
||||||
struct loopback_pcm *dpcm;
|
struct loopback_pcm *dpcm;
|
||||||
struct loopback_cable *cable;
|
struct loopback_cable *cable = NULL;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
int dev = get_cable_index(substream);
|
int dev = get_cable_index(substream);
|
||||||
|
|
||||||
|
@ -681,7 +700,6 @@ static int loopback_open(struct snd_pcm_substream *substream)
|
||||||
if (!cable) {
|
if (!cable) {
|
||||||
cable = kzalloc(sizeof(*cable), GFP_KERNEL);
|
cable = kzalloc(sizeof(*cable), GFP_KERNEL);
|
||||||
if (!cable) {
|
if (!cable) {
|
||||||
kfree(dpcm);
|
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
|
@ -723,6 +741,10 @@ static int loopback_open(struct snd_pcm_substream *substream)
|
||||||
else
|
else
|
||||||
runtime->hw = cable->hw;
|
runtime->hw = cable->hw;
|
||||||
unlock:
|
unlock:
|
||||||
|
if (err < 0) {
|
||||||
|
free_cable(substream);
|
||||||
|
kfree(dpcm);
|
||||||
|
}
|
||||||
mutex_unlock(&loopback->cable_lock);
|
mutex_unlock(&loopback->cable_lock);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -731,20 +753,10 @@ static int loopback_close(struct snd_pcm_substream *substream)
|
||||||
{
|
{
|
||||||
struct loopback *loopback = substream->private_data;
|
struct loopback *loopback = substream->private_data;
|
||||||
struct loopback_pcm *dpcm = substream->runtime->private_data;
|
struct loopback_pcm *dpcm = substream->runtime->private_data;
|
||||||
struct loopback_cable *cable;
|
|
||||||
int dev = get_cable_index(substream);
|
|
||||||
|
|
||||||
loopback_timer_stop(dpcm);
|
loopback_timer_stop(dpcm);
|
||||||
mutex_lock(&loopback->cable_lock);
|
mutex_lock(&loopback->cable_lock);
|
||||||
cable = loopback->cables[substream->number][dev];
|
free_cable(substream);
|
||||||
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);
|
|
||||||
}
|
|
||||||
mutex_unlock(&loopback->cable_lock);
|
mutex_unlock(&loopback->cable_lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue