aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2018-01-05 10:09:47 -0500
committerTakashi Iwai <tiwai@suse.de>2018-01-05 10:22:20 -0500
commit9685347aa0a5c2869058ca6ab79fd8e93084a67f (patch)
tree652ff2b454109ec274639e6ec05825c8601604b7
parentfb51f1cd06f9ced7b7085a2a4636375d520431ca (diff)
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: 597603d615d2 ("ALSA: introduce the snd-aloop module for the PCM loopback") Cc: <stable@vger.kernel.org> Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/drivers/aloop.c38
1 files changed, 25 insertions, 13 deletions
diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c
index afac886ffa28..8b6a39cb7f06 100644
--- a/sound/drivers/aloop.c
+++ b/sound/drivers/aloop.c
@@ -658,12 +658,31 @@ static int rule_channels(struct snd_pcm_hw_params *params,
658 return snd_interval_refine(hw_param_interval(params, rule->var), &t); 658 return snd_interval_refine(hw_param_interval(params, rule->var), &t);
659} 659}
660 660
661static 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
661static int loopback_open(struct snd_pcm_substream *substream) 680static int loopback_open(struct snd_pcm_substream *substream)
662{ 681{
663 struct snd_pcm_runtime *runtime = substream->runtime; 682 struct snd_pcm_runtime *runtime = substream->runtime;
664 struct loopback *loopback = substream->private_data; 683 struct loopback *loopback = substream->private_data;
665 struct loopback_pcm *dpcm; 684 struct loopback_pcm *dpcm;
666 struct loopback_cable *cable; 685 struct loopback_cable *cable = NULL;
667 int err = 0; 686 int err = 0;
668 int dev = get_cable_index(substream); 687 int dev = get_cable_index(substream);
669 688
@@ -681,7 +700,6 @@ static int loopback_open(struct snd_pcm_substream *substream)
681 if (!cable) { 700 if (!cable) {
682 cable = kzalloc(sizeof(*cable), GFP_KERNEL); 701 cable = kzalloc(sizeof(*cable), GFP_KERNEL);
683 if (!cable) { 702 if (!cable) {
684 kfree(dpcm);
685 err = -ENOMEM; 703 err = -ENOMEM;
686 goto unlock; 704 goto unlock;
687 } 705 }
@@ -723,6 +741,10 @@ static int loopback_open(struct snd_pcm_substream *substream)
723 else 741 else
724 runtime->hw = cable->hw; 742 runtime->hw = cable->hw;
725 unlock: 743 unlock:
744 if (err < 0) {
745 free_cable(substream);
746 kfree(dpcm);
747 }
726 mutex_unlock(&loopback->cable_lock); 748 mutex_unlock(&loopback->cable_lock);
727 return err; 749 return err;
728} 750}
@@ -731,20 +753,10 @@ static int loopback_close(struct snd_pcm_substream *substream)
731{ 753{
732 struct loopback *loopback = substream->private_data; 754 struct loopback *loopback = substream->private_data;
733 struct loopback_pcm *dpcm = substream->runtime->private_data; 755 struct loopback_pcm *dpcm = substream->runtime->private_data;
734 struct loopback_cable *cable;
735 int dev = get_cable_index(substream);
736 756
737 loopback_timer_stop(dpcm); 757 loopback_timer_stop(dpcm);
738 mutex_lock(&loopback->cable_lock); 758 mutex_lock(&loopback->cable_lock);
739 cable = loopback->cables[substream->number][dev]; 759 free_cable(substream);
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 }
748 mutex_unlock(&loopback->cable_lock); 760 mutex_unlock(&loopback->cable_lock);
749 return 0; 761 return 0;
750} 762}