Patch "ALSA: rawmidi: Fix race at copying & updating the position" has been added to the 4.4-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: rawmidi: Fix race at copying & updating the position

to the 4.4-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-rawmidi-fix-race-at-copying-updating-the-position.patch
and it can be found in the queue-4.4 subdirectory.

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


>From 81f577542af15640cbcb6ef68baa4caa610cbbfc Mon Sep 17 00:00:00 2001
From: Takashi Iwai <tiwai@xxxxxxx>
Date: Wed, 3 Feb 2016 14:41:22 +0100
Subject: ALSA: rawmidi: Fix race at copying & updating the position

From: Takashi Iwai <tiwai@xxxxxxx>

commit 81f577542af15640cbcb6ef68baa4caa610cbbfc upstream.

The rawmidi read and write functions manage runtime stream status
such as runtime->appl_ptr and runtime->avail.  These point where to
copy the new data and how many bytes have been copied (or to be
read).  The problem is that rawmidi read/write call copy_from_user()
or copy_to_user(), and the runtime spinlock is temporarily unlocked
and relocked while copying user-space.  Since the current code
advances and updates the runtime status after the spin unlock/relock,
the copy and the update may be asynchronous, and eventually
runtime->avail might go to a negative value when many concurrent
accesses are done.  This may lead to memory corruption in the end.

For fixing this race, in this patch, the status update code is
performed in the same lock before the temporary unlock.  Also, the
spinlock is now taken more widely in snd_rawmidi_kernel_read1() for
protecting more properly during the whole operation.

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

---
 sound/core/rawmidi.c |   34 ++++++++++++++++++++++------------
 1 file changed, 22 insertions(+), 12 deletions(-)

--- a/sound/core/rawmidi.c
+++ b/sound/core/rawmidi.c
@@ -942,31 +942,36 @@ static long snd_rawmidi_kernel_read1(str
 	unsigned long flags;
 	long result = 0, count1;
 	struct snd_rawmidi_runtime *runtime = substream->runtime;
+	unsigned long appl_ptr;
 
+	spin_lock_irqsave(&runtime->lock, flags);
 	while (count > 0 && runtime->avail) {
 		count1 = runtime->buffer_size - runtime->appl_ptr;
 		if (count1 > count)
 			count1 = count;
-		spin_lock_irqsave(&runtime->lock, flags);
 		if (count1 > (int)runtime->avail)
 			count1 = runtime->avail;
+
+		/* update runtime->appl_ptr before unlocking for userbuf */
+		appl_ptr = runtime->appl_ptr;
+		runtime->appl_ptr += count1;
+		runtime->appl_ptr %= runtime->buffer_size;
+		runtime->avail -= count1;
+
 		if (kernelbuf)
-			memcpy(kernelbuf + result, runtime->buffer + runtime->appl_ptr, count1);
+			memcpy(kernelbuf + result, runtime->buffer + appl_ptr, count1);
 		if (userbuf) {
 			spin_unlock_irqrestore(&runtime->lock, flags);
 			if (copy_to_user(userbuf + result,
-					 runtime->buffer + runtime->appl_ptr, count1)) {
+					 runtime->buffer + appl_ptr, count1)) {
 				return result > 0 ? result : -EFAULT;
 			}
 			spin_lock_irqsave(&runtime->lock, flags);
 		}
-		runtime->appl_ptr += count1;
-		runtime->appl_ptr %= runtime->buffer_size;
-		runtime->avail -= count1;
-		spin_unlock_irqrestore(&runtime->lock, flags);
 		result += count1;
 		count -= count1;
 	}
+	spin_unlock_irqrestore(&runtime->lock, flags);
 	return result;
 }
 
@@ -1223,6 +1228,7 @@ static long snd_rawmidi_kernel_write1(st
 	unsigned long flags;
 	long count1, result;
 	struct snd_rawmidi_runtime *runtime = substream->runtime;
+	unsigned long appl_ptr;
 
 	if (!kernelbuf && !userbuf)
 		return -EINVAL;
@@ -1243,12 +1249,19 @@ static long snd_rawmidi_kernel_write1(st
 			count1 = count;
 		if (count1 > (long)runtime->avail)
 			count1 = runtime->avail;
+
+		/* update runtime->appl_ptr before unlocking for userbuf */
+		appl_ptr = runtime->appl_ptr;
+		runtime->appl_ptr += count1;
+		runtime->appl_ptr %= runtime->buffer_size;
+		runtime->avail -= count1;
+
 		if (kernelbuf)
-			memcpy(runtime->buffer + runtime->appl_ptr,
+			memcpy(runtime->buffer + appl_ptr,
 			       kernelbuf + result, count1);
 		else if (userbuf) {
 			spin_unlock_irqrestore(&runtime->lock, flags);
-			if (copy_from_user(runtime->buffer + runtime->appl_ptr,
+			if (copy_from_user(runtime->buffer + appl_ptr,
 					   userbuf + result, count1)) {
 				spin_lock_irqsave(&runtime->lock, flags);
 				result = result > 0 ? result : -EFAULT;
@@ -1256,9 +1269,6 @@ static long snd_rawmidi_kernel_write1(st
 			}
 			spin_lock_irqsave(&runtime->lock, flags);
 		}
-		runtime->appl_ptr += count1;
-		runtime->appl_ptr %= runtime->buffer_size;
-		runtime->avail -= count1;
 		result += count1;
 		count -= count1;
 	}


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

queue-4.4/alsa-seq-fix-race-at-closing-in-virmidi-driver.patch
queue-4.4/alsa-hda-fix-bad-dereference-of-jack-object.patch
queue-4.4/alsa-usb-audio-add-quirk-for-microsoft-lifecam-hd-6000.patch
queue-4.4/alsa-rawmidi-remove-kernel-warning-for-null-user-space-buffer-check.patch
queue-4.4/alsa-usb-audio-fix-oppo-ha-1-vendor-id.patch
queue-4.4/alsa-timer-fix-race-at-concurrent-reads.patch
queue-4.4/alsa-hda-realtek-support-dell-headset-mode-for-alc225.patch
queue-4.4/alsa-hda-fix-static-checker-warning-in-patch_hdmi.c.patch
queue-4.4/alsa-seq-fix-lockdep-warnings-due-to-double-mutex-locks.patch
queue-4.4/alsa-usb-audio-fix-teac-ud-501-ud-503-nt-503-usb-delay.patch
queue-4.4/alsa-timer-fix-wrong-instance-passed-to-slave-callbacks.patch
queue-4.4/alsa-hda-disable-dynamic-clock-gating-on-broxton-before-reset.patch
queue-4.4/alsa-hda-realtek-support-headset-mode-for-alc225.patch
queue-4.4/alsa-hda-implement-loopback-control-switch-for-realtek-and-other-codecs.patch
queue-4.4/alsa-hda-realtek-new-codec-support-of-alc225.patch
queue-4.4/alsa-seq-degrade-the-error-message-for-too-many-opens.patch
queue-4.4/alsa-compress-disable-get_codec_caps-ioctl-for-some-architectures.patch
queue-4.4/alsa-rawmidi-make-snd_rawmidi_transmit-race-free.patch
queue-4.4/alsa-hda-fix-speaker-output-from-vaio-aio-machines.patch
queue-4.4/alsa-bebob-use-a-signed-return-type-for-get_formation_index.patch
queue-4.4/alsa-add-missing-dependency-on-config_snd_timer.patch
queue-4.4/alsa-dummy-implement-timer-backend-switching-more-safely.patch
queue-4.4/alsa-dummy-disable-switching-timer-backend-via-sysfs.patch
queue-4.4/alsa-seq-fix-incorrect-sanity-check-at-snd_seq_oss_synth_cleanup.patch
queue-4.4/alsa-seq-fix-yet-another-races-among-alsa-timer-accesses.patch
queue-4.4/alsa-usb-audio-avoid-freeing-umidi-object-twice.patch
queue-4.4/revert-alsa-hda-fix-noise-on-gigabyte-z170x-mobo.patch
queue-4.4/alsa-hda-add-fixup-for-mac-mini-7-1-model.patch
queue-4.4/alsa-usb-audio-add-native-dsd-support-for-ps-audio-nuwave-dac.patch
queue-4.4/alsa-timer-fix-leftover-link-at-closing.patch
queue-4.4/alsa-rawmidi-fix-race-at-copying-updating-the-position.patch
queue-4.4/alsa-pcm-fix-potential-deadlock-in-oss-emulation.patch
queue-4.4/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]