Patch "ALSA: timer: Fix link corruption due to double start or stop" has been added to the 3.10-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    ALSA: timer: Fix link corruption due to double start or stop

to the 3.10-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-timer-fix-link-corruption-due-to-double-start-or-stop.patch
and it can be found in the queue-3.10 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.


>From f784beb75ce82f4136f8a0960d3ee872f7109e09 Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@xxxxxxx>
Date: Sat, 30 Jan 2016 23:09:08 +0100
Subject: ALSA: timer: Fix link corruption due to double start or stop

From: Takashi Iwai <tiwai@xxxxxxx>

commit f784beb75ce82f4136f8a0960d3ee872f7109e09 upstream.

Although ALSA timer code got hardening for races, it still causes
use-after-free error.  This is however rather a corrupted linked list,
not actually the concurrent accesses.  Namely, when timer start is
triggered twice, list_add_tail() is called twice, too.  This ends
up with the link corruption and triggers KASAN error.

The simplest fix would be replacing list_add_tail() with
list_move_tail(), but fundamentally it's the problem that we don't
check the double start/stop correctly.  So, the right fix here is to
add the proper checks to snd_timer_start() and snd_timer_stop() (and
their variants).

BugLink: http://lkml.kernel.org/r/CACT4Y+ZyPRoMQjmawbvmCEDrkBD2BQuH7R09=eOkf5ESK8kJAw@xxxxxxxxxxxxxx
Reported-by: Dmitry Vyukov <dvyukov@xxxxxxxxxx>
Signed-off-by: Takashi Iwai <tiwai@xxxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>

---
 sound/core/timer.c |   30 ++++++++++++++++++++++++++++--
 1 file changed, 28 insertions(+), 2 deletions(-)

--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -444,6 +444,10 @@ static int snd_timer_start_slave(struct
 	unsigned long flags;
 
 	spin_lock_irqsave(&slave_active_lock, flags);
+	if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING) {
+		spin_unlock_irqrestore(&slave_active_lock, flags);
+		return -EBUSY;
+	}
 	timeri->flags |= SNDRV_TIMER_IFLG_RUNNING;
 	if (timeri->master && timeri->timer) {
 		spin_lock(&timeri->timer->lock);
@@ -468,18 +472,26 @@ int snd_timer_start(struct snd_timer_ins
 		return -EINVAL;
 	if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) {
 		result = snd_timer_start_slave(timeri);
-		snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START);
+		if (result >= 0)
+			snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START);
 		return result;
 	}
 	timer = timeri->timer;
 	if (timer == NULL)
 		return -EINVAL;
 	spin_lock_irqsave(&timer->lock, flags);
+	if (timeri->flags & (SNDRV_TIMER_IFLG_RUNNING |
+			     SNDRV_TIMER_IFLG_START)) {
+		result = -EBUSY;
+		goto unlock;
+	}
 	timeri->ticks = timeri->cticks = ticks;
 	timeri->pticks = 0;
 	result = snd_timer_start1(timer, timeri, ticks);
+ unlock:
 	spin_unlock_irqrestore(&timer->lock, flags);
-	snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START);
+	if (result >= 0)
+		snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START);
 	return result;
 }
 
@@ -495,6 +507,10 @@ static int _snd_timer_stop(struct snd_ti
 	if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) {
 		if (!keep_flag) {
 			spin_lock_irqsave(&slave_active_lock, flags);
+			if (!(timeri->flags & SNDRV_TIMER_IFLG_RUNNING)) {
+				spin_unlock_irqrestore(&slave_active_lock, flags);
+				return -EBUSY;
+			}
 			timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING;
 			list_del_init(&timeri->ack_list);
 			list_del_init(&timeri->active_list);
@@ -506,6 +522,11 @@ static int _snd_timer_stop(struct snd_ti
 	if (!timer)
 		return -EINVAL;
 	spin_lock_irqsave(&timer->lock, flags);
+	if (!(timeri->flags & (SNDRV_TIMER_IFLG_RUNNING |
+			       SNDRV_TIMER_IFLG_START))) {
+		spin_unlock_irqrestore(&timer->lock, flags);
+		return -EBUSY;
+	}
 	list_del_init(&timeri->ack_list);
 	list_del_init(&timeri->active_list);
 	if ((timeri->flags & SNDRV_TIMER_IFLG_RUNNING) &&
@@ -571,10 +592,15 @@ int snd_timer_continue(struct snd_timer_
 	if (! timer)
 		return -EINVAL;
 	spin_lock_irqsave(&timer->lock, flags);
+	if (timeri->flags & SNDRV_TIMER_IFLG_RUNNING) {
+		result = -EBUSY;
+		goto unlock;
+	}
 	if (!timeri->cticks)
 		timeri->cticks = 1;
 	timeri->pticks = 0;
 	result = snd_timer_start1(timer, timeri, timer->sticks);
+ unlock:
 	spin_unlock_irqrestore(&timer->lock, flags);
 	snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_CONTINUE);
 	return result;


Patches currently in stable-queue which might be from tiwai@xxxxxxx are

queue-3.10/alsa-seq-fix-race-at-closing-in-virmidi-driver.patch
queue-3.10/alsa-rawmidi-remove-kernel-warning-for-null-user-space-buffer-check.patch
queue-3.10/alsa-seq-fix-lockdep-warnings-due-to-double-mutex-locks.patch
queue-3.10/alsa-usb-audio-fix-teac-ud-501-ud-503-nt-503-usb-delay.patch
queue-3.10/alsa-timer-fix-wrong-instance-passed-to-slave-callbacks.patch
queue-3.10/alsa-compress-disable-get_codec_caps-ioctl-for-some-architectures.patch
queue-3.10/alsa-hda-fix-speaker-output-from-vaio-aio-machines.patch
queue-3.10/alsa-dummy-implement-timer-backend-switching-more-safely.patch
queue-3.10/alsa-dummy-disable-switching-timer-backend-via-sysfs.patch
queue-3.10/alsa-seq-fix-incorrect-sanity-check-at-snd_seq_oss_synth_cleanup.patch
queue-3.10/alsa-seq-fix-yet-another-races-among-alsa-timer-accesses.patch
queue-3.10/alsa-usb-audio-avoid-freeing-umidi-object-twice.patch
queue-3.10/alsa-timer-fix-leftover-link-at-closing.patch
queue-3.10/alsa-rawmidi-fix-race-at-copying-updating-the-position.patch
queue-3.10/alsa-pcm-fix-potential-deadlock-in-oss-emulation.patch
queue-3.10/alsa-timer-fix-link-corruption-due-to-double-start-or-stop.patch
--
To unsubscribe from this list: send the line "unsubscribe stable" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Kernel]     [Kernel Development Newbies]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]