--- /dev/null
+From 462b3f161beb62eeb290f4ec52f5ead29a2f8ac7 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Mon, 25 Jan 2016 13:59:21 +0100
+Subject: ALSA: compress: Disable GET_CODEC_CAPS ioctl for some architectures
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit 462b3f161beb62eeb290f4ec52f5ead29a2f8ac7 upstream.
+
+Some architectures like PowerPC can handle the maximum struct size in
+an ioctl only up to 13 bits, and struct snd_compr_codec_caps used by
+SNDRV_COMPRESS_GET_CODEC_CAPS ioctl overflows this limit. This
+problem was revealed recently by a powerpc change, as it's now treated
+as a fatal build error.
+
+This patch is a stop-gap for that: for architectures with less than 14
+bit ioctl struct size, get rid of the handling of the relevant ioctl.
+We should provide an alternative equivalent ioctl code later, but for
+now just paper over it. Luckily, the compress API hasn't been used on
+such architectures, so the impact must be effectively zero.
+
+Reviewed-by: Mark Brown <broonie@kernel.org>
+Acked-by: Sudip Mukherjee <sudipm.mukherjee@gmail.com>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/core/compress_offload.c | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+--- a/sound/core/compress_offload.c
++++ b/sound/core/compress_offload.c
+@@ -44,6 +44,13 @@
+ #include <sound/compress_offload.h>
+ #include <sound/compress_driver.h>
+
++/* struct snd_compr_codec_caps overflows the ioctl bit size for some
++ * architectures, so we need to disable the relevant ioctls.
++ */
++#if _IOC_SIZEBITS < 14
++#define COMPR_CODEC_CAPS_OVERFLOW
++#endif
++
+ /* TODO:
+ * - add substream support for multiple devices in case of
+ * SND_DYNAMIC_MINORS is not used
+@@ -427,6 +434,7 @@ out:
+ return retval;
+ }
+
++#ifndef COMPR_CODEC_CAPS_OVERFLOW
+ static int
+ snd_compr_get_codec_caps(struct snd_compr_stream *stream, unsigned long arg)
+ {
+@@ -450,6 +458,7 @@ out:
+ kfree(caps);
+ return retval;
+ }
++#endif /* !COMPR_CODEC_CAPS_OVERFLOW */
+
+ /* revisit this with snd_pcm_preallocate_xxx */
+ static int snd_compr_allocate_buffer(struct snd_compr_stream *stream,
+@@ -791,9 +800,11 @@ static long snd_compr_ioctl(struct file
+ case _IOC_NR(SNDRV_COMPRESS_GET_CAPS):
+ retval = snd_compr_get_caps(stream, arg);
+ break;
++#ifndef COMPR_CODEC_CAPS_OVERFLOW
+ case _IOC_NR(SNDRV_COMPRESS_GET_CODEC_CAPS):
+ retval = snd_compr_get_codec_caps(stream, arg);
+ break;
++#endif
+ case _IOC_NR(SNDRV_COMPRESS_SET_PARAMS):
+ retval = snd_compr_set_params(stream, arg);
+ break;
--- /dev/null
+From 7ee96216c31aabe1eb42fb91ff50dae9fcd014b2 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Thu, 28 Jan 2016 07:54:16 +0100
+Subject: ALSA: dummy: Disable switching timer backend via sysfs
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit 7ee96216c31aabe1eb42fb91ff50dae9fcd014b2 upstream.
+
+ALSA dummy driver can switch the timer backend between system timer
+and hrtimer via its hrtimer module option. This can be also switched
+dynamically via sysfs, but it may lead to a memory corruption when
+switching is done while a PCM stream is running; the stream instance
+for the newly switched timer method tries to access the memory that
+was allocated by another timer method although the sizes differ.
+
+As the simplest fix, this patch just disables the switch via sysfs by
+dropping the writable bit.
+
+BugLink: http://lkml.kernel.org/r/CACT4Y+ZGEeEBntHW5WHn2GoeE0G_kRrCmUh6=dWyy-wfzvuJLg@mail.gmail.com
+Reported-by: Dmitry Vyukov <dvyukov@google.com>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/drivers/dummy.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/sound/drivers/dummy.c
++++ b/sound/drivers/dummy.c
+@@ -87,7 +87,7 @@ MODULE_PARM_DESC(pcm_substreams, "PCM su
+ module_param(fake_buffer, bool, 0444);
+ MODULE_PARM_DESC(fake_buffer, "Fake buffer allocations.");
+ #ifdef CONFIG_HIGH_RES_TIMERS
+-module_param(hrtimer, bool, 0644);
++module_param(hrtimer, bool, 0444);
+ MODULE_PARM_DESC(hrtimer, "Use hrtimer as the timer source.");
+ #endif
+
--- /dev/null
+From ddce57a6f0a2d8d1bfacfa77f06043bc760403c2 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Tue, 2 Feb 2016 15:27:36 +0100
+Subject: ALSA: dummy: Implement timer backend switching more safely
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit ddce57a6f0a2d8d1bfacfa77f06043bc760403c2 upstream.
+
+Currently the selected timer backend is referred at any moment from
+the running PCM callbacks. When the backend is switched, it's
+possible to lead to inconsistency from the running backend. This was
+pointed by syzkaller fuzzer, and the commit [7ee96216c31a: ALSA:
+dummy: Disable switching timer backend via sysfs] disabled the dynamic
+switching for avoiding the crash.
+
+This patch improves the handling of timer backend switching. It keeps
+the reference to the selected backend during the whole operation of an
+opened stream so that it won't be changed by other streams.
+
+Together with this change, the hrtimer parameter is reenabled as
+writable now.
+
+NOTE: this patch also turned out to fix the still remaining race.
+Namely, ops was still replaced dynamically at dummy_pcm_open:
+
+ static int dummy_pcm_open(struct snd_pcm_substream *substream)
+ {
+ ....
+ dummy->timer_ops = &dummy_systimer_ops;
+ if (hrtimer)
+ dummy->timer_ops = &dummy_hrtimer_ops;
+
+Since dummy->timer_ops is common among all streams, and when the
+replacement happens during accesses of other streams, it may lead to a
+crash. This was actually triggered by syzkaller fuzzer and KASAN.
+
+This patch rewrites the code not to use the ops shared by all streams
+any longer, too.
+
+BugLink: http://lkml.kernel.org/r/CACT4Y+aZ+xisrpuM6cOXbL21DuM0yVxPYXf4cD4Md9uw0C3dBQ@mail.gmail.com
+Reported-by: Dmitry Vyukov <dvyukov@google.com>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/drivers/dummy.c | 37 +++++++++++++++++++------------------
+ 1 file changed, 19 insertions(+), 18 deletions(-)
+
+--- a/sound/drivers/dummy.c
++++ b/sound/drivers/dummy.c
+@@ -87,7 +87,7 @@ MODULE_PARM_DESC(pcm_substreams, "PCM su
+ module_param(fake_buffer, bool, 0444);
+ MODULE_PARM_DESC(fake_buffer, "Fake buffer allocations.");
+ #ifdef CONFIG_HIGH_RES_TIMERS
+-module_param(hrtimer, bool, 0444);
++module_param(hrtimer, bool, 0644);
+ MODULE_PARM_DESC(hrtimer, "Use hrtimer as the timer source.");
+ #endif
+
+@@ -109,6 +109,9 @@ struct dummy_timer_ops {
+ snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *);
+ };
+
++#define get_dummy_ops(substream) \
++ (*(const struct dummy_timer_ops **)(substream)->runtime->private_data)
++
+ struct dummy_model {
+ const char *name;
+ int (*playback_constraints)(struct snd_pcm_runtime *runtime);
+@@ -137,7 +140,6 @@ struct snd_dummy {
+ int iobox;
+ struct snd_kcontrol *cd_volume_ctl;
+ struct snd_kcontrol *cd_switch_ctl;
+- const struct dummy_timer_ops *timer_ops;
+ };
+
+ /*
+@@ -231,6 +233,8 @@ struct dummy_model *dummy_models[] = {
+ */
+
+ struct dummy_systimer_pcm {
++ /* ops must be the first item */
++ const struct dummy_timer_ops *timer_ops;
+ spinlock_t lock;
+ struct timer_list timer;
+ unsigned long base_time;
+@@ -368,6 +372,8 @@ static struct dummy_timer_ops dummy_syst
+ */
+
+ struct dummy_hrtimer_pcm {
++ /* ops must be the first item */
++ const struct dummy_timer_ops *timer_ops;
+ ktime_t base_time;
+ ktime_t period_time;
+ atomic_t running;
+@@ -494,31 +500,25 @@ static struct dummy_timer_ops dummy_hrti
+
+ static int dummy_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+ {
+- struct snd_dummy *dummy = snd_pcm_substream_chip(substream);
+-
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+- return dummy->timer_ops->start(substream);
++ return get_dummy_ops(substream)->start(substream);
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+- return dummy->timer_ops->stop(substream);
++ return get_dummy_ops(substream)->stop(substream);
+ }
+ return -EINVAL;
+ }
+
+ static int dummy_pcm_prepare(struct snd_pcm_substream *substream)
+ {
+- struct snd_dummy *dummy = snd_pcm_substream_chip(substream);
+-
+- return dummy->timer_ops->prepare(substream);
++ return get_dummy_ops(substream)->prepare(substream);
+ }
+
+ static snd_pcm_uframes_t dummy_pcm_pointer(struct snd_pcm_substream *substream)
+ {
+- struct snd_dummy *dummy = snd_pcm_substream_chip(substream);
+-
+- return dummy->timer_ops->pointer(substream);
++ return get_dummy_ops(substream)->pointer(substream);
+ }
+
+ static struct snd_pcm_hardware dummy_pcm_hardware = {
+@@ -564,17 +564,19 @@ static int dummy_pcm_open(struct snd_pcm
+ struct snd_dummy *dummy = snd_pcm_substream_chip(substream);
+ struct dummy_model *model = dummy->model;
+ struct snd_pcm_runtime *runtime = substream->runtime;
++ const struct dummy_timer_ops *ops;
+ int err;
+
+- dummy->timer_ops = &dummy_systimer_ops;
++ ops = &dummy_systimer_ops;
+ #ifdef CONFIG_HIGH_RES_TIMERS
+ if (hrtimer)
+- dummy->timer_ops = &dummy_hrtimer_ops;
++ ops = &dummy_hrtimer_ops;
+ #endif
+
+- err = dummy->timer_ops->create(substream);
++ err = ops->create(substream);
+ if (err < 0)
+ return err;
++ get_dummy_ops(substream) = ops;
+
+ runtime->hw = dummy->pcm_hw;
+ if (substream->pcm->device & 1) {
+@@ -596,7 +598,7 @@ static int dummy_pcm_open(struct snd_pcm
+ err = model->capture_constraints(substream->runtime);
+ }
+ if (err < 0) {
+- dummy->timer_ops->free(substream);
++ get_dummy_ops(substream)->free(substream);
+ return err;
+ }
+ return 0;
+@@ -604,8 +606,7 @@ static int dummy_pcm_open(struct snd_pcm
+
+ static int dummy_pcm_close(struct snd_pcm_substream *substream)
+ {
+- struct snd_dummy *dummy = snd_pcm_substream_chip(substream);
+- dummy->timer_ops->free(substream);
++ get_dummy_ops(substream)->free(substream);
+ return 0;
+ }
+
--- /dev/null
+From c44d9b1181cf34e0860c72cc8a00e0c47417aac0 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Sun, 7 Feb 2016 09:38:26 +0100
+Subject: ALSA: hda - Fix speaker output from VAIO AiO machines
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit c44d9b1181cf34e0860c72cc8a00e0c47417aac0 upstream.
+
+Some Sony VAIO AiO models (VGC-JS4EF and VGC-JS25G, both with PCI SSID
+104d:9044) need the same quirk to make the speaker working properly.
+
+Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=112031
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/pci/hda/patch_realtek.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/sound/pci/hda/patch_realtek.c
++++ b/sound/pci/hda/patch_realtek.c
+@@ -2188,6 +2188,7 @@ static const struct snd_pci_quirk alc882
+ SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC889_FIXUP_VAIO_TT),
+ SND_PCI_QUIRK(0x104d, 0x905a, "Sony Vaio Z", ALC882_FIXUP_NO_PRIMARY_HP),
+ SND_PCI_QUIRK(0x104d, 0x9043, "Sony Vaio VGC-LN51JGB", ALC882_FIXUP_NO_PRIMARY_HP),
++ SND_PCI_QUIRK(0x104d, 0x9044, "Sony VAIO AiO", ALC882_FIXUP_NO_PRIMARY_HP),
+
+ /* All Apple entries are in codec SSIDs */
+ SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC889_FIXUP_MBP_VREF),
--- /dev/null
+From b248371628aad599a48540962f6b85a21a8a0c3f Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Sun, 31 Jan 2016 10:32:37 +0100
+Subject: ALSA: pcm: Fix potential deadlock in OSS emulation
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit b248371628aad599a48540962f6b85a21a8a0c3f upstream.
+
+There are potential deadlocks in PCM OSS emulation code while
+accessing read/write and mmap concurrently. This comes from the
+infamous mmap_sem usage in copy_from/to_user(). Namely,
+
+ snd_pcm_oss_write() ->
+ &runtime->oss.params_lock ->
+ copy_to_user() ->
+ &mm->mmap_sem
+ mmap() ->
+ &mm->mmap_sem ->
+ snd_pcm_oss_mmap() ->
+ &runtime->oss.params_lock
+
+Since we can't avoid taking params_lock from mmap code path, use
+trylock variant and aborts with -EAGAIN as a workaround of this AB/BA
+deadlock.
+
+BugLink: http://lkml.kernel.org/r/CACT4Y+bVrBKDG0G2_AcUgUQa+X91VKTeS4v+wN7BSHwHtqn3kQ@mail.gmail.com
+Reported-by: Dmitry Vyukov <dvyukov@google.com>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/core/oss/pcm_oss.c | 21 +++++++++++++++------
+ 1 file changed, 15 insertions(+), 6 deletions(-)
+
+--- a/sound/core/oss/pcm_oss.c
++++ b/sound/core/oss/pcm_oss.c
+@@ -834,7 +834,8 @@ static int choose_rate(struct snd_pcm_su
+ return snd_pcm_hw_param_near(substream, params, SNDRV_PCM_HW_PARAM_RATE, best_rate, NULL);
+ }
+
+-static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream)
++static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream,
++ bool trylock)
+ {
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_pcm_hw_params *params, *sparams;
+@@ -848,7 +849,10 @@ static int snd_pcm_oss_change_params(str
+ struct snd_mask sformat_mask;
+ struct snd_mask mask;
+
+- if (mutex_lock_interruptible(&runtime->oss.params_lock))
++ if (trylock) {
++ if (!(mutex_trylock(&runtime->oss.params_lock)))
++ return -EAGAIN;
++ } else if (mutex_lock_interruptible(&runtime->oss.params_lock))
+ return -EINTR;
+ sw_params = kmalloc(sizeof(*sw_params), GFP_KERNEL);
+ params = kmalloc(sizeof(*params), GFP_KERNEL);
+@@ -1091,7 +1095,7 @@ static int snd_pcm_oss_get_active_substr
+ if (asubstream == NULL)
+ asubstream = substream;
+ if (substream->runtime->oss.params) {
+- err = snd_pcm_oss_change_params(substream);
++ err = snd_pcm_oss_change_params(substream, false);
+ if (err < 0)
+ return err;
+ }
+@@ -1130,7 +1134,7 @@ static int snd_pcm_oss_make_ready(struct
+ return 0;
+ runtime = substream->runtime;
+ if (runtime->oss.params) {
+- err = snd_pcm_oss_change_params(substream);
++ err = snd_pcm_oss_change_params(substream, false);
+ if (err < 0)
+ return err;
+ }
+@@ -2168,7 +2172,7 @@ static int snd_pcm_oss_get_space(struct
+ runtime = substream->runtime;
+
+ if (runtime->oss.params &&
+- (err = snd_pcm_oss_change_params(substream)) < 0)
++ (err = snd_pcm_oss_change_params(substream, false)) < 0)
+ return err;
+
+ info.fragsize = runtime->oss.period_bytes;
+@@ -2804,7 +2808,12 @@ static int snd_pcm_oss_mmap(struct file
+ return -EIO;
+
+ if (runtime->oss.params) {
+- if ((err = snd_pcm_oss_change_params(substream)) < 0)
++ /* use mutex_trylock() for params_lock for avoiding a deadlock
++ * between mmap_sem and params_lock taken by
++ * copy_from/to_user() in snd_pcm_oss_write/read()
++ */
++ err = snd_pcm_oss_change_params(substream, true);
++ if (err < 0)
+ return err;
+ }
+ #ifdef CONFIG_SND_PCM_OSS_PLUGINS
--- /dev/null
+From 81f577542af15640cbcb6ef68baa4caa610cbbfc Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Wed, 3 Feb 2016 14:41:22 +0100
+Subject: ALSA: rawmidi: Fix race at copying & updating the position
+
+From: Takashi Iwai <tiwai@suse.de>
+
+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@mail.gmail.com
+Reported-by: Dmitry Vyukov <dvyukov@google.com>
+Tested-by: Dmitry Vyukov <dvyukov@google.com>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/core/rawmidi.c | 34 ++++++++++++++++++++++------------
+ 1 file changed, 22 insertions(+), 12 deletions(-)
+
+--- a/sound/core/rawmidi.c
++++ b/sound/core/rawmidi.c
+@@ -934,31 +934,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;
+ }
+
+@@ -1161,6 +1166,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;
+@@ -1181,12 +1187,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;
+@@ -1194,9 +1207,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;
+ }
--- /dev/null
+From cc85f7a634cfaf9f0713c6aa06d08817424db37a Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Mon, 1 Feb 2016 12:04:55 +0100
+Subject: ALSA: rawmidi: Remove kernel WARNING for NULL user-space buffer check
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit cc85f7a634cfaf9f0713c6aa06d08817424db37a upstream.
+
+NULL user-space buffer can be passed even in a normal path, thus it's
+not good to spew a kernel warning with stack trace at each time.
+Just drop snd_BUG_ON() macro usage there.
+
+BugLink: http://lkml.kernel.org/r/CACT4Y+YfVJ3L+q0i-4vyQVyyPD7V=OMX0PWPi29x9Bo3QaBLdw@mail.gmail.com
+Reported-by: Dmitry Vyukov <dvyukov@google.com>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/core/rawmidi.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/sound/core/rawmidi.c
++++ b/sound/core/rawmidi.c
+@@ -1162,7 +1162,7 @@ static long snd_rawmidi_kernel_write1(st
+ long count1, result;
+ struct snd_rawmidi_runtime *runtime = substream->runtime;
+
+- if (snd_BUG_ON(!kernelbuf && !userbuf))
++ if (!kernelbuf && !userbuf)
+ return -EINVAL;
+ if (snd_BUG_ON(!runtime->buffer))
+ return -EINVAL;
--- /dev/null
+From 599151336638d57b98d92338aa59c048e3a3e97d Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Mon, 25 Jan 2016 11:01:47 +0100
+Subject: ALSA: seq: Fix incorrect sanity check at snd_seq_oss_synth_cleanup()
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit 599151336638d57b98d92338aa59c048e3a3e97d upstream.
+
+ALSA sequencer OSS emulation code has a sanity check for currently
+opened devices, but there is a thinko there, eventually it spews
+warnings and skips the operation wrongly like:
+ WARNING: CPU: 1 PID: 7573 at sound/core/seq/oss/seq_oss_synth.c:311
+
+Fix this off-by-one error.
+
+Reported-by: Dmitry Vyukov <dvyukov@google.com>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/core/seq/oss/seq_oss_synth.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/sound/core/seq/oss/seq_oss_synth.c
++++ b/sound/core/seq/oss/seq_oss_synth.c
+@@ -310,7 +310,7 @@ snd_seq_oss_synth_cleanup(struct seq_oss
+ struct seq_oss_synth *rec;
+ struct seq_oss_synthinfo *info;
+
+- if (snd_BUG_ON(dp->max_synthdev >= SNDRV_SEQ_OSS_MAX_SYNTH_DEVS))
++ if (snd_BUG_ON(dp->max_synthdev > SNDRV_SEQ_OSS_MAX_SYNTH_DEVS))
+ return;
+ for (i = 0; i < dp->max_synthdev; i++) {
+ info = &dp->synths[i];
--- /dev/null
+From 7f0973e973cd74aa40747c9d38844560cd184ee8 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Wed, 3 Feb 2016 08:32:44 +0100
+Subject: ALSA: seq: Fix lockdep warnings due to double mutex locks
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit 7f0973e973cd74aa40747c9d38844560cd184ee8 upstream.
+
+The port subscription code uses double mutex locks for source and
+destination ports, and this may become racy once when wrongly set up.
+It leads to lockdep warning splat, typically triggered by fuzzer like
+syzkaller, although the actual deadlock hasn't been seen, so far.
+
+This patch simplifies the handling by reducing to two single locks, so
+that no lockdep warning will be trigger any longer.
+
+By splitting to two actions, a still-in-progress element shall be
+added in one list while handling another. For ignoring this element,
+a new check is added in deliver_to_subscribers().
+
+Along with it, the code to add/remove the subscribers list element was
+cleaned up and refactored.
+
+BugLink: http://lkml.kernel.org/r/CACT4Y+aKQXV7xkBW9hpQbzaDO7LrUvohxWh-UwMxXjDy-yBD=A@mail.gmail.com
+Reported-by: Dmitry Vyukov <dvyukov@google.com>
+Tested-by: Dmitry Vyukov <dvyukov@google.com>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/core/seq/seq_clientmgr.c | 3
+ sound/core/seq/seq_ports.c | 235 ++++++++++++++++++++++-------------------
+ 2 files changed, 134 insertions(+), 104 deletions(-)
+
+--- a/sound/core/seq/seq_clientmgr.c
++++ b/sound/core/seq/seq_clientmgr.c
+@@ -678,6 +678,9 @@ static int deliver_to_subscribers(struct
+ else
+ down_read(&grp->list_mutex);
+ list_for_each_entry(subs, &grp->list_head, src_list) {
++ /* both ports ready? */
++ if (atomic_read(&subs->ref_count) != 2)
++ continue;
+ event->dest = subs->info.dest;
+ if (subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIMESTAMP)
+ /* convert time according to flag with subscription */
+--- a/sound/core/seq/seq_ports.c
++++ b/sound/core/seq/seq_ports.c
+@@ -175,10 +175,6 @@ struct snd_seq_client_port *snd_seq_crea
+ }
+
+ /* */
+-enum group_type {
+- SRC_LIST, DEST_LIST
+-};
+-
+ static int subscribe_port(struct snd_seq_client *client,
+ struct snd_seq_client_port *port,
+ struct snd_seq_port_subs_info *grp,
+@@ -205,6 +201,20 @@ static struct snd_seq_client_port *get_c
+ return NULL;
+ }
+
++static void delete_and_unsubscribe_port(struct snd_seq_client *client,
++ struct snd_seq_client_port *port,
++ struct snd_seq_subscribers *subs,
++ bool is_src, bool ack);
++
++static inline struct snd_seq_subscribers *
++get_subscriber(struct list_head *p, bool is_src)
++{
++ if (is_src)
++ return list_entry(p, struct snd_seq_subscribers, src_list);
++ else
++ return list_entry(p, struct snd_seq_subscribers, dest_list);
++}
++
+ /*
+ * remove all subscribers on the list
+ * this is called from port_delete, for each src and dest list.
+@@ -212,7 +222,7 @@ static struct snd_seq_client_port *get_c
+ static void clear_subscriber_list(struct snd_seq_client *client,
+ struct snd_seq_client_port *port,
+ struct snd_seq_port_subs_info *grp,
+- int grptype)
++ int is_src)
+ {
+ struct list_head *p, *n;
+
+@@ -221,15 +231,13 @@ static void clear_subscriber_list(struct
+ struct snd_seq_client *c;
+ struct snd_seq_client_port *aport;
+
+- if (grptype == SRC_LIST) {
+- subs = list_entry(p, struct snd_seq_subscribers, src_list);
++ subs = get_subscriber(p, is_src);
++ if (is_src)
+ aport = get_client_port(&subs->info.dest, &c);
+- } else {
+- subs = list_entry(p, struct snd_seq_subscribers, dest_list);
++ else
+ aport = get_client_port(&subs->info.sender, &c);
+- }
+- list_del(p);
+- unsubscribe_port(client, port, grp, &subs->info, 0);
++ delete_and_unsubscribe_port(client, port, subs, is_src, false);
++
+ if (!aport) {
+ /* looks like the connected port is being deleted.
+ * we decrease the counter, and when both ports are deleted
+@@ -237,21 +245,14 @@ static void clear_subscriber_list(struct
+ */
+ if (atomic_dec_and_test(&subs->ref_count))
+ kfree(subs);
+- } else {
+- /* ok we got the connected port */
+- struct snd_seq_port_subs_info *agrp;
+- agrp = (grptype == SRC_LIST) ? &aport->c_dest : &aport->c_src;
+- down_write(&agrp->list_mutex);
+- if (grptype == SRC_LIST)
+- list_del(&subs->dest_list);
+- else
+- list_del(&subs->src_list);
+- up_write(&agrp->list_mutex);
+- unsubscribe_port(c, aport, agrp, &subs->info, 1);
+- kfree(subs);
+- snd_seq_port_unlock(aport);
+- snd_seq_client_unlock(c);
++ continue;
+ }
++
++ /* ok we got the connected port */
++ delete_and_unsubscribe_port(c, aport, subs, !is_src, true);
++ kfree(subs);
++ snd_seq_port_unlock(aport);
++ snd_seq_client_unlock(c);
+ }
+ }
+
+@@ -264,8 +265,8 @@ static int port_delete(struct snd_seq_cl
+ snd_use_lock_sync(&port->use_lock);
+
+ /* clear subscribers info */
+- clear_subscriber_list(client, port, &port->c_src, SRC_LIST);
+- clear_subscriber_list(client, port, &port->c_dest, DEST_LIST);
++ clear_subscriber_list(client, port, &port->c_src, true);
++ clear_subscriber_list(client, port, &port->c_dest, false);
+
+ if (port->private_free)
+ port->private_free(port->private_data);
+@@ -484,85 +485,120 @@ static int match_subs_info(struct snd_se
+ return 0;
+ }
+
++static int check_and_subscribe_port(struct snd_seq_client *client,
++ struct snd_seq_client_port *port,
++ struct snd_seq_subscribers *subs,
++ bool is_src, bool exclusive, bool ack)
++{
++ struct snd_seq_port_subs_info *grp;
++ struct list_head *p;
++ struct snd_seq_subscribers *s;
++ int err;
+
+-/* connect two ports */
+-int snd_seq_port_connect(struct snd_seq_client *connector,
+- struct snd_seq_client *src_client,
+- struct snd_seq_client_port *src_port,
+- struct snd_seq_client *dest_client,
+- struct snd_seq_client_port *dest_port,
+- struct snd_seq_port_subscribe *info)
+-{
+- struct snd_seq_port_subs_info *src = &src_port->c_src;
+- struct snd_seq_port_subs_info *dest = &dest_port->c_dest;
+- struct snd_seq_subscribers *subs, *s;
+- int err, src_called = 0;
+- unsigned long flags;
+- int exclusive;
+-
+- subs = kzalloc(sizeof(*subs), GFP_KERNEL);
+- if (! subs)
+- return -ENOMEM;
+-
+- subs->info = *info;
+- atomic_set(&subs->ref_count, 2);
+-
+- down_write(&src->list_mutex);
+- down_write_nested(&dest->list_mutex, SINGLE_DEPTH_NESTING);
+-
+- exclusive = info->flags & SNDRV_SEQ_PORT_SUBS_EXCLUSIVE ? 1 : 0;
++ grp = is_src ? &port->c_src : &port->c_dest;
+ err = -EBUSY;
++ down_write(&grp->list_mutex);
+ if (exclusive) {
+- if (! list_empty(&src->list_head) || ! list_empty(&dest->list_head))
++ if (!list_empty(&grp->list_head))
+ goto __error;
+ } else {
+- if (src->exclusive || dest->exclusive)
++ if (grp->exclusive)
+ goto __error;
+ /* check whether already exists */
+- list_for_each_entry(s, &src->list_head, src_list) {
+- if (match_subs_info(info, &s->info))
+- goto __error;
+- }
+- list_for_each_entry(s, &dest->list_head, dest_list) {
+- if (match_subs_info(info, &s->info))
++ list_for_each(p, &grp->list_head) {
++ s = get_subscriber(p, is_src);
++ if (match_subs_info(&subs->info, &s->info))
+ goto __error;
+ }
+ }
+
+- if ((err = subscribe_port(src_client, src_port, src, info,
+- connector->number != src_client->number)) < 0)
+- goto __error;
+- src_called = 1;
+-
+- if ((err = subscribe_port(dest_client, dest_port, dest, info,
+- connector->number != dest_client->number)) < 0)
++ err = subscribe_port(client, port, grp, &subs->info, ack);
++ if (err < 0) {
++ grp->exclusive = 0;
+ goto __error;
++ }
+
+ /* add to list */
+- write_lock_irqsave(&src->list_lock, flags);
+- // write_lock(&dest->list_lock); // no other lock yet
+- list_add_tail(&subs->src_list, &src->list_head);
+- list_add_tail(&subs->dest_list, &dest->list_head);
+- // write_unlock(&dest->list_lock); // no other lock yet
+- write_unlock_irqrestore(&src->list_lock, flags);
++ write_lock_irq(&grp->list_lock);
++ if (is_src)
++ list_add_tail(&subs->src_list, &grp->list_head);
++ else
++ list_add_tail(&subs->dest_list, &grp->list_head);
++ grp->exclusive = exclusive;
++ atomic_inc(&subs->ref_count);
++ write_unlock_irq(&grp->list_lock);
++ err = 0;
+
+- src->exclusive = dest->exclusive = exclusive;
++ __error:
++ up_write(&grp->list_mutex);
++ return err;
++}
++
++static void delete_and_unsubscribe_port(struct snd_seq_client *client,
++ struct snd_seq_client_port *port,
++ struct snd_seq_subscribers *subs,
++ bool is_src, bool ack)
++{
++ struct snd_seq_port_subs_info *grp;
++
++ grp = is_src ? &port->c_src : &port->c_dest;
++ down_write(&grp->list_mutex);
++ write_lock_irq(&grp->list_lock);
++ if (is_src)
++ list_del(&subs->src_list);
++ else
++ list_del(&subs->dest_list);
++ grp->exclusive = 0;
++ write_unlock_irq(&grp->list_lock);
++ up_write(&grp->list_mutex);
++
++ unsubscribe_port(client, port, grp, &subs->info, ack);
++}
++
++/* connect two ports */
++int snd_seq_port_connect(struct snd_seq_client *connector,
++ struct snd_seq_client *src_client,
++ struct snd_seq_client_port *src_port,
++ struct snd_seq_client *dest_client,
++ struct snd_seq_client_port *dest_port,
++ struct snd_seq_port_subscribe *info)
++{
++ struct snd_seq_subscribers *subs;
++ bool exclusive;
++ int err;
++
++ subs = kzalloc(sizeof(*subs), GFP_KERNEL);
++ if (!subs)
++ return -ENOMEM;
++
++ subs->info = *info;
++ atomic_set(&subs->ref_count, 0);
++ INIT_LIST_HEAD(&subs->src_list);
++ INIT_LIST_HEAD(&subs->dest_list);
++
++ exclusive = !!(info->flags & SNDRV_SEQ_PORT_SUBS_EXCLUSIVE);
++
++ err = check_and_subscribe_port(src_client, src_port, subs, true,
++ exclusive,
++ connector->number != src_client->number);
++ if (err < 0)
++ goto error;
++ err = check_and_subscribe_port(dest_client, dest_port, subs, false,
++ exclusive,
++ connector->number != dest_client->number);
++ if (err < 0)
++ goto error_dest;
+
+- up_write(&dest->list_mutex);
+- up_write(&src->list_mutex);
+ return 0;
+
+- __error:
+- if (src_called)
+- unsubscribe_port(src_client, src_port, src, info,
+- connector->number != src_client->number);
++ error_dest:
++ delete_and_unsubscribe_port(src_client, src_port, subs, true,
++ connector->number != src_client->number);
++ error:
+ kfree(subs);
+- up_write(&dest->list_mutex);
+- up_write(&src->list_mutex);
+ return err;
+ }
+
+-
+ /* remove the connection */
+ int snd_seq_port_disconnect(struct snd_seq_client *connector,
+ struct snd_seq_client *src_client,
+@@ -572,37 +608,28 @@ int snd_seq_port_disconnect(struct snd_s
+ struct snd_seq_port_subscribe *info)
+ {
+ struct snd_seq_port_subs_info *src = &src_port->c_src;
+- struct snd_seq_port_subs_info *dest = &dest_port->c_dest;
+ struct snd_seq_subscribers *subs;
+ int err = -ENOENT;
+- unsigned long flags;
+
+ down_write(&src->list_mutex);
+- down_write_nested(&dest->list_mutex, SINGLE_DEPTH_NESTING);
+-
+ /* look for the connection */
+ list_for_each_entry(subs, &src->list_head, src_list) {
+ if (match_subs_info(info, &subs->info)) {
+- write_lock_irqsave(&src->list_lock, flags);
+- // write_lock(&dest->list_lock); // no lock yet
+- list_del(&subs->src_list);
+- list_del(&subs->dest_list);
+- // write_unlock(&dest->list_lock);
+- write_unlock_irqrestore(&src->list_lock, flags);
+- src->exclusive = dest->exclusive = 0;
+- unsubscribe_port(src_client, src_port, src, info,
+- connector->number != src_client->number);
+- unsubscribe_port(dest_client, dest_port, dest, info,
+- connector->number != dest_client->number);
+- kfree(subs);
++ atomic_dec(&subs->ref_count); /* mark as not ready */
+ err = 0;
+ break;
+ }
+ }
+-
+- up_write(&dest->list_mutex);
+ up_write(&src->list_mutex);
+- return err;
++ if (err < 0)
++ return err;
++
++ delete_and_unsubscribe_port(src_client, src_port, subs, true,
++ connector->number != src_client->number);
++ delete_and_unsubscribe_port(dest_client, dest_port, subs, false,
++ connector->number != dest_client->number);
++ kfree(subs);
++ return 0;
+ }
+
+
--- /dev/null
+From 2d1b5c08366acd46c35a2e9aba5d650cb5bf5c19 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Mon, 1 Feb 2016 12:06:42 +0100
+Subject: ALSA: seq: Fix race at closing in virmidi driver
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit 2d1b5c08366acd46c35a2e9aba5d650cb5bf5c19 upstream.
+
+The virmidi driver has an open race at closing its assigned rawmidi
+device, and this may lead to use-after-free in
+snd_seq_deliver_single_event().
+
+Plug the hole by properly protecting the linked list deletion and
+calling in the right order in snd_virmidi_input_close().
+
+BugLink: http://lkml.kernel.org/r/CACT4Y+Zd66+w12fNN85-425cVQT=K23kWbhnCEcMB8s3us-Frw@mail.gmail.com
+Reported-by: Dmitry Vyukov <dvyukov@google.com>
+Tested-by: Dmitry Vyukov <dvyukov@google.com>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/core/seq/seq_virmidi.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+--- a/sound/core/seq/seq_virmidi.c
++++ b/sound/core/seq/seq_virmidi.c
+@@ -254,9 +254,13 @@ static int snd_virmidi_output_open(struc
+ */
+ static int snd_virmidi_input_close(struct snd_rawmidi_substream *substream)
+ {
++ struct snd_virmidi_dev *rdev = substream->rmidi->private_data;
+ struct snd_virmidi *vmidi = substream->runtime->private_data;
+- snd_midi_event_free(vmidi->parser);
++
++ write_lock_irq(&rdev->filelist_lock);
+ list_del(&vmidi->list);
++ write_unlock_irq(&rdev->filelist_lock);
++ snd_midi_event_free(vmidi->parser);
+ substream->runtime->private_data = NULL;
+ kfree(vmidi);
+ return 0;
--- /dev/null
+From 2cdc7b636d55cbcf42e1e6c8accd85e62d3e9ae8 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Sat, 30 Jan 2016 23:30:25 +0100
+Subject: ALSA: seq: Fix yet another races among ALSA timer accesses
+
+From: Takashi Iwai <tiwai@suse.de>
+
+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.
+
+BugLink: http://lkml.kernel.org/r/CACT4Y+Z6RzW5MBr-HUdV-8zwg71WQfKTdPpYGvOeS7v4cyurNQ@mail.gmail.com
+Reported-by: Dmitry Vyukov <dvyukov@google.com>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/core/seq/seq_timer.c | 87 ++++++++++++++++++++++++++++++++++-----------
+ 1 file changed, 67 insertions(+), 20 deletions(-)
+
+--- a/sound/core/seq/seq_timer.c
++++ b/sound/core/seq/seq_timer.c
+@@ -92,6 +92,9 @@ void snd_seq_timer_delete(struct snd_seq
+
+ void 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_ti
+ return 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_s
+ return 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_t
+ return 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_se
+ return 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;
+ }
+
--- /dev/null
+From 094fd3be87b0f102589e2d5c3fa5d06b7e20496d Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Thu, 4 Feb 2016 17:06:13 +0100
+Subject: ALSA: timer: Fix leftover link at closing
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit 094fd3be87b0f102589e2d5c3fa5d06b7e20496d upstream.
+
+In ALSA timer core, the active timer instance is managed in
+active_list linked list. Each element is added / removed dynamically
+at timer start, stop and in timer interrupt. The problem is that
+snd_timer_interrupt() has a thinko and leaves the element in
+active_list when it's the last opened element. This eventually leads
+to list corruption or use-after-free error.
+
+This hasn't been revealed because we used to delete the list forcibly
+in snd_timer_stop() in the past. However, the recent fix avoids the
+double-stop behavior (in commit [f784beb75ce8: ALSA: timer: Fix link
+corruption due to double start or stop]), and this leak hits reality.
+
+This patch fixes the link management in snd_timer_interrupt(). Now it
+simply unlinks no matter which stream is.
+
+BugLink: http://lkml.kernel.org/r/CACT4Y+Yy2aukHP-EDp8-ziNqNNmb-NTf=jDWXMP7jB8HDa2vng@mail.gmail.com
+Reported-by: Dmitry Vyukov <dvyukov@google.com>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/core/timer.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/sound/core/timer.c
++++ b/sound/core/timer.c
+@@ -702,8 +702,8 @@ void snd_timer_interrupt(struct snd_time
+ ti->cticks = ti->ticks;
+ } else {
+ ti->flags &= ~SNDRV_TIMER_IFLG_RUNNING;
+- if (--timer->running)
+- list_del_init(&ti->active_list);
++ --timer->running;
++ list_del_init(&ti->active_list);
+ }
+ if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) ||
+ (ti->flags & SNDRV_TIMER_IFLG_FAST))
--- /dev/null
+From f784beb75ce82f4136f8a0960d3ee872f7109e09 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+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@suse.de>
+
+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@mail.gmail.com
+Reported-by: Dmitry Vyukov <dvyukov@google.com>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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;
--- /dev/null
+From 117159f0b9d392fb433a7871426fad50317f06f7 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Mon, 8 Feb 2016 17:36:25 +0100
+Subject: ALSA: timer: Fix wrong instance passed to slave callbacks
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit 117159f0b9d392fb433a7871426fad50317f06f7 upstream.
+
+In snd_timer_notify1(), the wrong timer instance was passed for slave
+ccallback function. This leads to the access to the wrong data when
+an incompatible master is handled (e.g. the master is the sequencer
+timer and the slave is a user timer), as spotted by syzkaller fuzzer.
+
+This patch fixes that wrong assignment.
+
+BugLink: http://lkml.kernel.org/r/CACT4Y+Y_Bm+7epAb=8Wi=AaWd+DYS7qawX52qxdCfOfY49vozQ@mail.gmail.com
+Reported-by: Dmitry Vyukov <dvyukov@google.com>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/core/timer.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/sound/core/timer.c
++++ b/sound/core/timer.c
+@@ -415,7 +415,7 @@ static void snd_timer_notify1(struct snd
+ spin_lock_irqsave(&timer->lock, flags);
+ list_for_each_entry(ts, &ti->slave_active_head, active_list)
+ if (ts->ccallback)
+- ts->ccallback(ti, event + 100, &tstamp, resolution);
++ ts->ccallback(ts, event + 100, &tstamp, resolution);
+ spin_unlock_irqrestore(&timer->lock, flags);
+ }
+
--- /dev/null
+From 07d86ca93db7e5cdf4743564d98292042ec21af7 Mon Sep 17 00:00:00 2001
+From: Andrey Konovalov <andreyknvl@gmail.com>
+Date: Sat, 13 Feb 2016 11:08:06 +0300
+Subject: ALSA: usb-audio: avoid freeing umidi object twice
+
+From: Andrey Konovalov <andreyknvl@gmail.com>
+
+commit 07d86ca93db7e5cdf4743564d98292042ec21af7 upstream.
+
+The 'umidi' object will be free'd on the error path by snd_usbmidi_free()
+when tearing down the rawmidi interface. So we shouldn't try to free it
+in snd_usbmidi_create() after having registered the rawmidi interface.
+
+Found by KASAN.
+
+Signed-off-by: Andrey Konovalov <andreyknvl@gmail.com>
+Acked-by: Clemens Ladisch <clemens@ladisch.de>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/usb/midi.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/sound/usb/midi.c
++++ b/sound/usb/midi.c
+@@ -2291,7 +2291,6 @@ int snd_usbmidi_create(struct snd_card *
+ else
+ err = snd_usbmidi_create_endpoints(umidi, endpoints);
+ if (err < 0) {
+- snd_usbmidi_free(umidi);
+ return err;
+ }
+
--- /dev/null
+From 5a4ff9ec8d6edd2ab1cfe8ce6a080d6e57cbea9a Mon Sep 17 00:00:00 2001
+From: Guillaume Fougnies <guillaume@eulerian.com>
+Date: Tue, 26 Jan 2016 00:28:27 +0100
+Subject: ALSA: usb-audio: Fix TEAC UD-501/UD-503/NT-503 usb delay
+
+From: Guillaume Fougnies <guillaume@eulerian.com>
+
+commit 5a4ff9ec8d6edd2ab1cfe8ce6a080d6e57cbea9a upstream.
+
+TEAC UD-501/UD-503/NT-503 fail to switch properly between different
+rate/format. Similar to 'Playback Design', this patch corrects the
+invalid clock source error for TEAC products and avoids complete
+freeze of the usb interface of 503 series.
+
+Signed-off-by: Guillaume Fougnies <guillaume@eulerian.com>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/usb/quirks.c | 14 +++++++++++++-
+ 1 file changed, 13 insertions(+), 1 deletion(-)
+
+--- a/sound/usb/quirks.c
++++ b/sound/usb/quirks.c
+@@ -900,8 +900,12 @@ void snd_usb_set_interface_quirk(struct
+ * "Playback Design" products need a 50ms delay after setting the
+ * USB interface.
+ */
+- if (le16_to_cpu(dev->descriptor.idVendor) == 0x23ba)
++ switch (le16_to_cpu(dev->descriptor.idVendor)) {
++ case 0x23ba: /* Playback Design */
++ case 0x0644: /* TEAC Corp. */
+ mdelay(50);
++ break;
++ }
+ }
+
+ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
+@@ -916,6 +920,14 @@ void snd_usb_ctl_msg_quirk(struct usb_de
+ (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
+ mdelay(20);
+
++ /*
++ * "TEAC Corp." products need a 20ms delay after each
++ * class compliant request
++ */
++ if ((le16_to_cpu(dev->descriptor.idVendor) == 0x0644) &&
++ (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
++ mdelay(20);
++
+ /* Marantz/Denon devices with USB DAC functionality need a delay
+ * after each class compliant request
+ */
--- /dev/null
+From 5e82d2be6ee53275c72e964507518d7964c82753 Mon Sep 17 00:00:00 2001
+From: Vinod Koul <vinod.koul@intel.com>
+Date: Mon, 1 Feb 2016 22:26:40 +0530
+Subject: ASoC: dpcm: fix the BE state on hw_free
+
+From: Vinod Koul <vinod.koul@intel.com>
+
+commit 5e82d2be6ee53275c72e964507518d7964c82753 upstream.
+
+While performing hw_free, DPCM checks the BE state but leaves out
+the suspend state. The suspend state needs to be checked as well,
+as we might be suspended and then usermode closes rather than
+resuming the audio stream.
+
+This was found by a stress testing of system with playback in
+loop and killed after few seconds running in background and second
+script running suspend-resume test in loop
+
+Signed-off-by: Vinod Koul <vinod.koul@intel.com>
+Acked-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
+Signed-off-by: Mark Brown <broonie@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/soc/soc-pcm.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/sound/soc/soc-pcm.c
++++ b/sound/soc/soc-pcm.c
+@@ -1248,7 +1248,8 @@ static int dpcm_be_dai_hw_free(struct sn
+ (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
+ (be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
+ (be->dpcm[stream].state != SND_SOC_DPCM_STATE_PAUSED) &&
+- (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP))
++ (be->dpcm[stream].state != SND_SOC_DPCM_STATE_STOP) &&
++ (be->dpcm[stream].state != SND_SOC_DPCM_STATE_SUSPEND))
+ continue;
+
+ dev_dbg(be->dev, "ASoC: hw_free BE %s\n",
--- /dev/null
+From ac75fe5d8fe4a0bf063be18fb29684405279e79e Mon Sep 17 00:00:00 2001
+From: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
+Date: Thu, 4 Feb 2016 15:59:43 -0200
+Subject: [media] saa7134-alsa: Only frees registered sound cards
+
+From: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
+
+commit ac75fe5d8fe4a0bf063be18fb29684405279e79e upstream.
+
+That prevents this bug:
+[ 2382.269496] BUG: unable to handle kernel NULL pointer dereference at 0000000000000540
+[ 2382.270013] IP: [<ffffffffa01fe616>] snd_card_free+0x36/0x70 [snd]
+[ 2382.270013] PGD 0
+[ 2382.270013] Oops: 0002 [#1] SMP
+[ 2382.270013] Modules linked in: saa7134_alsa(-) tda1004x saa7134_dvb videobuf2_dvb dvb_core tda827x tda8290 tuner saa7134 tveeprom videobuf2_dma_sg videobuf2_memops videobuf2_v4l2 videobuf2_core v4l2_common videodev media auth_rpcgss nfsv4 dns_resolver nfs lockd grace sunrpc tun bridge stp llc ebtables ip6table_filter ip6_tables nf_conntrack_ipv4 nf_defrag_ipv4 xt_conntrack nf_conntrack it87 hwmon_vid snd_hda_codec_idt snd_hda_codec_generic iTCO_wdt iTCO_vendor_support snd_hda_intel snd_hda_codec snd_hwdep snd_hda_core snd_seq pcspkr i2c_i801 snd_seq_device snd_pcm snd_timer lpc_ich snd mfd_core soundcore binfmt_misc i915 video i2c_algo_bit drm_kms_helper drm r8169 ata_generic serio_raw pata_acpi mii i2c_core [last unloaded: videobuf2_memops]
+[ 2382.270013] CPU: 0 PID: 4899 Comm: rmmod Not tainted 4.5.0-rc1+ #4
+[ 2382.270013] Hardware name: PCCHIPS P17G/P17G, BIOS 080012 05/14/2008
+[ 2382.270013] task: ffff880039c38000 ti: ffff88003c764000 task.ti: ffff88003c764000
+[ 2382.270013] RIP: 0010:[<ffffffffa01fe616>] [<ffffffffa01fe616>] snd_card_free+0x36/0x70 [snd]
+[ 2382.270013] RSP: 0018:ffff88003c767ea0 EFLAGS: 00010286
+[ 2382.270013] RAX: ffff88003c767eb8 RBX: 0000000000000000 RCX: 0000000000006260
+[ 2382.270013] RDX: ffffffffa020a060 RSI: ffffffffa0206de1 RDI: ffff88003c767eb0
+[ 2382.270013] RBP: ffff88003c767ed8 R08: 0000000000019960 R09: ffffffff811a5412
+[ 2382.270013] R10: ffffea0000d7c200 R11: 0000000000000000 R12: ffff88003c767ea8
+[ 2382.270013] R13: 00007ffe760617f7 R14: 0000000000000000 R15: 0000557625d7f1e0
+[ 2382.270013] FS: 00007f80bb1c0700(0000) GS:ffff88003f400000(0000) knlGS:0000000000000000
+[ 2382.270013] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b
+[ 2382.270013] CR2: 0000000000000540 CR3: 000000003c00f000 CR4: 00000000000006f0
+[ 2382.270013] Stack:
+[ 2382.270013] 000000003c767ed8 ffffffff00000000 ffff880000000000 ffff88003c767eb8
+[ 2382.270013] ffff88003c767eb8 ffffffffa049a890 00007ffe76060060 ffff88003c767ef0
+[ 2382.270013] ffffffffa049889d ffffffffa049a500 ffff88003c767f48 ffffffff8111079c
+[ 2382.270013] Call Trace:
+[ 2382.270013] [<ffffffffa049889d>] saa7134_alsa_exit+0x1d/0x780 [saa7134_alsa]
+[ 2382.270013] [<ffffffff8111079c>] SyS_delete_module+0x19c/0x1f0
+[ 2382.270013] [<ffffffff8170fc2e>] entry_SYSCALL_64_fastpath+0x12/0x71
+[ 2382.270013] Code: 20 a0 48 c7 c6 e1 6d 20 a0 48 89 e5 41 54 53 4c 8d 65 d0 48 89 fb 48 83 ec 28 c7 45 d0 00 00 00 00 49 8d 7c 24 08 e8 7a 55 ed e0 <4c> 89 a3 40 05 00 00 48 89 df e8 eb fd ff ff 85 c0 75 1a 48 8d
+[ 2382.270013] RIP [<ffffffffa01fe616>] snd_card_free+0x36/0x70 [snd]
+[ 2382.270013] RSP <ffff88003c767ea0>
+[ 2382.270013] CR2: 0000000000000540
+
+Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/media/pci/saa7134/saa7134-alsa.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/media/pci/saa7134/saa7134-alsa.c
++++ b/drivers/media/pci/saa7134/saa7134-alsa.c
+@@ -1145,6 +1145,8 @@ static int alsa_device_init(struct saa71
+
+ static int alsa_device_exit(struct saa7134_dev *dev)
+ {
++ if (!snd_saa7134_cards[dev->nr])
++ return 1;
+
+ snd_card_free(snd_saa7134_cards[dev->nr]);
+ snd_saa7134_cards[dev->nr] = NULL;
+@@ -1194,7 +1196,8 @@ static void saa7134_alsa_exit(void)
+ int idx;
+
+ for (idx = 0; idx < SNDRV_CARDS; idx++) {
+- snd_card_free(snd_saa7134_cards[idx]);
++ if (snd_saa7134_cards[idx])
++ snd_card_free(snd_saa7134_cards[idx]);
+ }
+
+ saa7134_dmasound_init = NULL;
v4l2-compat-ioctl32-fix-alignment-for-arm64.patch
media-vb2-dma-contig-fully-cache-synchronise-buffers-in-prepare-and-finish.patch
fix-sysvfs-symlinks.patch
+alsa-usb-audio-fix-teac-ud-501-ud-503-nt-503-usb-delay.patch
+alsa-usb-audio-avoid-freeing-umidi-object-twice.patch
+alsa-compress-disable-get_codec_caps-ioctl-for-some-architectures.patch
+alsa-dummy-disable-switching-timer-backend-via-sysfs.patch
+alsa-seq-fix-incorrect-sanity-check-at-snd_seq_oss_synth_cleanup.patch
+alsa-rawmidi-remove-kernel-warning-for-null-user-space-buffer-check.patch
+alsa-rawmidi-fix-race-at-copying-updating-the-position.patch
+alsa-pcm-fix-potential-deadlock-in-oss-emulation.patch
+asoc-dpcm-fix-the-be-state-on-hw_free.patch
+alsa-seq-fix-yet-another-races-among-alsa-timer-accesses.patch
+alsa-seq-fix-race-at-closing-in-virmidi-driver.patch
+alsa-seq-fix-lockdep-warnings-due-to-double-mutex-locks.patch
+alsa-timer-fix-leftover-link-at-closing.patch
+alsa-timer-fix-link-corruption-due-to-double-start-or-stop.patch
+alsa-timer-fix-wrong-instance-passed-to-slave-callbacks.patch
+alsa-hda-fix-speaker-output-from-vaio-aio-machines.patch
+alsa-dummy-implement-timer-backend-switching-more-safely.patch
+saa7134-alsa-only-frees-registered-sound-cards.patch
+usb-ti_usb_3410_502-fix-id-table-size.patch
+usb-serial-visor-fix-crash-on-detecting-device-without-write_urbs.patch
+usb-visor-fix-null-deref-at-probe.patch
--- /dev/null
+From cb3232138e37129e88240a98a1d2aba2187ff57c Mon Sep 17 00:00:00 2001
+From: Vladis Dronov <vdronov@redhat.com>
+Date: Tue, 12 Jan 2016 15:10:50 +0100
+Subject: USB: serial: visor: fix crash on detecting device without write_urbs
+
+From: Vladis Dronov <vdronov@redhat.com>
+
+commit cb3232138e37129e88240a98a1d2aba2187ff57c upstream.
+
+The visor driver crashes in clie_5_attach() when a specially crafted USB
+device without bulk-out endpoint is detected. This fix adds a check that
+the device has proper configuration expected by the driver.
+
+Reported-by: Ralf Spenneberg <ralf@spenneberg.net>
+Signed-off-by: Vladis Dronov <vdronov@redhat.com>
+Fixes: cfb8da8f69b8 ("USB: visor: fix initialisation of UX50/TH55 devices")
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/visor.c | 6 ++++--
+ 1 file changed, 4 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/serial/visor.c
++++ b/drivers/usb/serial/visor.c
+@@ -604,8 +604,10 @@ static int clie_5_attach(struct usb_seri
+ */
+
+ /* some sanity check */
+- if (serial->num_ports < 2)
+- return -1;
++ if (serial->num_bulk_out < 2) {
++ dev_err(&serial->interface->dev, "missing bulk out endpoints\n");
++ return -ENODEV;
++ }
+
+ /* port 0 now uses the modified endpoint Address */
+ port = serial->port[0];
--- /dev/null
+From ben@decadent.org.uk Sun Feb 14 11:30:13 2016
+From: Ben Hutchings <ben@decadent.org.uk>
+Date: Wed, 23 Dec 2015 13:25:54 +0000
+Subject: USB: ti_usb_3410_502: Fix ID table size
+To: stable@vger.kernel.org
+Message-ID: <20151223132554.GX28542@decadent.org.uk>
+Content-Disposition: inline
+
+From: Ben Hutchings <ben@decadent.org.uk>
+
+Commit 35a2fbc941ac ("USB: serial: ti_usb_3410_5052: new device id for
+Abbot strip port cable") failed to update the size of the
+ti_id_table_3410 array. This doesn't need to be fixed upstream
+following commit d7ece6515e12 ("USB: ti_usb_3410_5052: remove
+vendor/product module parameters") but should be fixed in stable
+branches older than 3.12.
+
+Backports of commit c9d09dc7ad10 ("USB: serial: ti_usb_3410_5052: add
+Abbott strip port ID to combined table as well.") similarly failed to
+update the size of the ti_id_table_combined array.
+
+Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/ti_usb_3410_5052.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/serial/ti_usb_3410_5052.c
++++ b/drivers/usb/serial/ti_usb_3410_5052.c
+@@ -158,7 +158,7 @@ static unsigned int product_5052_count;
+ /* the array dimension is the number of default entries plus */
+ /* TI_EXTRA_VID_PID_COUNT user defined entries plus 1 terminating */
+ /* null entry */
+-static struct usb_device_id ti_id_table_3410[15+TI_EXTRA_VID_PID_COUNT+1] = {
++static struct usb_device_id ti_id_table_3410[16+TI_EXTRA_VID_PID_COUNT+1] = {
+ { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) },
+ { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) },
+ { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) },
+@@ -184,7 +184,7 @@ static struct usb_device_id ti_id_table_
+ { USB_DEVICE(TI_VENDOR_ID, TI_5052_FIRMWARE_PRODUCT_ID) },
+ };
+
+-static struct usb_device_id ti_id_table_combined[19+2*TI_EXTRA_VID_PID_COUNT+1] = {
++static struct usb_device_id ti_id_table_combined[20+2*TI_EXTRA_VID_PID_COUNT+1] = {
+ { USB_DEVICE(TI_VENDOR_ID, TI_3410_PRODUCT_ID) },
+ { USB_DEVICE(TI_VENDOR_ID, TI_3410_EZ430_ID) },
+ { USB_DEVICE(MTS_VENDOR_ID, MTS_GSM_NO_FW_PRODUCT_ID) },
--- /dev/null
+From cac9b50b0d75a1d50d6c056ff65c005f3224c8e0 Mon Sep 17 00:00:00 2001
+From: Johan Hovold <johan@kernel.org>
+Date: Tue, 12 Jan 2016 12:05:20 +0100
+Subject: USB: visor: fix null-deref at probe
+
+From: Johan Hovold <johan@kernel.org>
+
+commit cac9b50b0d75a1d50d6c056ff65c005f3224c8e0 upstream.
+
+Fix null-pointer dereference at probe should a (malicious) Treo device
+lack the expected endpoints.
+
+Specifically, the Treo port-setup hack was dereferencing the bulk-in and
+interrupt-in urbs without first making sure they had been allocated by
+core.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/visor.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/usb/serial/visor.c
++++ b/drivers/usb/serial/visor.c
+@@ -551,6 +551,11 @@ static int treo_attach(struct usb_serial
+ (serial->num_interrupt_in == 0))
+ return 0;
+
++ if (serial->num_bulk_in < 2 || serial->num_interrupt_in < 2) {
++ dev_err(&serial->interface->dev, "missing endpoints\n");
++ return -ENODEV;
++ }
++
+ /*
+ * It appears that Treos and Kyoceras want to use the
+ * 1st bulk in endpoint to communicate with the 2nd bulk out endpoint,