lkml.org 
[lkml]   [2018]   [Apr]   [22]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.9 63/95] ALSA: pcm: Fix mutex unbalance in OSS emulation ioctls
    Date
    4.9-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    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;
    }

    \
     
     \ /
      Last update: 2018-04-22 16:51    [W:4.059 / U:0.060 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site