]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.14-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 14 Feb 2016 19:45:52 +0000 (11:45 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sun, 14 Feb 2016 19:45:52 +0000 (11:45 -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-add-fixup-for-mac-mini-7-1-model.patch
alsa-hda-fix-speaker-output-from-vaio-aio-machines.patch
alsa-hda-fix-static-checker-warning-in-patch_hdmi.c.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
tty-fix-gpf-in-flush_to_ldisc.patch
tty-fix-unsafe-ldisc-reference-via-ioctl-tiocgetd.patch
usb-cp210x-add-id-for-iai-usb-to-rs485-adaptor.patch
usb-hub-do-not-clear-bos-field-during-reset-device.patch
usb-option-fix-cinterion-ahxx-enumeration.patch
usb-serial-ftdi_sio-add-support-for-yaesu-scu-18-cable.patch
usb-serial-option-adding-support-for-telit-le922.patch
usb-serial-visor-fix-crash-on-detecting-device-without-write_urbs.patch
usb-visor-fix-null-deref-at-probe.patch

30 files changed:
queue-3.14/alsa-compress-disable-get_codec_caps-ioctl-for-some-architectures.patch [new file with mode: 0644]
queue-3.14/alsa-dummy-disable-switching-timer-backend-via-sysfs.patch [new file with mode: 0644]
queue-3.14/alsa-dummy-implement-timer-backend-switching-more-safely.patch [new file with mode: 0644]
queue-3.14/alsa-hda-add-fixup-for-mac-mini-7-1-model.patch [new file with mode: 0644]
queue-3.14/alsa-hda-fix-speaker-output-from-vaio-aio-machines.patch [new file with mode: 0644]
queue-3.14/alsa-hda-fix-static-checker-warning-in-patch_hdmi.c.patch [new file with mode: 0644]
queue-3.14/alsa-pcm-fix-potential-deadlock-in-oss-emulation.patch [new file with mode: 0644]
queue-3.14/alsa-rawmidi-fix-race-at-copying-updating-the-position.patch [new file with mode: 0644]
queue-3.14/alsa-rawmidi-remove-kernel-warning-for-null-user-space-buffer-check.patch [new file with mode: 0644]
queue-3.14/alsa-seq-fix-incorrect-sanity-check-at-snd_seq_oss_synth_cleanup.patch [new file with mode: 0644]
queue-3.14/alsa-seq-fix-lockdep-warnings-due-to-double-mutex-locks.patch [new file with mode: 0644]
queue-3.14/alsa-seq-fix-race-at-closing-in-virmidi-driver.patch [new file with mode: 0644]
queue-3.14/alsa-seq-fix-yet-another-races-among-alsa-timer-accesses.patch [new file with mode: 0644]
queue-3.14/alsa-timer-fix-leftover-link-at-closing.patch [new file with mode: 0644]
queue-3.14/alsa-timer-fix-link-corruption-due-to-double-start-or-stop.patch [new file with mode: 0644]
queue-3.14/alsa-timer-fix-wrong-instance-passed-to-slave-callbacks.patch [new file with mode: 0644]
queue-3.14/alsa-usb-audio-avoid-freeing-umidi-object-twice.patch [new file with mode: 0644]
queue-3.14/alsa-usb-audio-fix-teac-ud-501-ud-503-nt-503-usb-delay.patch [new file with mode: 0644]
queue-3.14/asoc-dpcm-fix-the-be-state-on-hw_free.patch [new file with mode: 0644]
queue-3.14/saa7134-alsa-only-frees-registered-sound-cards.patch [new file with mode: 0644]
queue-3.14/series
queue-3.14/tty-fix-gpf-in-flush_to_ldisc.patch [new file with mode: 0644]
queue-3.14/tty-fix-unsafe-ldisc-reference-via-ioctl-tiocgetd.patch [new file with mode: 0644]
queue-3.14/usb-cp210x-add-id-for-iai-usb-to-rs485-adaptor.patch [new file with mode: 0644]
queue-3.14/usb-hub-do-not-clear-bos-field-during-reset-device.patch [new file with mode: 0644]
queue-3.14/usb-option-fix-cinterion-ahxx-enumeration.patch [new file with mode: 0644]
queue-3.14/usb-serial-ftdi_sio-add-support-for-yaesu-scu-18-cable.patch [new file with mode: 0644]
queue-3.14/usb-serial-option-adding-support-for-telit-le922.patch [new file with mode: 0644]
queue-3.14/usb-serial-visor-fix-crash-on-detecting-device-without-write_urbs.patch [new file with mode: 0644]
queue-3.14/usb-visor-fix-null-deref-at-probe.patch [new file with mode: 0644]

diff --git a/queue-3.14/alsa-compress-disable-get_codec_caps-ioctl-for-some-architectures.patch b/queue-3.14/alsa-compress-disable-get_codec_caps-ioctl-for-some-architectures.patch
new file mode 100644 (file)
index 0000000..08d39e3
--- /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
+@@ -438,6 +445,7 @@ out:
+       return retval;
+ }
++#ifndef COMPR_CODEC_CAPS_OVERFLOW
+ static int
+ snd_compr_get_codec_caps(struct snd_compr_stream *stream, unsigned long arg)
+ {
+@@ -461,6 +469,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,
+@@ -799,9 +808,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.14/alsa-dummy-disable-switching-timer-backend-via-sysfs.patch b/queue-3.14/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.14/alsa-dummy-implement-timer-backend-switching-more-safely.patch b/queue-3.14/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.14/alsa-hda-add-fixup-for-mac-mini-7-1-model.patch b/queue-3.14/alsa-hda-add-fixup-for-mac-mini-7-1-model.patch
new file mode 100644 (file)
index 0000000..ada7066
--- /dev/null
@@ -0,0 +1,90 @@
+From 2154cc0e2d4ae15132d005d17e473327c70c9a06 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Wed, 3 Feb 2016 12:32:51 +0100
+Subject: ALSA: hda - Add fixup for Mac Mini 7,1 model
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit 2154cc0e2d4ae15132d005d17e473327c70c9a06 upstream.
+
+Mac Mini 7,1 model with CS4208 codec reports the headphone jack
+detection wrongly in an inverted way.  Moreover, the advertised pins
+for the audio input and SPDIF output have actually no jack detection.
+
+This patch addresses these issues.  The inv_jack_detect flag is set
+for fixing the headphone jack detection, and the pin configs for audio
+input and SPDIF output are marked as non-detectable.
+
+Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=105161
+Report-and-tested-by: moosotc@gmail.com
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/pci/hda/patch_cirrus.c |   27 +++++++++++++++++++++++++++
+ 1 file changed, 27 insertions(+)
+
+--- a/sound/pci/hda/patch_cirrus.c
++++ b/sound/pci/hda/patch_cirrus.c
+@@ -617,6 +617,7 @@ enum {
+       CS4208_MAC_AUTO,
+       CS4208_MBA6,
+       CS4208_MBP11,
++      CS4208_MACMINI,
+       CS4208_GPIO0,
+ };
+@@ -624,6 +625,7 @@ static const struct hda_model_fixup cs42
+       { .id = CS4208_GPIO0, .name = "gpio0" },
+       { .id = CS4208_MBA6, .name = "mba6" },
+       { .id = CS4208_MBP11, .name = "mbp11" },
++      { .id = CS4208_MACMINI, .name = "macmini" },
+       {}
+ };
+@@ -635,6 +637,7 @@ static const struct snd_pci_quirk cs4208
+ /* codec SSID matching */
+ static const struct snd_pci_quirk cs4208_mac_fixup_tbl[] = {
+       SND_PCI_QUIRK(0x106b, 0x5e00, "MacBookPro 11,2", CS4208_MBP11),
++      SND_PCI_QUIRK(0x106b, 0x6c00, "MacMini 7,1", CS4208_MACMINI),
+       SND_PCI_QUIRK(0x106b, 0x7100, "MacBookAir 6,1", CS4208_MBA6),
+       SND_PCI_QUIRK(0x106b, 0x7200, "MacBookAir 6,2", CS4208_MBA6),
+       SND_PCI_QUIRK(0x106b, 0x7b00, "MacBookPro 12,1", CS4208_MBP11),
+@@ -667,6 +670,24 @@ static void cs4208_fixup_mac(struct hda_
+       snd_hda_apply_fixup(codec, action);
+ }
++/* MacMini 7,1 has the inverted jack detection */
++static void cs4208_fixup_macmini(struct hda_codec *codec,
++                               const struct hda_fixup *fix, int action)
++{
++      static const struct hda_pintbl pincfgs[] = {
++              { 0x18, 0x00ab9150 }, /* mic (audio-in) jack: disable detect */
++              { 0x21, 0x004be140 }, /* SPDIF: disable detect */
++              { }
++      };
++
++      if (action == HDA_FIXUP_ACT_PRE_PROBE) {
++              /* HP pin (0x10) has an inverted detection */
++              codec->inv_jack_detect = 1;
++              /* disable the bogus Mic and SPDIF jack detections */
++              snd_hda_apply_pincfgs(codec, pincfgs);
++      }
++}
++
+ static int cs4208_spdif_sw_put(struct snd_kcontrol *kcontrol,
+                              struct snd_ctl_elem_value *ucontrol)
+ {
+@@ -710,6 +731,12 @@ static const struct hda_fixup cs4208_fix
+               .chained = true,
+               .chain_id = CS4208_GPIO0,
+       },
++      [CS4208_MACMINI] = {
++              .type = HDA_FIXUP_FUNC,
++              .v.func = cs4208_fixup_macmini,
++              .chained = true,
++              .chain_id = CS4208_GPIO0,
++      },
+       [CS4208_GPIO0] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = cs4208_fixup_gpio0,
diff --git a/queue-3.14/alsa-hda-fix-speaker-output-from-vaio-aio-machines.patch b/queue-3.14/alsa-hda-fix-speaker-output-from-vaio-aio-machines.patch
new file mode 100644 (file)
index 0000000..e5c6b6e
--- /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
+@@ -2266,6 +2266,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.14/alsa-hda-fix-static-checker-warning-in-patch_hdmi.c.patch b/queue-3.14/alsa-hda-fix-static-checker-warning-in-patch_hdmi.c.patch
new file mode 100644 (file)
index 0000000..b4585ea
--- /dev/null
@@ -0,0 +1,40 @@
+From 360a8245680053619205a3ae10e6bfe624a5da1d Mon Sep 17 00:00:00 2001
+From: David Henningsson <david.henningsson@canonical.com>
+Date: Fri, 5 Feb 2016 09:05:41 +0100
+Subject: ALSA: hda - Fix static checker warning in patch_hdmi.c
+
+From: David Henningsson <david.henningsson@canonical.com>
+
+commit 360a8245680053619205a3ae10e6bfe624a5da1d upstream.
+
+The static checker warning is:
+
+       sound/pci/hda/patch_hdmi.c:460 hdmi_eld_ctl_get()
+       error: __memcpy() 'eld->eld_buffer' too small (256 vs 512)
+
+I have a hard time figuring out if this can ever cause an information leak
+(I don't think so), but nonetheless it does not hurt to increase the
+robustness of the code.
+
+Fixes: 68e03de98507 ('ALSA: hda - hdmi: Do not expose eld data when eld is invalid')
+Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
+Signed-off-by: David Henningsson <david.henningsson@canonical.com>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/pci/hda/patch_hdmi.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/sound/pci/hda/patch_hdmi.c
++++ b/sound/pci/hda/patch_hdmi.c
+@@ -426,7 +426,8 @@ static int hdmi_eld_ctl_get(struct snd_k
+       eld = &per_pin->sink_eld;
+       mutex_lock(&per_pin->lock);
+-      if (eld->eld_size > ARRAY_SIZE(ucontrol->value.bytes.data)) {
++      if (eld->eld_size > ARRAY_SIZE(ucontrol->value.bytes.data) ||
++          eld->eld_size > ELD_MAX_SIZE) {
+               mutex_unlock(&per_pin->lock);
+               snd_BUG();
+               return -EINVAL;
diff --git a/queue-3.14/alsa-pcm-fix-potential-deadlock-in-oss-emulation.patch b/queue-3.14/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.14/alsa-rawmidi-fix-race-at-copying-updating-the-position.patch b/queue-3.14/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.14/alsa-rawmidi-remove-kernel-warning-for-null-user-space-buffer-check.patch b/queue-3.14/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.14/alsa-seq-fix-incorrect-sanity-check-at-snd_seq_oss_synth_cleanup.patch b/queue-3.14/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.14/alsa-seq-fix-lockdep-warnings-due-to-double-mutex-locks.patch b/queue-3.14/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.14/alsa-seq-fix-race-at-closing-in-virmidi-driver.patch b/queue-3.14/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.14/alsa-seq-fix-yet-another-races-among-alsa-timer-accesses.patch b/queue-3.14/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.14/alsa-timer-fix-leftover-link-at-closing.patch b/queue-3.14/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.14/alsa-timer-fix-link-corruption-due-to-double-start-or-stop.patch b/queue-3.14/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.14/alsa-timer-fix-wrong-instance-passed-to-slave-callbacks.patch b/queue-3.14/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.14/alsa-usb-audio-avoid-freeing-umidi-object-twice.patch b/queue-3.14/alsa-usb-audio-avoid-freeing-umidi-object-twice.patch
new file mode 100644 (file)
index 0000000..fc7cf83
--- /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
+@@ -2365,7 +2365,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.14/alsa-usb-audio-fix-teac-ud-501-ud-503-nt-503-usb-delay.patch b/queue-3.14/alsa-usb-audio-fix-teac-ud-501-ud-503-nt-503-usb-delay.patch
new file mode 100644 (file)
index 0000000..0df67ac
--- /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
+@@ -1128,8 +1128,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,
+@@ -1144,6 +1148,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.14/asoc-dpcm-fix-the-be-state-on-hw_free.patch b/queue-3.14/asoc-dpcm-fix-the-be-state-on-hw_free.patch
new file mode 100644 (file)
index 0000000..dc70416
--- /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
+@@ -1404,7 +1404,8 @@ int dpcm_be_dai_hw_free(struct snd_soc_p
+                   (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.14/saa7134-alsa-only-frees-registered-sound-cards.patch b/queue-3.14/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 f7375ee071eaf4414d28de6fe63d1992aa59023c..69ccb57adb0442427882d7ce576c86e6b4021434 100644 (file)
@@ -30,3 +30,32 @@ 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-add-fixup-for-mac-mini-7-1-model.patch
+alsa-hda-fix-static-checker-warning-in-patch_hdmi.c.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-serial-visor-fix-crash-on-detecting-device-without-write_urbs.patch
+usb-visor-fix-null-deref-at-probe.patch
+usb-hub-do-not-clear-bos-field-during-reset-device.patch
+usb-serial-ftdi_sio-add-support-for-yaesu-scu-18-cable.patch
+usb-cp210x-add-id-for-iai-usb-to-rs485-adaptor.patch
+usb-serial-option-adding-support-for-telit-le922.patch
+usb-option-fix-cinterion-ahxx-enumeration.patch
+tty-fix-gpf-in-flush_to_ldisc.patch
+tty-fix-unsafe-ldisc-reference-via-ioctl-tiocgetd.patch
diff --git a/queue-3.14/tty-fix-gpf-in-flush_to_ldisc.patch b/queue-3.14/tty-fix-gpf-in-flush_to_ldisc.patch
new file mode 100644 (file)
index 0000000..0601b1b
--- /dev/null
@@ -0,0 +1,67 @@
+From 9ce119f318ba1a07c29149301f1544b6c4bea52a Mon Sep 17 00:00:00 2001
+From: Peter Hurley <peter@hurleysoftware.com>
+Date: Fri, 27 Nov 2015 14:25:08 -0500
+Subject: tty: Fix GPF in flush_to_ldisc()
+
+From: Peter Hurley <peter@hurleysoftware.com>
+
+commit 9ce119f318ba1a07c29149301f1544b6c4bea52a upstream.
+
+A line discipline which does not define a receive_buf() method can
+can cause a GPF if data is ever received [1]. Oddly, this was known
+to the author of n_tracesink in 2011, but never fixed.
+
+[1] GPF report
+    BUG: unable to handle kernel NULL pointer dereference at           (null)
+    IP: [<          (null)>]           (null)
+    PGD 3752d067 PUD 37a7b067 PMD 0
+    Oops: 0010 [#1] SMP KASAN
+    Modules linked in:
+    CPU: 2 PID: 148 Comm: kworker/u10:2 Not tainted 4.4.0-rc2+ #51
+    Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011
+    Workqueue: events_unbound flush_to_ldisc
+    task: ffff88006da94440 ti: ffff88006db60000 task.ti: ffff88006db60000
+    RIP: 0010:[<0000000000000000>]  [<          (null)>]           (null)
+    RSP: 0018:ffff88006db67b50  EFLAGS: 00010246
+    RAX: 0000000000000102 RBX: ffff88003ab32f88 RCX: 0000000000000102
+    RDX: 0000000000000000 RSI: ffff88003ab330a6 RDI: ffff88003aabd388
+    RBP: ffff88006db67c48 R08: ffff88003ab32f9c R09: ffff88003ab31fb0
+    R10: ffff88003ab32fa8 R11: 0000000000000000 R12: dffffc0000000000
+    R13: ffff88006db67c20 R14: ffffffff863df820 R15: ffff88003ab31fb8
+    FS:  0000000000000000(0000) GS:ffff88006dc00000(0000) knlGS:0000000000000000
+    CS:  0010 DS: 0000 ES: 0000 CR0: 000000008005003b
+    CR2: 0000000000000000 CR3: 0000000037938000 CR4: 00000000000006e0
+    Stack:
+     ffffffff829f46f1 ffff88006da94bf8 ffff88006da94bf8 0000000000000000
+     ffff88003ab31fb0 ffff88003aabd438 ffff88003ab31ff8 ffff88006430fd90
+     ffff88003ab32f9c ffffed0007557a87 1ffff1000db6cf78 ffff88003ab32078
+    Call Trace:
+     [<ffffffff8127cf91>] process_one_work+0x8f1/0x17a0 kernel/workqueue.c:2030
+     [<ffffffff8127df14>] worker_thread+0xd4/0x1180 kernel/workqueue.c:2162
+     [<ffffffff8128faaf>] kthread+0x1cf/0x270 drivers/block/aoe/aoecmd.c:1302
+     [<ffffffff852a7c2f>] ret_from_fork+0x3f/0x70 arch/x86/entry/entry_64.S:468
+    Code:  Bad RIP value.
+    RIP  [<          (null)>]           (null)
+     RSP <ffff88006db67b50>
+    CR2: 0000000000000000
+    ---[ end trace a587f8947e54d6ea ]---
+
+Reported-by: Dmitry Vyukov <dvyukov@google.com>
+Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/tty/tty_buffer.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/tty/tty_buffer.c
++++ b/drivers/tty/tty_buffer.c
+@@ -411,7 +411,7 @@ receive_buf(struct tty_struct *tty, stru
+               count = disc->ops->receive_buf2(tty, p, f, count);
+       else {
+               count = min_t(int, count, tty->receive_room);
+-              if (count)
++              if (count && disc->ops->receive_buf)
+                       disc->ops->receive_buf(tty, p, f, count);
+       }
+       head->read += count;
diff --git a/queue-3.14/tty-fix-unsafe-ldisc-reference-via-ioctl-tiocgetd.patch b/queue-3.14/tty-fix-unsafe-ldisc-reference-via-ioctl-tiocgetd.patch
new file mode 100644 (file)
index 0000000..4101047
--- /dev/null
@@ -0,0 +1,68 @@
+From 5c17c861a357e9458001f021a7afa7aab9937439 Mon Sep 17 00:00:00 2001
+From: Peter Hurley <peter@hurleysoftware.com>
+Date: Sun, 10 Jan 2016 22:40:55 -0800
+Subject: tty: Fix unsafe ldisc reference via ioctl(TIOCGETD)
+
+From: Peter Hurley <peter@hurleysoftware.com>
+
+commit 5c17c861a357e9458001f021a7afa7aab9937439 upstream.
+
+ioctl(TIOCGETD) retrieves the line discipline id directly from the
+ldisc because the line discipline id (c_line) in termios is untrustworthy;
+userspace may have set termios via ioctl(TCSETS*) without actually
+changing the line discipline via ioctl(TIOCSETD).
+
+However, directly accessing the current ldisc via tty->ldisc is
+unsafe; the ldisc ptr dereferenced may be stale if the line discipline
+is changing via ioctl(TIOCSETD) or hangup.
+
+Wait for the line discipline reference (just like read() or write())
+to retrieve the "current" line discipline id.
+
+Signed-off-by: Peter Hurley <peter@hurleysoftware.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/tty/tty_io.c |   24 +++++++++++++++++++++++-
+ 1 file changed, 23 insertions(+), 1 deletion(-)
+
+--- a/drivers/tty/tty_io.c
++++ b/drivers/tty/tty_io.c
+@@ -2581,6 +2581,28 @@ static int tiocsetd(struct tty_struct *t
+ }
+ /**
++ *    tiocgetd        -       get line discipline
++ *    @tty: tty device
++ *    @p: pointer to user data
++ *
++ *    Retrieves the line discipline id directly from the ldisc.
++ *
++ *    Locking: waits for ldisc reference (in case the line discipline
++ *            is changing or the tty is being hungup)
++ */
++
++static int tiocgetd(struct tty_struct *tty, int __user *p)
++{
++      struct tty_ldisc *ld;
++      int ret;
++
++      ld = tty_ldisc_ref_wait(tty);
++      ret = put_user(ld->ops->num, p);
++      tty_ldisc_deref(ld);
++      return ret;
++}
++
++/**
+  *    send_break      -       performed time break
+  *    @tty: device to break on
+  *    @duration: timeout in mS
+@@ -2794,7 +2816,7 @@ long tty_ioctl(struct file *file, unsign
+       case TIOCGSID:
+               return tiocgsid(tty, real_tty, p);
+       case TIOCGETD:
+-              return put_user(tty->ldisc->ops->num, (int __user *)p);
++              return tiocgetd(tty, p);
+       case TIOCSETD:
+               return tiocsetd(tty, p);
+       case TIOCVHANGUP:
diff --git a/queue-3.14/usb-cp210x-add-id-for-iai-usb-to-rs485-adaptor.patch b/queue-3.14/usb-cp210x-add-id-for-iai-usb-to-rs485-adaptor.patch
new file mode 100644 (file)
index 0000000..57b264b
--- /dev/null
@@ -0,0 +1,30 @@
+From f487c54ddd544e1c9172cd510954f697b77b76e3 Mon Sep 17 00:00:00 2001
+From: Peter Dedecker <peter.dedecker@hotmail.com>
+Date: Fri, 8 Jan 2016 12:34:41 +0100
+Subject: USB: cp210x: add ID for IAI USB to RS485 adaptor
+
+From: Peter Dedecker <peter.dedecker@hotmail.com>
+
+commit f487c54ddd544e1c9172cd510954f697b77b76e3 upstream.
+
+Added the USB serial console device ID for IAI Corp. RCB-CV-USB
+USB to RS485 adaptor.
+
+Signed-off-by: Peter Dedecker <peter.dedecker@hotmail.com>
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/cp210x.c |    1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/drivers/usb/serial/cp210x.c
++++ b/drivers/usb/serial/cp210x.c
+@@ -98,6 +98,7 @@ static const struct usb_device_id id_tab
+       { USB_DEVICE(0x10C4, 0x81AC) }, /* MSD Dash Hawk */
+       { USB_DEVICE(0x10C4, 0x81AD) }, /* INSYS USB Modem */
+       { USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */
++      { USB_DEVICE(0x10C4, 0x81D7) }, /* IAI Corp. RCB-CV-USB USB to RS485 Adaptor */
+       { USB_DEVICE(0x10C4, 0x81E2) }, /* Lipowsky Industrie Elektronik GmbH, Baby-LIN */
+       { USB_DEVICE(0x10C4, 0x81E7) }, /* Aerocomm Radio */
+       { USB_DEVICE(0x10C4, 0x81E8) }, /* Zephyr Bioharness */
diff --git a/queue-3.14/usb-hub-do-not-clear-bos-field-during-reset-device.patch b/queue-3.14/usb-hub-do-not-clear-bos-field-during-reset-device.patch
new file mode 100644 (file)
index 0000000..ad63fa1
--- /dev/null
@@ -0,0 +1,61 @@
+From d8f00cd685f5c8e0def8593e520a7fef12c22407 Mon Sep 17 00:00:00 2001
+From: "Du, Changbin" <changbin.du@intel.com>
+Date: Mon, 18 Jan 2016 21:02:42 +0800
+Subject: usb: hub: do not clear BOS field during reset device
+
+From: Du, Changbin <changbin.du@intel.com>
+
+commit d8f00cd685f5c8e0def8593e520a7fef12c22407 upstream.
+
+In function usb_reset_and_verify_device, the old BOS descriptor may
+still be used before allocating a new one. (usb_unlocked_disable_lpm
+function uses it under the situation that it fails to disable lpm.)
+So we cannot set the udev->bos to NULL before that, just keep what it
+was. It will be overwrite when allocating a new one.
+
+Crash log:
+BUG: unable to handle kernel NULL pointer dereference at
+0000000000000010
+IP: [<ffffffff8171f98d>] usb_enable_link_state+0x2d/0x2f0
+Call Trace:
+[<ffffffff8171ed5b>] ? usb_set_lpm_timeout+0x12b/0x140
+[<ffffffff8171fcd1>] usb_enable_lpm+0x81/0xa0
+[<ffffffff8171fdd8>] usb_disable_lpm+0xa8/0xc0
+[<ffffffff8171fe1c>] usb_unlocked_disable_lpm+0x2c/0x50
+[<ffffffff81723933>] usb_reset_and_verify_device+0xc3/0x710
+[<ffffffff8172c4ed>] ? usb_sg_wait+0x13d/0x190
+[<ffffffff81724743>] usb_reset_device+0x133/0x280
+[<ffffffff8179ccd1>] usb_stor_port_reset+0x61/0x70
+[<ffffffff8179cd68>] usb_stor_invoke_transport+0x88/0x520
+
+Signed-off-by: Du, Changbin <changbin.du@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/core/hub.c |    8 +++++---
+ 1 file changed, 5 insertions(+), 3 deletions(-)
+
+--- a/drivers/usb/core/hub.c
++++ b/drivers/usb/core/hub.c
+@@ -5225,7 +5225,6 @@ static int usb_reset_and_verify_device(s
+               usb_set_usb2_hardware_lpm(udev, 0);
+       bos = udev->bos;
+-      udev->bos = NULL;
+       /* Disable LPM and LTM while we reset the device and reinstall the alt
+        * settings.  Device-initiated LPM settings, and system exit latency
+@@ -5334,8 +5333,11 @@ done:
+       usb_set_usb2_hardware_lpm(udev, 1);
+       usb_unlocked_enable_lpm(udev);
+       usb_enable_ltm(udev);
+-      usb_release_bos_descriptor(udev);
+-      udev->bos = bos;
++      /* release the new BOS descriptor allocated  by hub_port_init() */
++      if (udev->bos != bos) {
++              usb_release_bos_descriptor(udev);
++              udev->bos = bos;
++      }
+       return 0;
+ re_enumerate:
diff --git a/queue-3.14/usb-option-fix-cinterion-ahxx-enumeration.patch b/queue-3.14/usb-option-fix-cinterion-ahxx-enumeration.patch
new file mode 100644 (file)
index 0000000..f64272a
--- /dev/null
@@ -0,0 +1,48 @@
+From 4152b387da81617c80cb2946b2d56e3958906b3e Mon Sep 17 00:00:00 2001
+From: John Ernberg <john.ernberg@actia.se>
+Date: Mon, 25 Jan 2016 12:27:17 +0000
+Subject: USB: option: fix Cinterion AHxx enumeration
+
+From: John Ernberg <john.ernberg@actia.se>
+
+commit 4152b387da81617c80cb2946b2d56e3958906b3e upstream.
+
+In certain kernel configurations where the cdc_ether and option drivers
+are compiled as modules there can occur a race condition in enumeration.
+This causes the option driver to enumerate the ethernet(wwan) interface
+as usb-serial interfaces.
+
+usb-devices output for the modem:
+T:  Bus=01 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  5 Spd=480 MxCh= 0
+D:  Ver= 2.00 Cls=ef(misc ) Sub=02 Prot=01 MxPS=64 #Cfgs=  1
+P:  Vendor=1e2d ProdID=0055 Rev=00.00
+S:  Manufacturer=Cinterion
+S:  Product=AHx
+C:  #Ifs= 6 Cfg#= 1 Atr=e0 MxPwr=10mA
+I:  If#= 0 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option
+I:  If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option
+I:  If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=option
+I:  If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=ff Driver=option
+I:  If#= 4 Alt= 0 #EPs= 1 Cls=02(commc) Sub=06 Prot=00 Driver=cdc_ether
+I:  If#= 5 Alt= 1 #EPs= 2 Cls=0a(data ) Sub=00 Prot=00 Driver=cdc_ether
+
+Signed-off-by: John Ernberg <john.ernberg@actia.se>
+Fixes: 1941138e1c02 ("USB: added support for Cinterion's products...")
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/option.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/usb/serial/option.c
++++ b/drivers/usb/serial/option.c
+@@ -1695,7 +1695,7 @@ static const struct usb_device_id option
+       { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_EU3_P) },
+       { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PH8),
+               .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+-      { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX) },
++      { USB_DEVICE_INTERFACE_CLASS(CINTERION_VENDOR_ID, CINTERION_PRODUCT_AHXX, 0xff) },
+       { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_PLXX),
+               .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+       { USB_DEVICE(CINTERION_VENDOR_ID, CINTERION_PRODUCT_HC28_MDM) }, 
diff --git a/queue-3.14/usb-serial-ftdi_sio-add-support-for-yaesu-scu-18-cable.patch b/queue-3.14/usb-serial-ftdi_sio-add-support-for-yaesu-scu-18-cable.patch
new file mode 100644 (file)
index 0000000..a5c2c62
--- /dev/null
@@ -0,0 +1,43 @@
+From e03cdf22a2727c60307be6a729233edab3bfda9c Mon Sep 17 00:00:00 2001
+From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Date: Tue, 19 Jan 2016 23:43:13 -0800
+Subject: USB: serial: ftdi_sio: add support for Yaesu SCU-18 cable
+
+From: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+commit e03cdf22a2727c60307be6a729233edab3bfda9c upstream.
+
+Harald Linden reports that the ftdi_sio driver works properly for the
+Yaesu SCU-18 cable if the device ids are added to the driver.  So let's
+add them.
+
+Reported-by: Harald Linden <harald.linden@7183.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/ftdi_sio.c     |    1 +
+ drivers/usb/serial/ftdi_sio_ids.h |    1 +
+ 2 files changed, 2 insertions(+)
+
+--- a/drivers/usb/serial/ftdi_sio.c
++++ b/drivers/usb/serial/ftdi_sio.c
+@@ -837,6 +837,7 @@ static const struct usb_device_id id_tab
+       { USB_DEVICE(FTDI_VID, FTDI_TURTELIZER_PID),
+               .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+       { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_USB60F) },
++      { USB_DEVICE(RATOC_VENDOR_ID, RATOC_PRODUCT_ID_SCU18) },
+       { USB_DEVICE(FTDI_VID, FTDI_REU_TINY_PID) },
+       /* Papouch devices based on FTDI chip */
+--- a/drivers/usb/serial/ftdi_sio_ids.h
++++ b/drivers/usb/serial/ftdi_sio_ids.h
+@@ -615,6 +615,7 @@
+  */
+ #define RATOC_VENDOR_ID               0x0584
+ #define RATOC_PRODUCT_ID_USB60F       0xb020
++#define RATOC_PRODUCT_ID_SCU18        0xb03a
+ /*
+  * Infineon Technologies
diff --git a/queue-3.14/usb-serial-option-adding-support-for-telit-le922.patch b/queue-3.14/usb-serial-option-adding-support-for-telit-le922.patch
new file mode 100644 (file)
index 0000000..769d661
--- /dev/null
@@ -0,0 +1,58 @@
+From ff4e2494dc17b173468e1713fdf6237fd8578bc7 Mon Sep 17 00:00:00 2001
+From: Daniele Palmas <dnlplm@gmail.com>
+Date: Tue, 12 Jan 2016 17:22:06 +0100
+Subject: USB: serial: option: Adding support for Telit LE922
+
+From: Daniele Palmas <dnlplm@gmail.com>
+
+commit ff4e2494dc17b173468e1713fdf6237fd8578bc7 upstream.
+
+This patch adds support for two PIDs of LE922.
+
+Signed-off-by: Daniele Palmas <dnlplm@gmail.com>
+Signed-off-by: Johan Hovold <johan@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/usb/serial/option.c |   16 ++++++++++++++++
+ 1 file changed, 16 insertions(+)
+
+--- a/drivers/usb/serial/option.c
++++ b/drivers/usb/serial/option.c
+@@ -269,6 +269,8 @@ static void option_instat_callback(struc
+ #define TELIT_PRODUCT_CC864_SINGLE            0x1006
+ #define TELIT_PRODUCT_DE910_DUAL              0x1010
+ #define TELIT_PRODUCT_UE910_V2                        0x1012
++#define TELIT_PRODUCT_LE922_USBCFG0           0x1042
++#define TELIT_PRODUCT_LE922_USBCFG3           0x1043
+ #define TELIT_PRODUCT_LE920                   0x1200
+ #define TELIT_PRODUCT_LE910                   0x1201
+@@ -623,6 +625,16 @@ static const struct option_blacklist_inf
+       .reserved = BIT(1) | BIT(5),
+ };
++static const struct option_blacklist_info telit_le922_blacklist_usbcfg0 = {
++      .sendsetup = BIT(2),
++      .reserved = BIT(0) | BIT(1) | BIT(3),
++};
++
++static const struct option_blacklist_info telit_le922_blacklist_usbcfg3 = {
++      .sendsetup = BIT(0),
++      .reserved = BIT(1) | BIT(2) | BIT(3),
++};
++
+ static const struct usb_device_id option_ids[] = {
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
+       { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
+@@ -1168,6 +1180,10 @@ static const struct usb_device_id option
+       { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_SINGLE) },
+       { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_DE910_DUAL) },
+       { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UE910_V2) },
++      { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG0),
++              .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg0 },
++      { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE922_USBCFG3),
++              .driver_info = (kernel_ulong_t)&telit_le922_blacklist_usbcfg3 },
+       { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE910),
+               .driver_info = (kernel_ulong_t)&telit_le910_blacklist },
+       { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_LE920),
diff --git a/queue-3.14/usb-serial-visor-fix-crash-on-detecting-device-without-write_urbs.patch b/queue-3.14/usb-serial-visor-fix-crash-on-detecting-device-without-write_urbs.patch
new file mode 100644 (file)
index 0000000..b94579f
--- /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
+@@ -597,8 +597,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.14/usb-visor-fix-null-deref-at-probe.patch b/queue-3.14/usb-visor-fix-null-deref-at-probe.patch
new file mode 100644 (file)
index 0000000..809ed72
--- /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
+@@ -544,6 +544,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,