]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.18-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 11 Jan 2018 07:17:34 +0000 (08:17 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 11 Jan 2018 07:17:34 +0000 (08:17 +0100)
added patches:
alsa-aloop-fix-inconsistent-format-due-to-incomplete-rule.patch
alsa-aloop-fix-racy-hw-constraints-adjustment.patch
alsa-aloop-release-cable-upon-open-error-path.patch
alsa-pcm-abort-properly-at-pending-signal-in-oss-read-write-loops.patch
alsa-pcm-add-missing-error-checks-in-oss-emulation-plugin-builder.patch
alsa-pcm-allow-aborting-mutex-lock-at-oss-read-write-loops.patch
alsa-pcm-remove-incorrect-snd_bug_on-usages.patch

queue-3.18/alsa-aloop-fix-inconsistent-format-due-to-incomplete-rule.patch [new file with mode: 0644]
queue-3.18/alsa-aloop-fix-racy-hw-constraints-adjustment.patch [new file with mode: 0644]
queue-3.18/alsa-aloop-release-cable-upon-open-error-path.patch [new file with mode: 0644]
queue-3.18/alsa-pcm-abort-properly-at-pending-signal-in-oss-read-write-loops.patch [new file with mode: 0644]
queue-3.18/alsa-pcm-add-missing-error-checks-in-oss-emulation-plugin-builder.patch [new file with mode: 0644]
queue-3.18/alsa-pcm-allow-aborting-mutex-lock-at-oss-read-write-loops.patch [new file with mode: 0644]
queue-3.18/alsa-pcm-remove-incorrect-snd_bug_on-usages.patch [new file with mode: 0644]
queue-3.18/series

diff --git a/queue-3.18/alsa-aloop-fix-inconsistent-format-due-to-incomplete-rule.patch b/queue-3.18/alsa-aloop-fix-inconsistent-format-due-to-incomplete-rule.patch
new file mode 100644 (file)
index 0000000..7f64398
--- /dev/null
@@ -0,0 +1,65 @@
+From b088b53e20c7d09b5ab84c5688e609f478e5c417 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Fri, 5 Jan 2018 16:15:33 +0100
+Subject: ALSA: aloop: Fix inconsistent format due to incomplete rule
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit b088b53e20c7d09b5ab84c5688e609f478e5c417 upstream.
+
+The extra hw constraint rule for the formats the aloop driver
+introduced has a slight flaw, where it doesn't return a positive value
+when the mask got changed.  It came from the fact that it's basically
+a copy&paste from snd_hw_constraint_mask64().  The original code is
+supposed to be a single-shot and it modifies the mask bits only once
+and never after, while what we need for aloop is the dynamic hw rule
+that limits the mask bits.
+
+This difference results in the inconsistent state, as the hw_refine
+doesn't apply the dependencies fully.  The worse and surprisingly
+result is that it causes a crash in OSS emulation when multiple
+full-duplex reads/writes are performed concurrently (I leave why it
+triggers Oops to readers as a homework).
+
+For fixing this, replace a few open-codes with the standard
+snd_mask_*() macros.
+
+Reported-by: syzbot+3902b5220e8ca27889ca@syzkaller.appspotmail.com
+Fixes: b1c73fc8e697 ("ALSA: snd-aloop: Fix hw_params restrictions and checking")
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/drivers/aloop.c |   13 ++++++-------
+ 1 file changed, 6 insertions(+), 7 deletions(-)
+
+--- a/sound/drivers/aloop.c
++++ b/sound/drivers/aloop.c
+@@ -39,6 +39,7 @@
+ #include <sound/core.h>
+ #include <sound/control.h>
+ #include <sound/pcm.h>
++#include <sound/pcm_params.h>
+ #include <sound/info.h>
+ #include <sound/initval.h>
+@@ -623,14 +624,12 @@ static int rule_format(struct snd_pcm_hw
+ {
+       struct snd_pcm_hardware *hw = rule->private;
+-      struct snd_mask *maskp = hw_param_mask(params, rule->var);
++      struct snd_mask m;
+-      maskp->bits[0] &= (u_int32_t)hw->formats;
+-      maskp->bits[1] &= (u_int32_t)(hw->formats >> 32);
+-      memset(maskp->bits + 2, 0, (SNDRV_MASK_MAX-64) / 8); /* clear rest */
+-      if (! maskp->bits[0] && ! maskp->bits[1])
+-              return -EINVAL;
+-      return 0;
++      snd_mask_none(&m);
++      m.bits[0] = (u_int32_t)hw->formats;
++      m.bits[1] = (u_int32_t)(hw->formats >> 32);
++      return snd_mask_refine(hw_param_mask(params, rule->var), &m);
+ }
+ static int rule_rate(struct snd_pcm_hw_params *params,
diff --git a/queue-3.18/alsa-aloop-fix-racy-hw-constraints-adjustment.patch b/queue-3.18/alsa-aloop-fix-racy-hw-constraints-adjustment.patch
new file mode 100644 (file)
index 0000000..28f3f24
--- /dev/null
@@ -0,0 +1,149 @@
+From 898dfe4687f460ba337a01c11549f87269a13fa2 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Thu, 4 Jan 2018 17:38:54 +0100
+Subject: ALSA: aloop: Fix racy hw constraints adjustment
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit 898dfe4687f460ba337a01c11549f87269a13fa2 upstream.
+
+The aloop driver tries to update the hw constraints of the connected
+target on the cable of the opened PCM substream.  This is done by
+adding the extra hw constraints rules referring to the substream
+runtime->hw fields, while the other substream may update the runtime
+hw of another side on the fly.
+
+This is, however, racy and may result in the inconsistent values when
+both PCM streams perform the prepare concurrently.  One of the reason
+is that it overwrites the other's runtime->hw field; which is not only
+racy but also broken when it's called before the open of another side
+finishes.  And, since the reference to runtime->hw isn't protected,
+the concurrent write may give the partial value update and become
+inconsistent.
+
+This patch is an attempt to fix and clean up:
+- The prepare doesn't change the runtime->hw of other side any longer,
+  but only update the cable->hw that is referred commonly.
+- The extra rules refer to the loopback_pcm object instead of the
+  runtime->hw.  The actual hw is deduced from cable->hw.
+- The extra rules take the cable_lock to protect against the race.
+
+Fixes: b1c73fc8e697 ("ALSA: snd-aloop: Fix hw_params restrictions and checking")
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/drivers/aloop.c |   51 ++++++++++++++++++++------------------------------
+ 1 file changed, 21 insertions(+), 30 deletions(-)
+
+--- a/sound/drivers/aloop.c
++++ b/sound/drivers/aloop.c
+@@ -307,19 +307,6 @@ static int loopback_trigger(struct snd_p
+       return 0;
+ }
+-static void params_change_substream(struct loopback_pcm *dpcm,
+-                                  struct snd_pcm_runtime *runtime)
+-{
+-      struct snd_pcm_runtime *dst_runtime;
+-
+-      if (dpcm == NULL || dpcm->substream == NULL)
+-              return;
+-      dst_runtime = dpcm->substream->runtime;
+-      if (dst_runtime == NULL)
+-              return;
+-      dst_runtime->hw = dpcm->cable->hw;
+-}
+-
+ static void params_change(struct snd_pcm_substream *substream)
+ {
+       struct snd_pcm_runtime *runtime = substream->runtime;
+@@ -331,10 +318,6 @@ static void params_change(struct snd_pcm
+       cable->hw.rate_max = runtime->rate;
+       cable->hw.channels_min = runtime->channels;
+       cable->hw.channels_max = runtime->channels;
+-      params_change_substream(cable->streams[SNDRV_PCM_STREAM_PLAYBACK],
+-                              runtime);
+-      params_change_substream(cable->streams[SNDRV_PCM_STREAM_CAPTURE],
+-                              runtime);
+ }
+ static int loopback_prepare(struct snd_pcm_substream *substream)
+@@ -622,24 +605,29 @@ static unsigned int get_cable_index(stru
+ static int rule_format(struct snd_pcm_hw_params *params,
+                      struct snd_pcm_hw_rule *rule)
+ {
+-
+-      struct snd_pcm_hardware *hw = rule->private;
++      struct loopback_pcm *dpcm = rule->private;
++      struct loopback_cable *cable = dpcm->cable;
+       struct snd_mask m;
+       snd_mask_none(&m);
+-      m.bits[0] = (u_int32_t)hw->formats;
+-      m.bits[1] = (u_int32_t)(hw->formats >> 32);
++      mutex_lock(&dpcm->loopback->cable_lock);
++      m.bits[0] = (u_int32_t)cable->hw.formats;
++      m.bits[1] = (u_int32_t)(cable->hw.formats >> 32);
++      mutex_unlock(&dpcm->loopback->cable_lock);
+       return snd_mask_refine(hw_param_mask(params, rule->var), &m);
+ }
+ static int rule_rate(struct snd_pcm_hw_params *params,
+                    struct snd_pcm_hw_rule *rule)
+ {
+-      struct snd_pcm_hardware *hw = rule->private;
++      struct loopback_pcm *dpcm = rule->private;
++      struct loopback_cable *cable = dpcm->cable;
+       struct snd_interval t;
+-        t.min = hw->rate_min;
+-        t.max = hw->rate_max;
++      mutex_lock(&dpcm->loopback->cable_lock);
++      t.min = cable->hw.rate_min;
++      t.max = cable->hw.rate_max;
++      mutex_unlock(&dpcm->loopback->cable_lock);
+         t.openmin = t.openmax = 0;
+         t.integer = 0;
+       return snd_interval_refine(hw_param_interval(params, rule->var), &t);
+@@ -648,11 +636,14 @@ static int rule_rate(struct snd_pcm_hw_p
+ static int rule_channels(struct snd_pcm_hw_params *params,
+                        struct snd_pcm_hw_rule *rule)
+ {
+-      struct snd_pcm_hardware *hw = rule->private;
++      struct loopback_pcm *dpcm = rule->private;
++      struct loopback_cable *cable = dpcm->cable;
+       struct snd_interval t;
+-        t.min = hw->channels_min;
+-        t.max = hw->channels_max;
++      mutex_lock(&dpcm->loopback->cable_lock);
++      t.min = cable->hw.channels_min;
++      t.max = cable->hw.channels_max;
++      mutex_unlock(&dpcm->loopback->cable_lock);
+         t.openmin = t.openmax = 0;
+         t.integer = 0;
+       return snd_interval_refine(hw_param_interval(params, rule->var), &t);
+@@ -718,19 +709,19 @@ static int loopback_open(struct snd_pcm_
+       /* are cached -> they do not reflect the actual state */
+       err = snd_pcm_hw_rule_add(runtime, 0,
+                                 SNDRV_PCM_HW_PARAM_FORMAT,
+-                                rule_format, &runtime->hw,
++                                rule_format, dpcm,
+                                 SNDRV_PCM_HW_PARAM_FORMAT, -1);
+       if (err < 0)
+               goto unlock;
+       err = snd_pcm_hw_rule_add(runtime, 0,
+                                 SNDRV_PCM_HW_PARAM_RATE,
+-                                rule_rate, &runtime->hw,
++                                rule_rate, dpcm,
+                                 SNDRV_PCM_HW_PARAM_RATE, -1);
+       if (err < 0)
+               goto unlock;
+       err = snd_pcm_hw_rule_add(runtime, 0,
+                                 SNDRV_PCM_HW_PARAM_CHANNELS,
+-                                rule_channels, &runtime->hw,
++                                rule_channels, dpcm,
+                                 SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+       if (err < 0)
+               goto unlock;
diff --git a/queue-3.18/alsa-aloop-release-cable-upon-open-error-path.patch b/queue-3.18/alsa-aloop-release-cable-upon-open-error-path.patch
new file mode 100644 (file)
index 0000000..1bbcf45
--- /dev/null
@@ -0,0 +1,102 @@
+From 9685347aa0a5c2869058ca6ab79fd8e93084a67f Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Fri, 5 Jan 2018 16:09:47 +0100
+Subject: ALSA: aloop: Release cable upon open error path
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit 9685347aa0a5c2869058ca6ab79fd8e93084a67f upstream.
+
+The aloop runtime object and its assignment in the cable are left even
+when opening a substream fails.  This doesn't mean any memory leak,
+but it still keeps the invalid pointer that may be referred by the
+another side of the cable spontaneously, which is a potential Oops
+cause.
+
+Clean up the cable assignment and the empty cable upon the error path
+properly.
+
+Fixes: 597603d615d2 ("ALSA: introduce the snd-aloop module for the PCM loopback")
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/drivers/aloop.c |   38 +++++++++++++++++++++++++-------------
+ 1 file changed, 25 insertions(+), 13 deletions(-)
+
+--- a/sound/drivers/aloop.c
++++ b/sound/drivers/aloop.c
+@@ -659,12 +659,31 @@ static int rule_channels(struct snd_pcm_
+       return snd_interval_refine(hw_param_interval(params, rule->var), &t);
+ }
++static void free_cable(struct snd_pcm_substream *substream)
++{
++      struct loopback *loopback = substream->private_data;
++      int dev = get_cable_index(substream);
++      struct loopback_cable *cable;
++
++      cable = loopback->cables[substream->number][dev];
++      if (!cable)
++              return;
++      if (cable->streams[!substream->stream]) {
++              /* other stream is still alive */
++              cable->streams[substream->stream] = NULL;
++      } else {
++              /* free the cable */
++              loopback->cables[substream->number][dev] = NULL;
++              kfree(cable);
++      }
++}
++
+ static int loopback_open(struct snd_pcm_substream *substream)
+ {
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct loopback *loopback = substream->private_data;
+       struct loopback_pcm *dpcm;
+-      struct loopback_cable *cable;
++      struct loopback_cable *cable = NULL;
+       int err = 0;
+       int dev = get_cable_index(substream);
+@@ -683,7 +702,6 @@ static int loopback_open(struct snd_pcm_
+       if (!cable) {
+               cable = kzalloc(sizeof(*cable), GFP_KERNEL);
+               if (!cable) {
+-                      kfree(dpcm);
+                       err = -ENOMEM;
+                       goto unlock;
+               }
+@@ -725,6 +743,10 @@ static int loopback_open(struct snd_pcm_
+       else
+               runtime->hw = cable->hw;
+  unlock:
++      if (err < 0) {
++              free_cable(substream);
++              kfree(dpcm);
++      }
+       mutex_unlock(&loopback->cable_lock);
+       return err;
+ }
+@@ -733,20 +755,10 @@ static int loopback_close(struct snd_pcm
+ {
+       struct loopback *loopback = substream->private_data;
+       struct loopback_pcm *dpcm = substream->runtime->private_data;
+-      struct loopback_cable *cable;
+-      int dev = get_cable_index(substream);
+       loopback_timer_stop(dpcm);
+       mutex_lock(&loopback->cable_lock);
+-      cable = loopback->cables[substream->number][dev];
+-      if (cable->streams[!substream->stream]) {
+-              /* other stream is still alive */
+-              cable->streams[substream->stream] = NULL;
+-      } else {
+-              /* free the cable */
+-              loopback->cables[substream->number][dev] = NULL;
+-              kfree(cable);
+-      }
++      free_cable(substream);
+       mutex_unlock(&loopback->cable_lock);
+       return 0;
+ }
diff --git a/queue-3.18/alsa-pcm-abort-properly-at-pending-signal-in-oss-read-write-loops.patch b/queue-3.18/alsa-pcm-abort-properly-at-pending-signal-in-oss-read-write-loops.patch
new file mode 100644 (file)
index 0000000..859168d
--- /dev/null
@@ -0,0 +1,50 @@
+From 29159a4ed7044c52e3e2cf1a9fb55cec4745c60b Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Mon, 8 Jan 2018 13:58:31 +0100
+Subject: ALSA: pcm: Abort properly at pending signal in OSS read/write loops
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit 29159a4ed7044c52e3e2cf1a9fb55cec4745c60b upstream.
+
+The loops for read and write in PCM OSS emulation have no proper check
+of pending signals, and they keep processing even after user tries to
+break.  This results in a very long delay, often seen as RCU stall
+when a huge unprocessed bytes remain queued.  The bug could be easily
+triggered by syzkaller.
+
+As a simple workaround, this patch adds the proper check of pending
+signals and aborts the loop appropriately.
+
+Reported-by: syzbot+993cb4cfcbbff3947c21@syzkaller.appspotmail.com
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/core/oss/pcm_oss.c |    8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/sound/core/oss/pcm_oss.c
++++ b/sound/core/oss/pcm_oss.c
+@@ -1417,6 +1417,10 @@ static ssize_t snd_pcm_oss_write1(struct
+                           tmp != runtime->oss.period_bytes)
+                               break;
+               }
++              if (signal_pending(current)) {
++                      tmp = -ERESTARTSYS;
++                      goto err;
++              }
+       }
+       mutex_unlock(&runtime->oss.params_lock);
+       return xfer;
+@@ -1502,6 +1506,10 @@ static ssize_t snd_pcm_oss_read1(struct
+                       bytes -= tmp;
+                       xfer += tmp;
+               }
++              if (signal_pending(current)) {
++                      tmp = -ERESTARTSYS;
++                      goto err;
++              }
+       }
+       mutex_unlock(&runtime->oss.params_lock);
+       return xfer;
diff --git a/queue-3.18/alsa-pcm-add-missing-error-checks-in-oss-emulation-plugin-builder.patch b/queue-3.18/alsa-pcm-add-missing-error-checks-in-oss-emulation-plugin-builder.patch
new file mode 100644 (file)
index 0000000..7b4a055
--- /dev/null
@@ -0,0 +1,54 @@
+From 6708913750344a900f2e73bfe4a4d6dbbce4fe8d Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Thu, 4 Jan 2018 16:39:27 +0100
+Subject: ALSA: pcm: Add missing error checks in OSS emulation plugin builder
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit 6708913750344a900f2e73bfe4a4d6dbbce4fe8d upstream.
+
+In the OSS emulation plugin builder where the frame size is parsed in
+the plugin chain, some places miss the possible errors returned from
+the plugin src_ or dst_frames callback.
+
+This patch papers over such places.
+
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/core/oss/pcm_plugin.c |   14 +++++++++++---
+ 1 file changed, 11 insertions(+), 3 deletions(-)
+
+--- a/sound/core/oss/pcm_plugin.c
++++ b/sound/core/oss/pcm_plugin.c
+@@ -591,18 +591,26 @@ snd_pcm_sframes_t snd_pcm_plug_write_tra
+       snd_pcm_sframes_t frames = size;
+       plugin = snd_pcm_plug_first(plug);
+-      while (plugin && frames > 0) {
++      while (plugin) {
++              if (frames <= 0)
++                      return frames;
+               if ((next = plugin->next) != NULL) {
+                       snd_pcm_sframes_t frames1 = frames;
+-                      if (plugin->dst_frames)
++                      if (plugin->dst_frames) {
+                               frames1 = plugin->dst_frames(plugin, frames);
++                              if (frames1 <= 0)
++                                      return frames1;
++                      }
+                       if ((err = next->client_channels(next, frames1, &dst_channels)) < 0) {
+                               return err;
+                       }
+                       if (err != frames1) {
+                               frames = err;
+-                              if (plugin->src_frames)
++                              if (plugin->src_frames) {
+                                       frames = plugin->src_frames(plugin, frames1);
++                                      if (frames <= 0)
++                                              return frames;
++                              }
+                       }
+               } else
+                       dst_channels = NULL;
diff --git a/queue-3.18/alsa-pcm-allow-aborting-mutex-lock-at-oss-read-write-loops.patch b/queue-3.18/alsa-pcm-allow-aborting-mutex-lock-at-oss-read-write-loops.patch
new file mode 100644 (file)
index 0000000..a93be0f
--- /dev/null
@@ -0,0 +1,103 @@
+From 900498a34a3ac9c611e9b425094c8106bdd7dc1c Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Mon, 8 Jan 2018 14:03:53 +0100
+Subject: ALSA: pcm: Allow aborting mutex lock at OSS read/write loops
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit 900498a34a3ac9c611e9b425094c8106bdd7dc1c upstream.
+
+PCM OSS read/write loops keep taking the mutex lock for the whole
+read/write, and this might take very long when the exceptionally high
+amount of data is given.  Also, since it invokes with mutex_lock(),
+the concurrent read/write becomes unbreakable.
+
+This patch tries to address these issues by replacing mutex_lock()
+with mutex_lock_interruptible(), and also splits / re-takes the lock
+at each read/write period chunk, so that it can switch the context
+more finely if requested.
+
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/core/oss/pcm_oss.c |   36 +++++++++++++++++++++---------------
+ 1 file changed, 21 insertions(+), 15 deletions(-)
+
+--- a/sound/core/oss/pcm_oss.c
++++ b/sound/core/oss/pcm_oss.c
+@@ -1370,8 +1370,11 @@ static ssize_t snd_pcm_oss_write1(struct
+       if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
+               return tmp;
+-      mutex_lock(&runtime->oss.params_lock);
+       while (bytes > 0) {
++              if (mutex_lock_interruptible(&runtime->oss.params_lock)) {
++                      tmp = -ERESTARTSYS;
++                      break;
++              }
+               if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) {
+                       tmp = bytes;
+                       if (tmp + runtime->oss.buffer_used > runtime->oss.period_bytes)
+@@ -1415,18 +1418,18 @@ static ssize_t snd_pcm_oss_write1(struct
+                       xfer += tmp;
+                       if ((substream->f_flags & O_NONBLOCK) != 0 &&
+                           tmp != runtime->oss.period_bytes)
+-                              break;
++                              tmp = -EAGAIN;
+               }
++ err:
++              mutex_unlock(&runtime->oss.params_lock);
++              if (tmp < 0)
++                      break;
+               if (signal_pending(current)) {
+                       tmp = -ERESTARTSYS;
+-                      goto err;
++                      break;
+               }
++              tmp = 0;
+       }
+-      mutex_unlock(&runtime->oss.params_lock);
+-      return xfer;
+-
+- err:
+-      mutex_unlock(&runtime->oss.params_lock);
+       return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
+ }
+@@ -1474,8 +1477,11 @@ static ssize_t snd_pcm_oss_read1(struct
+       if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
+               return tmp;
+-      mutex_lock(&runtime->oss.params_lock);
+       while (bytes > 0) {
++              if (mutex_lock_interruptible(&runtime->oss.params_lock)) {
++                      tmp = -ERESTARTSYS;
++                      break;
++              }
+               if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) {
+                       if (runtime->oss.buffer_used == 0) {
+                               tmp = snd_pcm_oss_read2(substream, runtime->oss.buffer, runtime->oss.period_bytes, 1);
+@@ -1506,16 +1512,16 @@ static ssize_t snd_pcm_oss_read1(struct
+                       bytes -= tmp;
+                       xfer += tmp;
+               }
++ err:
++              mutex_unlock(&runtime->oss.params_lock);
++              if (tmp < 0)
++                      break;
+               if (signal_pending(current)) {
+                       tmp = -ERESTARTSYS;
+-                      goto err;
++                      break;
+               }
++              tmp = 0;
+       }
+-      mutex_unlock(&runtime->oss.params_lock);
+-      return xfer;
+-
+- err:
+-      mutex_unlock(&runtime->oss.params_lock);
+       return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
+ }
diff --git a/queue-3.18/alsa-pcm-remove-incorrect-snd_bug_on-usages.patch b/queue-3.18/alsa-pcm-remove-incorrect-snd_bug_on-usages.patch
new file mode 100644 (file)
index 0000000..d9a7cd2
--- /dev/null
@@ -0,0 +1,77 @@
+From fe08f34d066f4404934a509b6806db1a4f700c86 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Mon, 1 Jan 2018 09:50:50 +0100
+Subject: ALSA: pcm: Remove incorrect snd_BUG_ON() usages
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit fe08f34d066f4404934a509b6806db1a4f700c86 upstream.
+
+syzkaller triggered kernel warnings through PCM OSS emulation at
+closing a stream:
+  WARNING: CPU: 0 PID: 3502 at sound/core/pcm_lib.c:1635
+  snd_pcm_hw_param_first+0x289/0x690 sound/core/pcm_lib.c:1635
+  Call Trace:
+  ....
+   snd_pcm_hw_param_near.constprop.27+0x78d/0x9a0 sound/core/oss/pcm_oss.c:457
+   snd_pcm_oss_change_params+0x17d3/0x3720 sound/core/oss/pcm_oss.c:969
+   snd_pcm_oss_make_ready+0xaa/0x130 sound/core/oss/pcm_oss.c:1128
+   snd_pcm_oss_sync+0x257/0x830 sound/core/oss/pcm_oss.c:1638
+   snd_pcm_oss_release+0x20b/0x280 sound/core/oss/pcm_oss.c:2431
+   __fput+0x327/0x7e0 fs/file_table.c:210
+   ....
+
+This happens while it tries to open and set up the aloop device
+concurrently.  The warning above (invoked from snd_BUG_ON() macro) is
+to detect the unexpected logical error where snd_pcm_hw_refine() call
+shouldn't fail.  The theory is true for the case where the hw_params
+config rules are static.  But for an aloop device, the hw_params rule
+condition does vary dynamically depending on the connected target;
+when another device is opened and changes the parameters, the device
+connected in another side is also affected, and it caused the error
+from snd_pcm_hw_refine().
+
+That is, the simplest "solution" for this is to remove the incorrect
+assumption of static rules, and treat such an error as a normal error
+path.  As there are a couple of other places using snd_BUG_ON()
+incorrectly, this patch removes these spurious snd_BUG_ON() calls.
+
+Reported-by: syzbot+6f11c7e2a1b91d466432@syzkaller.appspotmail.com
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/core/oss/pcm_oss.c |    1 -
+ sound/core/pcm_lib.c     |    4 ++--
+ 2 files changed, 2 insertions(+), 3 deletions(-)
+
+--- a/sound/core/oss/pcm_oss.c
++++ b/sound/core/oss/pcm_oss.c
+@@ -465,7 +465,6 @@ static int snd_pcm_hw_param_near(struct
+               v = snd_pcm_hw_param_last(pcm, params, var, dir);
+       else
+               v = snd_pcm_hw_param_first(pcm, params, var, dir);
+-      snd_BUG_ON(v < 0);
+       return v;
+ }
+--- a/sound/core/pcm_lib.c
++++ b/sound/core/pcm_lib.c
+@@ -1633,7 +1633,7 @@ int snd_pcm_hw_param_first(struct snd_pc
+               return changed;
+       if (params->rmask) {
+               int err = snd_pcm_hw_refine(pcm, params);
+-              if (snd_BUG_ON(err < 0))
++              if (err < 0)
+                       return err;
+       }
+       return snd_pcm_hw_param_value(params, var, dir);
+@@ -1680,7 +1680,7 @@ int snd_pcm_hw_param_last(struct snd_pcm
+               return changed;
+       if (params->rmask) {
+               int err = snd_pcm_hw_refine(pcm, params);
+-              if (snd_BUG_ON(err < 0))
++              if (err < 0)
+                       return err;
+       }
+       return snd_pcm_hw_param_value(params, var, dir);
index 12f35e852aaff666f6ccc9095b65684a7ec9a4d2..8f64278a581a2ea094222ccaf2097a967c626b15 100644 (file)
@@ -12,3 +12,10 @@ mips-also-verify-sizeof-elf_fpreg_t-with-ptrace_setregset.patch
 perf-core-fix-concurrent-sys_perf_event_open-vs.-move_group-race.patch
 kvm-vmx-scrub-hardware-gprs-at-vm-exit.patch
 x86-acpi-handle-sci-interrupts-above-legacy-space-gracefully.patch
+alsa-pcm-remove-incorrect-snd_bug_on-usages.patch
+alsa-pcm-add-missing-error-checks-in-oss-emulation-plugin-builder.patch
+alsa-pcm-abort-properly-at-pending-signal-in-oss-read-write-loops.patch
+alsa-pcm-allow-aborting-mutex-lock-at-oss-read-write-loops.patch
+alsa-aloop-release-cable-upon-open-error-path.patch
+alsa-aloop-fix-inconsistent-format-due-to-incomplete-rule.patch
+alsa-aloop-fix-racy-hw-constraints-adjustment.patch