Patch "ALSA: seq: Fix yet another races among ALSA timer accesses" has been added to the 3.14-stable tree
Subsystems (2)
This is a note to let you know that I've just added the patch titled
ALSA: seq: Fix yet another races among ALSA timer accesses
to the 3.14-stable tree which can be found at:
http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary
The filename of the patch is:
alsa-seq-fix-yet-another-races-among-alsa-timer-accesses.patch
and it can be found in the queue-3.14 subdirectory.
If you, or anyone else, feels it should not be added to the stable tree, please let <[email protected]> know about it.
Quoted 1 line
From
2cdc7b636d55cbcf42e1e6c8accd85e62d3e9ae8Mon Sep 17 00:00:00 2001
From: Takashi Iwai <[email protected]>
Date: Sat, 30 Jan 2016 23:30:25 +0100
Subject: ALSA: seq: Fix yet another races among ALSA timer accesses
From: Takashi Iwai <[email protected]>
commit 2cdc7b636d55cbcf42e1e6c8accd85e62d3e9ae8 upstream.
ALSA sequencer may open/close and control ALSA timer instance dynamically either via sequencer events or direct ioctls. These are done mostly asynchronously, and it may call still some timer action like snd_timer_start() while another is calling snd_timer_close(). Since the instance gets removed by snd_timer_close(), it may lead to a use-after-free.
This patch tries to address such a race by protecting each snd_timer_*() call via the existing spinlock and also by avoiding the access to timer during close call.
--- sound/core/seq/seq_timer.c | 87 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 67 insertions(+), 20 deletions(-)
sound/core/seq/seq_timer.c +67 -20
@@ -92,6 +92,9 @@ void snd_seq_timer_delete(struct snd_seqvoid snd_seq_timer_defaults (struct snd_seq_timer * tmr) { +unsigned long flags; + +spin_lock_irqsave (&tmr->lock, flags);/* setup defaults */ tmr->ppq =96 ;/* 96 PPQ */ tmr->tempo =500000 ;/* 120 BPM */
@@ -107,21 +110,25 @@ void snd_seq_timer_defaults(struct snd_s tmr->preferred_resolution = seq_default_timer_resolution; tmr->skew = tmr->skew_base =SKEW_BASE ; +spin_unlock_irqrestore (&tmr->lock, flags); } -void snd_seq_timer_reset (struct snd_seq_timer * tmr) +static void seq_timer_reset (struct snd_seq_timer *tmr) { -unsigned long flags; - -spin_lock_irqsave (&tmr->lock, flags); -/* reset time & songposition */ tmr->cur_time.tv_sec =0 ; tmr->cur_time.tv_nsec =0 ; tmr->tick.cur_tick =0 ; tmr->tick.fraction =0 ; +} + +void snd_seq_timer_reset (struct snd_seq_timer *tmr) +{ +unsigned long flags; +spin_lock_irqsave (&tmr->lock, flags); +seq_timer_reset (tmr);spin_unlock_irqrestore (&tmr->lock, flags); }
@@ -140,8 +147,11 @@ static void snd_seq_timer_interrupt(stru tmr = q->timer;if (tmr ==NULL )return ; -if (!tmr->running) +spin_lock_irqsave (&tmr->lock, flags); +if (!tmr->running) { +spin_unlock_irqrestore (&tmr->lock, flags);return ; + } resolution *= ticks;if (tmr->skew != tmr->skew_base) {
@@ -150,8 +160,6 @@ static void snd_seq_timer_interrupt(stru (((resolution &0xffff ) * tmr->skew) >>16 ); } -spin_lock_irqsave (&tmr->lock, flags); -/* update timer */ snd_seq_inc_time_nsec (&tmr->cur_time, resolution);
@@ -298,26 +306,30 @@ int snd_seq_timer_open(struct snd_seq_qu t->callback = snd_seq_timer_interrupt; t->callback_data = q; t->flags |=SNDRV_TIMER_IFLG_AUTO ; +spin_lock_irq (&tmr->lock); tmr->timeri = t; +spin_unlock_irq (&tmr->lock);return 0 ; }int snd_seq_timer_close (struct snd_seq_queue *q) {struct snd_seq_timer *tmr; +struct snd_timer_instance *t; tmr = q->timer;if (snd_BUG_ON (!tmr))return -EINVAL ; -if (tmr->timeri) { -snd_timer_stop (tmr->timeri); -snd_timer_close (tmr->timeri); - tmr->timeri =NULL ; - } +spin_lock_irq (&tmr->lock); + t = tmr->timeri; + tmr->timeri =NULL ; +spin_unlock_irq (&tmr->lock); +if (t) +snd_timer_close (t);return 0 ; } -int snd_seq_timer_stop (struct snd_seq_timer * tmr) +static int seq_timer_stop (struct snd_seq_timer *tmr) {if (! tmr->timeri)return -EINVAL ;
@@ -328,6 +340,17 @@ int snd_seq_timer_stop(struct snd_seq_tireturn 0 ; } +int snd_seq_timer_stop (struct snd_seq_timer *tmr) +{ +unsigned long flags; +int err; + +spin_lock_irqsave (&tmr->lock, flags); + err =seq_timer_stop (tmr); +spin_unlock_irqrestore (&tmr->lock, flags); +return err; +} +static int initialize_timer (struct snd_seq_timer *tmr) {struct snd_timer *t;
@@ -360,13 +383,13 @@ static int initialize_timer(struct snd_sreturn 0 ; } -int snd_seq_timer_start (struct snd_seq_timer * tmr) +static int seq_timer_start (struct snd_seq_timer *tmr) {if (! tmr->timeri)return -EINVAL ;if (tmr->running) -snd_seq_timer_stop (tmr); -snd_seq_timer_reset (tmr); +seq_timer_stop (tmr); +seq_timer_reset (tmr);if (initialize_timer (tmr) <0 )return -EINVAL ;snd_timer_start (tmr->timeri, tmr->ticks);
@@ -375,14 +398,25 @@ int snd_seq_timer_start(struct snd_seq_treturn 0 ; } -int snd_seq_timer_continue (struct snd_seq_timer * tmr) +int snd_seq_timer_start (struct snd_seq_timer *tmr) +{ +unsigned long flags; +int err; + +spin_lock_irqsave (&tmr->lock, flags); + err =seq_timer_start (tmr); +spin_unlock_irqrestore (&tmr->lock, flags); +return err; +} + +static int seq_timer_continue (struct snd_seq_timer *tmr) {if (! tmr->timeri)return -EINVAL ;if (tmr->running)return -EBUSY ;if (! tmr->initialized) { -snd_seq_timer_reset (tmr); +seq_timer_reset (tmr);if (initialize_timer (tmr) <0 )return -EINVAL ; }
@@ -392,11 +426,24 @@ int snd_seq_timer_continue(struct snd_sereturn 0 ; } +int snd_seq_timer_continue (struct snd_seq_timer *tmr) +{ +unsigned long flags; +int err; + +spin_lock_irqsave (&tmr->lock, flags); + err =seq_timer_continue (tmr); +spin_unlock_irqrestore (&tmr->lock, flags); +return err; +} +/* return current 'real' time. use timeofday() to get better granularity. */ snd_seq_real_time_t snd_seq_timer_get_cur_time (struct snd_seq_timer *tmr) {snd_seq_real_time_t cur_time; +unsigned long flags; +spin_lock_irqsave (&tmr->lock, flags); cur_time = tmr->cur_time;if (tmr->running) {struct timeval tm;
@@ -412,7 +459,7 @@ snd_seq_real_time_t snd_seq_timer_get_cu }snd_seq_sanity_real_time (&cur_time); } - +spin_unlock_irqrestore (&tmr->lock, flags);return cur_time; }
Patches currently in stable-queue which might be from [email protected] are
queue-3.14/alsa-seq-fix-race-at-closing-in-virmidi-driver.patch queue-3.14/alsa-rawmidi-remove-kernel-warning-for-null-user-space-buffer-check.patch queue-3.14/alsa-hda-fix-static-checker-warning-in-patch_hdmi.c.patch queue-3.14/alsa-seq-fix-lockdep-warnings-due-to-double-mutex-locks.patch queue-3.14/alsa-usb-audio-fix-teac-ud-501-ud-503-nt-503-usb-delay.patch queue-3.14/alsa-timer-fix-wrong-instance-passed-to-slave-callbacks.patch queue-3.14/alsa-compress-disable-get_codec_caps-ioctl-for-some-architectures.patch queue-3.14/alsa-hda-fix-speaker-output-from-vaio-aio-machines.patch queue-3.14/alsa-dummy-implement-timer-backend-switching-more-safely.patch queue-3.14/alsa-dummy-disable-switching-timer-backend-via-sysfs.patch queue-3.14/alsa-seq-fix-incorrect-sanity-check-at-snd_seq_oss_synth_cleanup.patch queue-3.14/alsa-seq-fix-yet-another-races-among-alsa-timer-accesses.patch queue-3.14/alsa-usb-audio-avoid-freeing-umidi-object-twice.patch queue-3.14/alsa-hda-add-fixup-for-mac-mini-7-1-model.patch queue-3.14/alsa-timer-fix-leftover-link-at-closing.patch queue-3.14/alsa-rawmidi-fix-race-at-copying-updating-the-position.patch queue-3.14/alsa-pcm-fix-potential-deadlock-in-oss-emulation.patch queue-3.14/alsa-timer-fix-link-corruption-due-to-double-start-or-stop.patch