aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2018-03-22 03:56:06 -0400
committerTakashi Iwai <tiwai@suse.de>2018-03-22 05:34:12 -0400
commit67a01afaf3d34893cf7d2ea19b34555d6abb7cb0 (patch)
treeb499d7415039119c5bc6441d9ac2ed416fba70b8
parent88d42b2b45d7208cc872c2c9dec0b1ae6c6008d7 (diff)
ALSA: aloop: Sync stale timer before release
The aloop driver tries to stop the pending timer via timer_del() in the trigger callback and in the close callback. The former is correct, as it's an atomic operation, while the latter expects that the timer gets really removed and proceeds the resource releases after that. But timer_del() doesn't synchronize, hence the running timer may still access the released resources. A similar situation can be also seen in the prepare callback after trigger(STOP) where the prepare tries to re-initialize the things while a timer is still running. The problems like the above are seen indirectly in some syzkaller reports (although it's not 100% clear whether this is the only cause, as the race condition is quite narrow and not always easy to trigger). For addressing these issues, this patch adds the explicit alls of timer_del_sync() in some places, so that the pending timer is properly killed / synced. Cc: <stable@vger.kernel.org> Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/drivers/aloop.c9
1 files changed, 8 insertions, 1 deletions
diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c
index 0333143a1fa7..0a08e63e9c66 100644
--- a/sound/drivers/aloop.c
+++ b/sound/drivers/aloop.c
@@ -192,6 +192,11 @@ static inline void loopback_timer_stop(struct loopback_pcm *dpcm)
192 dpcm->timer.expires = 0; 192 dpcm->timer.expires = 0;
193} 193}
194 194
195static inline void loopback_timer_stop_sync(struct loopback_pcm *dpcm)
196{
197 del_timer_sync(&dpcm->timer);
198}
199
195#define CABLE_VALID_PLAYBACK (1 << SNDRV_PCM_STREAM_PLAYBACK) 200#define CABLE_VALID_PLAYBACK (1 << SNDRV_PCM_STREAM_PLAYBACK)
196#define CABLE_VALID_CAPTURE (1 << SNDRV_PCM_STREAM_CAPTURE) 201#define CABLE_VALID_CAPTURE (1 << SNDRV_PCM_STREAM_CAPTURE)
197#define CABLE_VALID_BOTH (CABLE_VALID_PLAYBACK|CABLE_VALID_CAPTURE) 202#define CABLE_VALID_BOTH (CABLE_VALID_PLAYBACK|CABLE_VALID_CAPTURE)
@@ -326,6 +331,8 @@ static int loopback_prepare(struct snd_pcm_substream *substream)
326 struct loopback_cable *cable = dpcm->cable; 331 struct loopback_cable *cable = dpcm->cable;
327 int bps, salign; 332 int bps, salign;
328 333
334 loopback_timer_stop_sync(dpcm);
335
329 salign = (snd_pcm_format_width(runtime->format) * 336 salign = (snd_pcm_format_width(runtime->format) *
330 runtime->channels) / 8; 337 runtime->channels) / 8;
331 bps = salign * runtime->rate; 338 bps = salign * runtime->rate;
@@ -744,7 +751,7 @@ static int loopback_close(struct snd_pcm_substream *substream)
744 struct loopback *loopback = substream->private_data; 751 struct loopback *loopback = substream->private_data;
745 struct loopback_pcm *dpcm = substream->runtime->private_data; 752 struct loopback_pcm *dpcm = substream->runtime->private_data;
746 753
747 loopback_timer_stop(dpcm); 754 loopback_timer_stop_sync(dpcm);
748 mutex_lock(&loopback->cable_lock); 755 mutex_lock(&loopback->cable_lock);
749 free_cable(substream); 756 free_cable(substream);
750 mutex_unlock(&loopback->cable_lock); 757 mutex_unlock(&loopback->cable_lock);