]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.10-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 14 Feb 2016 19:33:30 +0000 (11:33 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 14 Feb 2016 19:33:30 +0000 (11:33 -0800)
added patches:
alsa-compress-disable-get_codec_caps-ioctl-for-some-architectures.patch
alsa-dummy-disable-switching-timer-backend-via-sysfs.patch
alsa-dummy-implement-timer-backend-switching-more-safely.patch
alsa-hda-fix-speaker-output-from-vaio-aio-machines.patch
alsa-pcm-fix-potential-deadlock-in-oss-emulation.patch
alsa-rawmidi-fix-race-at-copying-updating-the-position.patch
alsa-rawmidi-remove-kernel-warning-for-null-user-space-buffer-check.patch
alsa-seq-fix-incorrect-sanity-check-at-snd_seq_oss_synth_cleanup.patch
alsa-seq-fix-lockdep-warnings-due-to-double-mutex-locks.patch
alsa-seq-fix-race-at-closing-in-virmidi-driver.patch
alsa-seq-fix-yet-another-races-among-alsa-timer-accesses.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-usb-audio-avoid-freeing-umidi-object-twice.patch
alsa-usb-audio-fix-teac-ud-501-ud-503-nt-503-usb-delay.patch
asoc-dpcm-fix-the-be-state-on-hw_free.patch
saa7134-alsa-only-frees-registered-sound-cards.patch
usb-serial-visor-fix-crash-on-detecting-device-without-write_urbs.patch
usb-ti_usb_3410_502-fix-id-table-size.patch
usb-visor-fix-null-deref-at-probe.patch

22 files changed:
queue-3.10/alsa-compress-disable-get_codec_caps-ioctl-for-some-architectures.patch [new file with mode: 0644]
queue-3.10/alsa-dummy-disable-switching-timer-backend-via-sysfs.patch [new file with mode: 0644]
queue-3.10/alsa-dummy-implement-timer-backend-switching-more-safely.patch [new file with mode: 0644]
queue-3.10/alsa-hda-fix-speaker-output-from-vaio-aio-machines.patch [new file with mode: 0644]
queue-3.10/alsa-pcm-fix-potential-deadlock-in-oss-emulation.patch [new file with mode: 0644]
queue-3.10/alsa-rawmidi-fix-race-at-copying-updating-the-position.patch [new file with mode: 0644]
queue-3.10/alsa-rawmidi-remove-kernel-warning-for-null-user-space-buffer-check.patch [new file with mode: 0644]
queue-3.10/alsa-seq-fix-incorrect-sanity-check-at-snd_seq_oss_synth_cleanup.patch [new file with mode: 0644]
queue-3.10/alsa-seq-fix-lockdep-warnings-due-to-double-mutex-locks.patch [new file with mode: 0644]
queue-3.10/alsa-seq-fix-race-at-closing-in-virmidi-driver.patch [new file with mode: 0644]
queue-3.10/alsa-seq-fix-yet-another-races-among-alsa-timer-accesses.patch [new file with mode: 0644]
queue-3.10/alsa-timer-fix-leftover-link-at-closing.patch [new file with mode: 0644]
queue-3.10/alsa-timer-fix-link-corruption-due-to-double-start-or-stop.patch [new file with mode: 0644]
queue-3.10/alsa-timer-fix-wrong-instance-passed-to-slave-callbacks.patch [new file with mode: 0644]
queue-3.10/alsa-usb-audio-avoid-freeing-umidi-object-twice.patch [new file with mode: 0644]
queue-3.10/alsa-usb-audio-fix-teac-ud-501-ud-503-nt-503-usb-delay.patch [new file with mode: 0644]
queue-3.10/asoc-dpcm-fix-the-be-state-on-hw_free.patch [new file with mode: 0644]
queue-3.10/saa7134-alsa-only-frees-registered-sound-cards.patch [new file with mode: 0644]
queue-3.10/series
queue-3.10/usb-serial-visor-fix-crash-on-detecting-device-without-write_urbs.patch [new file with mode: 0644]
queue-3.10/usb-ti_usb_3410_502-fix-id-table-size.patch [new file with mode: 0644]
queue-3.10/usb-visor-fix-null-deref-at-probe.patch [new file with mode: 0644]

diff --git a/queue-3.10/alsa-compress-disable-get_codec_caps-ioctl-for-some-architectures.patch b/queue-3.10/alsa-compress-disable-get_codec_caps-ioctl-for-some-architectures.patch
new file mode 100644 (file)
index 0000000..3403a81
--- /dev/null
@@ -0,0 +1,74 @@
+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;
diff --git a/queue-3.10/alsa-dummy-disable-switching-timer-backend-via-sysfs.patch b/queue-3.10/alsa-dummy-disable-switching-timer-backend-via-sysfs.patch
new file mode 100644 (file)
index 0000000..49ccb68
--- /dev/null
@@ -0,0 +1,39 @@
+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
diff --git a/queue-3.10/alsa-dummy-implement-timer-backend-switching-more-safely.patch b/queue-3.10/alsa-dummy-implement-timer-backend-switching-more-safely.patch
new file mode 100644 (file)
index 0000000..6d53292
--- /dev/null
@@ -0,0 +1,174 @@
+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;
+ }
diff --git a/queue-3.10/alsa-hda-fix-speaker-output-from-vaio-aio-machines.patch b/queue-3.10/alsa-hda-fix-speaker-output-from-vaio-aio-machines.patch
new file mode 100644 (file)
index 0000000..3267271
--- /dev/null
@@ -0,0 +1,30 @@
+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),
diff --git a/queue-3.10/alsa-pcm-fix-potential-deadlock-in-oss-emulation.patch b/queue-3.10/alsa-pcm-fix-potential-deadlock-in-oss-emulation.patch
new file mode 100644 (file)
index 0000000..2257f22
--- /dev/null
@@ -0,0 +1,100 @@
+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
diff --git a/queue-3.10/alsa-rawmidi-fix-race-at-copying-updating-the-position.patch b/queue-3.10/alsa-rawmidi-fix-race-at-copying-updating-the-position.patch
new file mode 100644 (file)
index 0000000..77a850a
--- /dev/null
@@ -0,0 +1,121 @@
+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;
+       }
diff --git a/queue-3.10/alsa-rawmidi-remove-kernel-warning-for-null-user-space-buffer-check.patch b/queue-3.10/alsa-rawmidi-remove-kernel-warning-for-null-user-space-buffer-check.patch
new file mode 100644 (file)
index 0000000..ba03e12
--- /dev/null
@@ -0,0 +1,33 @@
+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;
diff --git a/queue-3.10/alsa-seq-fix-incorrect-sanity-check-at-snd_seq_oss_synth_cleanup.patch b/queue-3.10/alsa-seq-fix-incorrect-sanity-check-at-snd_seq_oss_synth_cleanup.patch
new file mode 100644 (file)
index 0000000..754d225
--- /dev/null
@@ -0,0 +1,35 @@
+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];
diff --git a/queue-3.10/alsa-seq-fix-lockdep-warnings-due-to-double-mutex-locks.patch b/queue-3.10/alsa-seq-fix-lockdep-warnings-due-to-double-mutex-locks.patch
new file mode 100644 (file)
index 0000000..fd7db71
--- /dev/null
@@ -0,0 +1,377 @@
+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;
+ }
diff --git a/queue-3.10/alsa-seq-fix-race-at-closing-in-virmidi-driver.patch b/queue-3.10/alsa-seq-fix-race-at-closing-in-virmidi-driver.patch
new file mode 100644 (file)
index 0000000..e2b7cc4
--- /dev/null
@@ -0,0 +1,43 @@
+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;
diff --git a/queue-3.10/alsa-seq-fix-yet-another-races-among-alsa-timer-accesses.patch b/queue-3.10/alsa-seq-fix-yet-another-races-among-alsa-timer-accesses.patch
new file mode 100644 (file)
index 0000000..2603df8
--- /dev/null
@@ -0,0 +1,228 @@
+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;        
+ }
diff --git a/queue-3.10/alsa-timer-fix-leftover-link-at-closing.patch b/queue-3.10/alsa-timer-fix-leftover-link-at-closing.patch
new file mode 100644 (file)
index 0000000..0f26baf
--- /dev/null
@@ -0,0 +1,46 @@
+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))
diff --git a/queue-3.10/alsa-timer-fix-link-corruption-due-to-double-start-or-stop.patch b/queue-3.10/alsa-timer-fix-link-corruption-due-to-double-start-or-stop.patch
new file mode 100644 (file)
index 0000000..81e6cc2
--- /dev/null
@@ -0,0 +1,111 @@
+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;
diff --git a/queue-3.10/alsa-timer-fix-wrong-instance-passed-to-slave-callbacks.patch b/queue-3.10/alsa-timer-fix-wrong-instance-passed-to-slave-callbacks.patch
new file mode 100644 (file)
index 0000000..7625ebb
--- /dev/null
@@ -0,0 +1,36 @@
+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);
+ }
diff --git a/queue-3.10/alsa-usb-audio-avoid-freeing-umidi-object-twice.patch b/queue-3.10/alsa-usb-audio-avoid-freeing-umidi-object-twice.patch
new file mode 100644 (file)
index 0000000..114f195
--- /dev/null
@@ -0,0 +1,34 @@
+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;
+       }
diff --git a/queue-3.10/alsa-usb-audio-fix-teac-ud-501-ud-503-nt-503-usb-delay.patch b/queue-3.10/alsa-usb-audio-fix-teac-ud-501-ud-503-nt-503-usb-delay.patch
new file mode 100644 (file)
index 0000000..b616aad
--- /dev/null
@@ -0,0 +1,53 @@
+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
+        */
diff --git a/queue-3.10/asoc-dpcm-fix-the-be-state-on-hw_free.patch b/queue-3.10/asoc-dpcm-fix-the-be-state-on-hw_free.patch
new file mode 100644 (file)
index 0000000..b465bef
--- /dev/null
@@ -0,0 +1,39 @@
+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",
diff --git a/queue-3.10/saa7134-alsa-only-frees-registered-sound-cards.patch b/queue-3.10/saa7134-alsa-only-frees-registered-sound-cards.patch
new file mode 100644 (file)
index 0000000..2d19528
--- /dev/null
@@ -0,0 +1,69 @@
+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;
index f794b872ccf80da649c91c8c4c42b4f6b68d8fc2..ceda30abee1e495122e8210f38ab8ca0a3152c14 100644 (file)
@@ -23,3 +23,24 @@ parisc-fix-__arch_si_preamble_size.patch
 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
diff --git a/queue-3.10/usb-serial-visor-fix-crash-on-detecting-device-without-write_urbs.patch b/queue-3.10/usb-serial-visor-fix-crash-on-detecting-device-without-write_urbs.patch
new file mode 100644 (file)
index 0000000..99a9a6e
--- /dev/null
@@ -0,0 +1,38 @@
+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];
diff --git a/queue-3.10/usb-ti_usb_3410_502-fix-id-table-size.patch b/queue-3.10/usb-ti_usb_3410_502-fix-id-table-size.patch
new file mode 100644 (file)
index 0000000..a73efc8
--- /dev/null
@@ -0,0 +1,48 @@
+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) },
diff --git a/queue-3.10/usb-visor-fix-null-deref-at-probe.patch b/queue-3.10/usb-visor-fix-null-deref-at-probe.patch
new file mode 100644 (file)
index 0000000..d58cde7
--- /dev/null
@@ -0,0 +1,38 @@
+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,