--- /dev/null
+From 02a5d6925cd34c3b774bdb8eefb057c40a30e870 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Thu, 22 Mar 2018 18:10:14 +0100
+Subject: ALSA: pcm: Avoid potential races between OSS ioctls and read/write
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit 02a5d6925cd34c3b774bdb8eefb057c40a30e870 upstream.
+
+Although we apply the params_lock mutex to the whole read and write
+operations as well as snd_pcm_oss_change_params(), we may still face
+some races.
+
+First off, the params_lock is taken inside the read and write loop.
+This is intentional for avoiding the too long locking, but it allows
+the in-between parameter change, which might lead to invalid
+pointers. We check the readiness of the stream and set up via
+snd_pcm_oss_make_ready() at the beginning of read and write, but it's
+called only once, by assuming that it remains ready in the rest.
+
+Second, many ioctls that may change the actual parameters
+(i.e. setting runtime->oss.params=1) aren't protected, hence they can
+be processed in a half-baked state.
+
+This patch is an attempt to plug these holes. The stream readiness
+check is moved inside the read/write inner loop, so that the stream is
+always set up in a proper state before further processing. Also, each
+ioctl that may change the parameter is wrapped with the params_lock
+for avoiding the races.
+
+The issues were triggered by syzkaller in a few different scenarios,
+particularly the one below appearing as GPF in loopback_pos_update.
+
+Reported-by: syzbot+c4227aec125487ec3efa@syzkaller.appspotmail.com
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/core/oss/pcm_oss.c | 134 +++++++++++++++++++++++++++++++++++++----------
+ 1 file changed, 106 insertions(+), 28 deletions(-)
+
+--- a/sound/core/oss/pcm_oss.c
++++ b/sound/core/oss/pcm_oss.c
+@@ -834,8 +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,
+- bool trylock)
++/* call with params_lock held */
++static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream)
+ {
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_pcm_hw_params *params, *sparams;
+@@ -849,11 +849,8 @@ static int snd_pcm_oss_change_params(str
+ struct snd_mask sformat_mask;
+ struct snd_mask mask;
+
+- if (trylock) {
+- if (!(mutex_trylock(&runtime->oss.params_lock)))
+- return -EAGAIN;
+- } else if (mutex_lock_interruptible(&runtime->oss.params_lock))
+- return -ERESTARTSYS;
++ if (!runtime->oss.params)
++ return 0;
+ sw_params = kzalloc(sizeof(*sw_params), GFP_KERNEL);
+ params = kmalloc(sizeof(*params), GFP_KERNEL);
+ sparams = kmalloc(sizeof(*sparams), GFP_KERNEL);
+@@ -1079,6 +1076,23 @@ failure:
+ kfree(sw_params);
+ kfree(params);
+ kfree(sparams);
++ return err;
++}
++
++/* this one takes the lock by itself */
++static int snd_pcm_oss_change_params(struct snd_pcm_substream *substream,
++ bool trylock)
++{
++ struct snd_pcm_runtime *runtime = substream->runtime;
++ int err;
++
++ if (trylock) {
++ if (!(mutex_trylock(&runtime->oss.params_lock)))
++ return -EAGAIN;
++ } else if (mutex_lock_interruptible(&runtime->oss.params_lock))
++ return -ERESTARTSYS;
++
++ err = snd_pcm_oss_change_params_locked(substream);
+ mutex_unlock(&runtime->oss.params_lock);
+ return err;
+ }
+@@ -1107,11 +1121,14 @@ static int snd_pcm_oss_get_active_substr
+ return 0;
+ }
+
++/* call with params_lock held */
+ static int snd_pcm_oss_prepare(struct snd_pcm_substream *substream)
+ {
+ int err;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
++ if (!runtime->oss.prepare)
++ return 0;
+ err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL);
+ if (err < 0) {
+ pcm_dbg(substream->pcm,
+@@ -1131,8 +1148,6 @@ static int snd_pcm_oss_make_ready(struct
+ struct snd_pcm_runtime *runtime;
+ int err;
+
+- if (substream == NULL)
+- return 0;
+ runtime = substream->runtime;
+ if (runtime->oss.params) {
+ err = snd_pcm_oss_change_params(substream, false);
+@@ -1140,6 +1155,29 @@ static int snd_pcm_oss_make_ready(struct
+ return err;
+ }
+ if (runtime->oss.prepare) {
++ if (mutex_lock_interruptible(&runtime->oss.params_lock))
++ return -ERESTARTSYS;
++ err = snd_pcm_oss_prepare(substream);
++ mutex_unlock(&runtime->oss.params_lock);
++ if (err < 0)
++ return err;
++ }
++ return 0;
++}
++
++/* call with params_lock held */
++static int snd_pcm_oss_make_ready_locked(struct snd_pcm_substream *substream)
++{
++ struct snd_pcm_runtime *runtime;
++ int err;
++
++ runtime = substream->runtime;
++ if (runtime->oss.params) {
++ err = snd_pcm_oss_change_params_locked(substream);
++ if (err < 0)
++ return err;
++ }
++ if (runtime->oss.prepare) {
+ err = snd_pcm_oss_prepare(substream);
+ if (err < 0)
+ return err;
+@@ -1367,13 +1405,14 @@ static ssize_t snd_pcm_oss_write1(struct
+ if (atomic_read(&substream->mmap_count))
+ return -ENXIO;
+
+- if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
+- return tmp;
+ while (bytes > 0) {
+ if (mutex_lock_interruptible(&runtime->oss.params_lock)) {
+ tmp = -ERESTARTSYS;
+ break;
+ }
++ tmp = snd_pcm_oss_make_ready_locked(substream);
++ if (tmp < 0)
++ goto err;
+ if (bytes < runtime->oss.period_bytes || runtime->oss.buffer_used > 0) {
+ tmp = bytes;
+ if (tmp + runtime->oss.buffer_used > runtime->oss.period_bytes)
+@@ -1474,13 +1513,14 @@ static ssize_t snd_pcm_oss_read1(struct
+ if (atomic_read(&substream->mmap_count))
+ return -ENXIO;
+
+- if ((tmp = snd_pcm_oss_make_ready(substream)) < 0)
+- return tmp;
+ while (bytes > 0) {
+ if (mutex_lock_interruptible(&runtime->oss.params_lock)) {
+ tmp = -ERESTARTSYS;
+ break;
+ }
++ tmp = snd_pcm_oss_make_ready_locked(substream);
++ if (tmp < 0)
++ goto err;
+ 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);
+@@ -1536,10 +1576,12 @@ static int snd_pcm_oss_reset(struct snd_
+ continue;
+ runtime = substream->runtime;
+ snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
++ mutex_lock(&runtime->oss.params_lock);
+ runtime->oss.prepare = 1;
+ runtime->oss.buffer_used = 0;
+ runtime->oss.prev_hw_ptr_period = 0;
+ runtime->oss.period_ptr = 0;
++ mutex_unlock(&runtime->oss.params_lock);
+ }
+ return 0;
+ }
+@@ -1625,9 +1667,10 @@ static int snd_pcm_oss_sync(struct snd_p
+ goto __direct;
+ if ((err = snd_pcm_oss_make_ready(substream)) < 0)
+ return err;
++ if (mutex_lock_interruptible(&runtime->oss.params_lock))
++ return -ERESTARTSYS;
+ format = snd_pcm_oss_format_from(runtime->oss.format);
+ width = snd_pcm_format_physical_width(format);
+- mutex_lock(&runtime->oss.params_lock);
+ if (runtime->oss.buffer_used > 0) {
+ #ifdef OSS_DEBUG
+ pcm_dbg(substream->pcm, "sync: buffer_used\n");
+@@ -1695,7 +1738,9 @@ static int snd_pcm_oss_sync(struct snd_p
+ substream->f_flags = saved_f_flags;
+ if (err < 0)
+ return err;
++ mutex_lock(&runtime->oss.params_lock);
+ runtime->oss.prepare = 1;
++ mutex_unlock(&runtime->oss.params_lock);
+ }
+
+ substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
+@@ -1706,8 +1751,10 @@ static int snd_pcm_oss_sync(struct snd_p
+ err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
+ if (err < 0)
+ return err;
++ mutex_lock(&runtime->oss.params_lock);
+ runtime->oss.buffer_used = 0;
+ runtime->oss.prepare = 1;
++ mutex_unlock(&runtime->oss.params_lock);
+ }
+ return 0;
+ }
+@@ -1726,10 +1773,13 @@ static int snd_pcm_oss_set_rate(struct s
+ rate = 1000;
+ else if (rate > 192000)
+ rate = 192000;
++ if (mutex_lock_interruptible(&runtime->oss.params_lock))
++ return -ERESTARTSYS;
+ if (runtime->oss.rate != rate) {
+ runtime->oss.params = 1;
+ runtime->oss.rate = rate;
+ }
++ mutex_unlock(&runtime->oss.params_lock);
+ }
+ return snd_pcm_oss_get_rate(pcm_oss_file);
+ }
+@@ -1757,10 +1807,13 @@ static int snd_pcm_oss_set_channels(stru
+ if (substream == NULL)
+ continue;
+ runtime = substream->runtime;
++ if (mutex_lock_interruptible(&runtime->oss.params_lock))
++ return -ERESTARTSYS;
+ if (runtime->oss.channels != channels) {
+ runtime->oss.params = 1;
+ runtime->oss.channels = channels;
+ }
++ mutex_unlock(&runtime->oss.params_lock);
+ }
+ return snd_pcm_oss_get_channels(pcm_oss_file);
+ }
+@@ -1846,10 +1899,13 @@ static int snd_pcm_oss_set_format(struct
+ if (substream == NULL)
+ continue;
+ runtime = substream->runtime;
++ if (mutex_lock_interruptible(&runtime->oss.params_lock))
++ return -ERESTARTSYS;
+ if (runtime->oss.format != format) {
+ runtime->oss.params = 1;
+ runtime->oss.format = format;
+ }
++ mutex_unlock(&runtime->oss.params_lock);
+ }
+ }
+ return snd_pcm_oss_get_format(pcm_oss_file);
+@@ -1869,8 +1925,6 @@ static int snd_pcm_oss_set_subdivide1(st
+ {
+ struct snd_pcm_runtime *runtime;
+
+- if (substream == NULL)
+- return 0;
+ runtime = substream->runtime;
+ if (subdivide == 0) {
+ subdivide = runtime->oss.subdivision;
+@@ -1894,9 +1948,16 @@ static int snd_pcm_oss_set_subdivide(str
+
+ for (idx = 1; idx >= 0; --idx) {
+ struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
++ struct snd_pcm_runtime *runtime;
++
+ if (substream == NULL)
+ continue;
+- if ((err = snd_pcm_oss_set_subdivide1(substream, subdivide)) < 0)
++ runtime = substream->runtime;
++ if (mutex_lock_interruptible(&runtime->oss.params_lock))
++ return -ERESTARTSYS;
++ err = snd_pcm_oss_set_subdivide1(substream, subdivide);
++ mutex_unlock(&runtime->oss.params_lock);
++ if (err < 0)
+ return err;
+ }
+ return err;
+@@ -1906,8 +1967,6 @@ static int snd_pcm_oss_set_fragment1(str
+ {
+ struct snd_pcm_runtime *runtime;
+
+- if (substream == NULL)
+- return 0;
+ runtime = substream->runtime;
+ if (runtime->oss.subdivision || runtime->oss.fragshift)
+ return -EINVAL;
+@@ -1927,9 +1986,16 @@ static int snd_pcm_oss_set_fragment(stru
+
+ for (idx = 1; idx >= 0; --idx) {
+ struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
++ struct snd_pcm_runtime *runtime;
++
+ if (substream == NULL)
+ continue;
+- if ((err = snd_pcm_oss_set_fragment1(substream, val)) < 0)
++ runtime = substream->runtime;
++ if (mutex_lock_interruptible(&runtime->oss.params_lock))
++ return -ERESTARTSYS;
++ err = snd_pcm_oss_set_fragment1(substream, val);
++ mutex_unlock(&runtime->oss.params_lock);
++ if (err < 0)
+ return err;
+ }
+ return err;
+@@ -2013,6 +2079,9 @@ static int snd_pcm_oss_set_trigger(struc
+ }
+ if (psubstream) {
+ runtime = psubstream->runtime;
++ cmd = 0;
++ if (mutex_lock_interruptible(&runtime->oss.params_lock))
++ return -ERESTARTSYS;
+ if (trigger & PCM_ENABLE_OUTPUT) {
+ if (runtime->oss.trigger)
+ goto _skip1;
+@@ -2030,13 +2099,19 @@ static int snd_pcm_oss_set_trigger(struc
+ cmd = SNDRV_PCM_IOCTL_DROP;
+ runtime->oss.prepare = 1;
+ }
+- err = snd_pcm_kernel_ioctl(psubstream, cmd, NULL);
+- if (err < 0)
+- return err;
+- }
+ _skip1:
++ mutex_unlock(&runtime->oss.params_lock);
++ if (cmd) {
++ err = snd_pcm_kernel_ioctl(psubstream, cmd, NULL);
++ if (err < 0)
++ return err;
++ }
++ }
+ if (csubstream) {
+ runtime = csubstream->runtime;
++ cmd = 0;
++ if (mutex_lock_interruptible(&runtime->oss.params_lock))
++ return -ERESTARTSYS;
+ if (trigger & PCM_ENABLE_INPUT) {
+ if (runtime->oss.trigger)
+ goto _skip2;
+@@ -2051,11 +2126,14 @@ static int snd_pcm_oss_set_trigger(struc
+ cmd = SNDRV_PCM_IOCTL_DROP;
+ runtime->oss.prepare = 1;
+ }
+- err = snd_pcm_kernel_ioctl(csubstream, cmd, NULL);
+- if (err < 0)
+- return err;
+- }
+ _skip2:
++ mutex_unlock(&runtime->oss.params_lock);
++ if (cmd) {
++ err = snd_pcm_kernel_ioctl(csubstream, cmd, NULL);
++ if (err < 0)
++ return err;
++ }
++ }
+ return 0;
+ }
+
--- /dev/null
+From e15dc99dbb9cf99f6432e8e3c0b3a8f7a3403a86 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Sat, 7 Apr 2018 11:48:58 +0200
+Subject: ALSA: pcm: Fix endless loop for XRUN recovery in OSS emulation
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit e15dc99dbb9cf99f6432e8e3c0b3a8f7a3403a86 upstream.
+
+The commit 02a5d6925cd3 ("ALSA: pcm: Avoid potential races between OSS
+ioctls and read/write") split the PCM preparation code to a locked
+version, and it added a sanity check of runtime->oss.prepare flag
+along with the change. This leaded to an endless loop when the stream
+gets XRUN: namely, snd_pcm_oss_write3() and co call
+snd_pcm_oss_prepare() without setting runtime->oss.prepare flag and
+the loop continues until the PCM state reaches to another one.
+
+As the function is supposed to execute the preparation
+unconditionally, drop the invalid state check there.
+
+The bug was triggered by syzkaller.
+
+Fixes: 02a5d6925cd3 ("ALSA: pcm: Avoid potential races between OSS ioctls and read/write")
+Reported-by: syzbot+150189c103427d31a053@syzkaller.appspotmail.com
+Reported-by: syzbot+7e3f31a52646f939c052@syzkaller.appspotmail.com
+Reported-by: syzbot+4f2016cf5185da7759dc@syzkaller.appspotmail.com
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/core/oss/pcm_oss.c | 5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/sound/core/oss/pcm_oss.c
++++ b/sound/core/oss/pcm_oss.c
+@@ -1139,13 +1139,14 @@ static int snd_pcm_oss_get_active_substr
+ }
+
+ /* call with params_lock held */
++/* NOTE: this always call PREPARE unconditionally no matter whether
++ * runtime->oss.prepare is set or not
++ */
+ static int snd_pcm_oss_prepare(struct snd_pcm_substream *substream)
+ {
+ int err;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+- if (!runtime->oss.prepare)
+- return 0;
+ err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL);
+ if (err < 0) {
+ pcm_dbg(substream->pcm,
--- /dev/null
+From f6d297df4dd47ef949540e4a201230d0c5308325 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Tue, 27 Mar 2018 14:32:23 +0200
+Subject: ALSA: pcm: Fix mutex unbalance in OSS emulation ioctls
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit f6d297df4dd47ef949540e4a201230d0c5308325 upstream.
+
+The previous fix 40cab6e88cb0 ("ALSA: pcm: Return -EBUSY for OSS
+ioctls changing busy streams") introduced some mutex unbalance; the
+check of runtime->oss.rw_ref was inserted in a wrong place after the
+mutex lock.
+
+This patch fixes the inconsistency by rewriting with the helper
+functions to lock/unlock parameters with the stream check.
+
+Fixes: 40cab6e88cb0 ("ALSA: pcm: Return -EBUSY for OSS ioctls changing busy streams")
+Reported-by: Dan Carpenter <dan.carpenter@oracle.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/core/oss/pcm_oss.c | 67 +++++++++++++++++++++++++++++------------------
+ 1 file changed, 42 insertions(+), 25 deletions(-)
+
+--- a/sound/core/oss/pcm_oss.c
++++ b/sound/core/oss/pcm_oss.c
+@@ -834,6 +834,23 @@ static int choose_rate(struct snd_pcm_su
+ return snd_pcm_hw_param_near(substream, params, SNDRV_PCM_HW_PARAM_RATE, best_rate, NULL);
+ }
+
++/* parameter locking: returns immediately if tried during streaming */
++static int lock_params(struct snd_pcm_runtime *runtime)
++{
++ if (mutex_lock_interruptible(&runtime->oss.params_lock))
++ return -ERESTARTSYS;
++ if (atomic_read(&runtime->oss.rw_ref)) {
++ mutex_unlock(&runtime->oss.params_lock);
++ return -EBUSY;
++ }
++ return 0;
++}
++
++static void unlock_params(struct snd_pcm_runtime *runtime)
++{
++ mutex_unlock(&runtime->oss.params_lock);
++}
++
+ /* call with params_lock held */
+ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream)
+ {
+@@ -1773,6 +1790,8 @@ static int snd_pcm_oss_set_rate(struct s
+ for (idx = 1; idx >= 0; --idx) {
+ struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
+ struct snd_pcm_runtime *runtime;
++ int err;
++
+ if (substream == NULL)
+ continue;
+ runtime = substream->runtime;
+@@ -1780,15 +1799,14 @@ static int snd_pcm_oss_set_rate(struct s
+ rate = 1000;
+ else if (rate > 192000)
+ rate = 192000;
+- if (mutex_lock_interruptible(&runtime->oss.params_lock))
+- return -ERESTARTSYS;
+- if (atomic_read(&runtime->oss.rw_ref))
+- return -EBUSY;
++ err = lock_params(runtime);
++ if (err < 0)
++ return err;
+ if (runtime->oss.rate != rate) {
+ runtime->oss.params = 1;
+ runtime->oss.rate = rate;
+ }
+- mutex_unlock(&runtime->oss.params_lock);
++ unlock_params(runtime);
+ }
+ return snd_pcm_oss_get_rate(pcm_oss_file);
+ }
+@@ -1813,18 +1831,19 @@ static int snd_pcm_oss_set_channels(stru
+ for (idx = 1; idx >= 0; --idx) {
+ struct snd_pcm_substream *substream = pcm_oss_file->streams[idx];
+ struct snd_pcm_runtime *runtime;
++ int err;
++
+ if (substream == NULL)
+ continue;
+ runtime = substream->runtime;
+- if (mutex_lock_interruptible(&runtime->oss.params_lock))
+- return -ERESTARTSYS;
+- if (atomic_read(&runtime->oss.rw_ref))
+- return -EBUSY;
++ err = lock_params(runtime);
++ if (err < 0)
++ return err;
+ if (runtime->oss.channels != channels) {
+ runtime->oss.params = 1;
+ runtime->oss.channels = channels;
+ }
+- mutex_unlock(&runtime->oss.params_lock);
++ unlock_params(runtime);
+ }
+ return snd_pcm_oss_get_channels(pcm_oss_file);
+ }
+@@ -1897,6 +1916,7 @@ static int snd_pcm_oss_get_formats(struc
+ static int snd_pcm_oss_set_format(struct snd_pcm_oss_file *pcm_oss_file, int format)
+ {
+ int formats, idx;
++ int err;
+
+ if (format != AFMT_QUERY) {
+ formats = snd_pcm_oss_get_formats(pcm_oss_file);
+@@ -1910,15 +1930,14 @@ static int snd_pcm_oss_set_format(struct
+ if (substream == NULL)
+ continue;
+ runtime = substream->runtime;
+- if (atomic_read(&runtime->oss.rw_ref))
+- return -EBUSY;
+- if (mutex_lock_interruptible(&runtime->oss.params_lock))
+- return -ERESTARTSYS;
++ err = lock_params(runtime);
++ if (err < 0)
++ return err;
+ if (runtime->oss.format != format) {
+ runtime->oss.params = 1;
+ runtime->oss.format = format;
+ }
+- mutex_unlock(&runtime->oss.params_lock);
++ unlock_params(runtime);
+ }
+ }
+ return snd_pcm_oss_get_format(pcm_oss_file);
+@@ -1966,12 +1985,11 @@ static int snd_pcm_oss_set_subdivide(str
+ if (substream == NULL)
+ continue;
+ runtime = substream->runtime;
+- if (atomic_read(&runtime->oss.rw_ref))
+- return -EBUSY;
+- if (mutex_lock_interruptible(&runtime->oss.params_lock))
+- return -ERESTARTSYS;
++ err = lock_params(runtime);
++ if (err < 0)
++ return err;
+ err = snd_pcm_oss_set_subdivide1(substream, subdivide);
+- mutex_unlock(&runtime->oss.params_lock);
++ unlock_params(runtime);
+ if (err < 0)
+ return err;
+ }
+@@ -2006,12 +2024,11 @@ static int snd_pcm_oss_set_fragment(stru
+ if (substream == NULL)
+ continue;
+ runtime = substream->runtime;
+- if (atomic_read(&runtime->oss.rw_ref))
+- return -EBUSY;
+- if (mutex_lock_interruptible(&runtime->oss.params_lock))
+- return -ERESTARTSYS;
++ err = lock_params(runtime);
++ if (err < 0)
++ return err;
+ err = snd_pcm_oss_set_fragment1(substream, val);
+- mutex_unlock(&runtime->oss.params_lock);
++ unlock_params(runtime);
+ if (err < 0)
+ return err;
+ }
--- /dev/null
+From 40cab6e88cb0b6c56d3f30b7491a20e803f948f6 Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Fri, 23 Mar 2018 08:03:26 +0100
+Subject: ALSA: pcm: Return -EBUSY for OSS ioctls changing busy streams
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit 40cab6e88cb0b6c56d3f30b7491a20e803f948f6 upstream.
+
+OSS PCM stream management isn't modal but it allows ioctls issued at
+any time for changing the parameters. In the previous hardening
+patch ("ALSA: pcm: Avoid potential races between OSS ioctls and
+read/write"), we covered these races and prevent the corruption by
+protecting the concurrent accesses via params_lock mutex. However,
+this means that some ioctls that try to change the stream parameter
+(e.g. channels or format) would be blocked until the read/write
+finishes, and it may take really long.
+
+Basically changing the parameter while reading/writing is an invalid
+operation, hence it's even more user-friendly from the API POV if it
+returns -EBUSY in such a situation.
+
+This patch adds such checks in the relevant ioctls with the addition
+of read/write access refcount.
+
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ include/sound/pcm_oss.h | 1 +
+ sound/core/oss/pcm_oss.c | 36 +++++++++++++++++++++++++++---------
+ 2 files changed, 28 insertions(+), 9 deletions(-)
+
+--- a/include/sound/pcm_oss.h
++++ b/include/sound/pcm_oss.h
+@@ -57,6 +57,7 @@ struct snd_pcm_oss_runtime {
+ char *buffer; /* vmallocated period */
+ size_t buffer_used; /* used length from period buffer */
+ struct mutex params_lock;
++ atomic_t rw_ref; /* concurrent read/write accesses */
+ #ifdef CONFIG_SND_PCM_OSS_PLUGINS
+ struct snd_pcm_plugin *plugin_first;
+ struct snd_pcm_plugin *plugin_last;
+--- a/sound/core/oss/pcm_oss.c
++++ b/sound/core/oss/pcm_oss.c
+@@ -1405,6 +1405,7 @@ static ssize_t snd_pcm_oss_write1(struct
+ if (atomic_read(&substream->mmap_count))
+ return -ENXIO;
+
++ atomic_inc(&runtime->oss.rw_ref);
+ while (bytes > 0) {
+ if (mutex_lock_interruptible(&runtime->oss.params_lock)) {
+ tmp = -ERESTARTSYS;
+@@ -1468,6 +1469,7 @@ static ssize_t snd_pcm_oss_write1(struct
+ }
+ tmp = 0;
+ }
++ atomic_dec(&runtime->oss.rw_ref);
+ return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
+ }
+
+@@ -1513,6 +1515,7 @@ static ssize_t snd_pcm_oss_read1(struct
+ if (atomic_read(&substream->mmap_count))
+ return -ENXIO;
+
++ atomic_inc(&runtime->oss.rw_ref);
+ while (bytes > 0) {
+ if (mutex_lock_interruptible(&runtime->oss.params_lock)) {
+ tmp = -ERESTARTSYS;
+@@ -1561,6 +1564,7 @@ static ssize_t snd_pcm_oss_read1(struct
+ }
+ tmp = 0;
+ }
++ atomic_dec(&runtime->oss.rw_ref);
+ return xfer > 0 ? (snd_pcm_sframes_t)xfer : tmp;
+ }
+
+@@ -1667,8 +1671,11 @@ static int snd_pcm_oss_sync(struct snd_p
+ goto __direct;
+ if ((err = snd_pcm_oss_make_ready(substream)) < 0)
+ return err;
+- if (mutex_lock_interruptible(&runtime->oss.params_lock))
++ atomic_inc(&runtime->oss.rw_ref);
++ if (mutex_lock_interruptible(&runtime->oss.params_lock)) {
++ atomic_dec(&runtime->oss.rw_ref);
+ return -ERESTARTSYS;
++ }
+ format = snd_pcm_oss_format_from(runtime->oss.format);
+ width = snd_pcm_format_physical_width(format);
+ if (runtime->oss.buffer_used > 0) {
+@@ -1680,10 +1687,8 @@ static int snd_pcm_oss_sync(struct snd_p
+ runtime->oss.buffer + runtime->oss.buffer_used,
+ size);
+ err = snd_pcm_oss_sync1(substream, runtime->oss.period_bytes);
+- if (err < 0) {
+- mutex_unlock(&runtime->oss.params_lock);
+- return err;
+- }
++ if (err < 0)
++ goto unlock;
+ } else if (runtime->oss.period_ptr > 0) {
+ #ifdef OSS_DEBUG
+ pcm_dbg(substream->pcm, "sync: period_ptr\n");
+@@ -1693,10 +1698,8 @@ static int snd_pcm_oss_sync(struct snd_p
+ runtime->oss.buffer,
+ size * 8 / width);
+ err = snd_pcm_oss_sync1(substream, size);
+- if (err < 0) {
+- mutex_unlock(&runtime->oss.params_lock);
+- return err;
+- }
++ if (err < 0)
++ goto unlock;
+ }
+ /*
+ * The ALSA's period might be a bit large than OSS one.
+@@ -1727,7 +1730,11 @@ static int snd_pcm_oss_sync(struct snd_p
+ snd_pcm_lib_writev(substream, buffers, size);
+ }
+ }
++unlock:
+ mutex_unlock(&runtime->oss.params_lock);
++ atomic_dec(&runtime->oss.rw_ref);
++ if (err < 0)
++ return err;
+ /*
+ * finish sync: drain the buffer
+ */
+@@ -1775,6 +1782,8 @@ static int snd_pcm_oss_set_rate(struct s
+ rate = 192000;
+ if (mutex_lock_interruptible(&runtime->oss.params_lock))
+ return -ERESTARTSYS;
++ if (atomic_read(&runtime->oss.rw_ref))
++ return -EBUSY;
+ if (runtime->oss.rate != rate) {
+ runtime->oss.params = 1;
+ runtime->oss.rate = rate;
+@@ -1809,6 +1818,8 @@ static int snd_pcm_oss_set_channels(stru
+ runtime = substream->runtime;
+ if (mutex_lock_interruptible(&runtime->oss.params_lock))
+ return -ERESTARTSYS;
++ if (atomic_read(&runtime->oss.rw_ref))
++ return -EBUSY;
+ if (runtime->oss.channels != channels) {
+ runtime->oss.params = 1;
+ runtime->oss.channels = channels;
+@@ -1899,6 +1910,8 @@ static int snd_pcm_oss_set_format(struct
+ if (substream == NULL)
+ continue;
+ runtime = substream->runtime;
++ if (atomic_read(&runtime->oss.rw_ref))
++ return -EBUSY;
+ if (mutex_lock_interruptible(&runtime->oss.params_lock))
+ return -ERESTARTSYS;
+ if (runtime->oss.format != format) {
+@@ -1953,6 +1966,8 @@ static int snd_pcm_oss_set_subdivide(str
+ if (substream == NULL)
+ continue;
+ runtime = substream->runtime;
++ if (atomic_read(&runtime->oss.rw_ref))
++ return -EBUSY;
+ if (mutex_lock_interruptible(&runtime->oss.params_lock))
+ return -ERESTARTSYS;
+ err = snd_pcm_oss_set_subdivide1(substream, subdivide);
+@@ -1991,6 +2006,8 @@ static int snd_pcm_oss_set_fragment(stru
+ if (substream == NULL)
+ continue;
+ runtime = substream->runtime;
++ if (atomic_read(&runtime->oss.rw_ref))
++ return -EBUSY;
+ if (mutex_lock_interruptible(&runtime->oss.params_lock))
+ return -ERESTARTSYS;
+ err = snd_pcm_oss_set_fragment1(substream, val);
+@@ -2385,6 +2402,7 @@ static void snd_pcm_oss_init_substream(s
+ runtime->oss.maxfrags = 0;
+ runtime->oss.subdivision = 0;
+ substream->pcm_release = snd_pcm_oss_release_substream;
++ atomic_set(&runtime->oss.rw_ref, 0);
+ }
+
+ static int snd_pcm_oss_release_file(struct snd_pcm_oss_file *pcm_oss_file)
--- /dev/null
+From c64ed5dd9feba193c76eb460b451225ac2a0d87b Mon Sep 17 00:00:00 2001
+From: Takashi Iwai <tiwai@suse.de>
+Date: Tue, 9 Jan 2018 08:51:02 +0100
+Subject: ALSA: pcm: Use ERESTARTSYS instead of EINTR in OSS emulation
+
+From: Takashi Iwai <tiwai@suse.de>
+
+commit c64ed5dd9feba193c76eb460b451225ac2a0d87b upstream.
+
+Fix the last standing EINTR in the whole subsystem. Use more correct
+ERESTARTSYS for pending signals.
+
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/core/oss/pcm_oss.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/sound/core/oss/pcm_oss.c
++++ b/sound/core/oss/pcm_oss.c
+@@ -853,7 +853,7 @@ static int snd_pcm_oss_change_params(str
+ if (!(mutex_trylock(&runtime->oss.params_lock)))
+ return -EAGAIN;
+ } else if (mutex_lock_interruptible(&runtime->oss.params_lock))
+- return -EINTR;
++ return -ERESTARTSYS;
+ sw_params = kzalloc(sizeof(*sw_params), GFP_KERNEL);
+ params = kmalloc(sizeof(*params), GFP_KERNEL);
+ sparams = kmalloc(sizeof(*sparams), GFP_KERNEL);
dt-bindings-clock-mediatek-add-binding-for-fixed-factor-clock-axisel_d4.patch
watchdog-f71808e_wdt-fix-wd_en-register-read.patch
vfio-pci-virtualize-maximum-read-request-size.patch
+alsa-pcm-use-erestartsys-instead-of-eintr-in-oss-emulation.patch
+alsa-pcm-avoid-potential-races-between-oss-ioctls-and-read-write.patch
+alsa-pcm-return-ebusy-for-oss-ioctls-changing-busy-streams.patch
+alsa-pcm-fix-mutex-unbalance-in-oss-emulation-ioctls.patch
+alsa-pcm-fix-endless-loop-for-xrun-recovery-in-oss-emulation.patch