--- /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
+@@ -823,8 +823,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;
+@@ -838,11 +838,8 @@ static int snd_pcm_oss_change_params(str
+ const 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);
+@@ -1068,6 +1065,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;
+ }
+@@ -1096,11 +1110,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,
+@@ -1120,8 +1137,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);
+@@ -1129,6 +1144,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;
+@@ -1332,13 +1370,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)
+@@ -1439,13 +1478,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);
+@@ -1501,10 +1541,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;
+ }
+@@ -1590,9 +1632,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");
+@@ -1643,7 +1686,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];
+@@ -1654,8 +1699,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;
+ }
+@@ -1674,10 +1721,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);
+ }
+@@ -1705,10 +1755,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);
+ }
+@@ -1794,10 +1847,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);
+@@ -1817,8 +1873,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;
+@@ -1842,9 +1896,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;
+@@ -1854,8 +1915,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;
+@@ -1875,9 +1934,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;
+@@ -1961,6 +2027,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;
+@@ -1978,13 +2047,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;
+@@ -1999,11 +2074,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
+@@ -1128,13 +1128,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
+@@ -823,6 +823,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)
+ {
+@@ -1721,6 +1738,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;
+@@ -1728,15 +1747,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);
+ }
+@@ -1761,18 +1779,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);
+ }
+@@ -1845,6 +1864,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);
+@@ -1858,15 +1878,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);
+@@ -1914,12 +1933,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;
+ }
+@@ -1954,12 +1972,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
+@@ -1370,6 +1370,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;
+@@ -1433,6 +1434,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;
+ }
+
+@@ -1478,6 +1480,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;
+@@ -1526,6 +1529,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;
+ }
+
+@@ -1632,8 +1636,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) {
+@@ -1645,10 +1652,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");
+@@ -1658,10 +1663,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.
+@@ -1675,7 +1678,11 @@ static int snd_pcm_oss_sync(struct snd_p
+ else if (runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
+ snd_pcm_lib_writev(substream, NULL, size);
+ }
++unlock:
+ mutex_unlock(&runtime->oss.params_lock);
++ atomic_dec(&runtime->oss.rw_ref);
++ if (err < 0)
++ return err;
+ /*
+ * finish sync: drain the buffer
+ */
+@@ -1723,6 +1730,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;
+@@ -1757,6 +1766,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;
+@@ -1847,6 +1858,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) {
+@@ -1901,6 +1914,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);
+@@ -1939,6 +1954,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);
+@@ -2333,6 +2350,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
+@@ -842,7 +842,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