lkml.org 
[lkml]   [2021]   [Nov]   [15]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.15 042/917] ALSA: mixer: oss: Fix racy access to slots
    Date
    From: Takashi Iwai <tiwai@suse.de>

    commit 411cef6adfb38a5bb6bd9af3941b28198e7fb680 upstream.

    The OSS mixer can reassign the mapping slots dynamically via proc
    file. Although the addition and deletion of those slots are protected
    by mixer->reg_mutex, the access to slots aren't, hence this may cause
    UAF when the slots in use are deleted concurrently.

    This patch applies the mixer->reg_mutex in all appropriate code paths
    (i.e. the ioctl functions) that may access slots.

    Reported-by: syzbot+9988f17cf72a1045a189@syzkaller.appspotmail.com
    Reviewed-by: Jaroslav Kysela <perex@perex.cz>
    Cc: <stable@vger.kernel.org>
    Link: https://lore.kernel.org/r/00000000000036adc005ceca9175@google.com
    Link: https://lore.kernel.org/r/20211020164846.922-1-tiwai@suse.de
    Signed-off-by: Takashi Iwai <tiwai@suse.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    sound/core/oss/mixer_oss.c | 44 +++++++++++++++++++++++++++++++++-----------
    1 file changed, 33 insertions(+), 11 deletions(-)

    --- a/sound/core/oss/mixer_oss.c
    +++ b/sound/core/oss/mixer_oss.c
    @@ -130,11 +130,13 @@ static int snd_mixer_oss_devmask(struct

    if (mixer == NULL)
    return -EIO;
    + mutex_lock(&mixer->reg_mutex);
    for (chn = 0; chn < 31; chn++) {
    pslot = &mixer->slots[chn];
    if (pslot->put_volume || pslot->put_recsrc)
    result |= 1 << chn;
    }
    + mutex_unlock(&mixer->reg_mutex);
    return result;
    }

    @@ -146,11 +148,13 @@ static int snd_mixer_oss_stereodevs(stru

    if (mixer == NULL)
    return -EIO;
    + mutex_lock(&mixer->reg_mutex);
    for (chn = 0; chn < 31; chn++) {
    pslot = &mixer->slots[chn];
    if (pslot->put_volume && pslot->stereo)
    result |= 1 << chn;
    }
    + mutex_unlock(&mixer->reg_mutex);
    return result;
    }

    @@ -161,6 +165,7 @@ static int snd_mixer_oss_recmask(struct

    if (mixer == NULL)
    return -EIO;
    + mutex_lock(&mixer->reg_mutex);
    if (mixer->put_recsrc && mixer->get_recsrc) { /* exclusive */
    result = mixer->mask_recsrc;
    } else {
    @@ -172,6 +177,7 @@ static int snd_mixer_oss_recmask(struct
    result |= 1 << chn;
    }
    }
    + mutex_unlock(&mixer->reg_mutex);
    return result;
    }

    @@ -182,12 +188,12 @@ static int snd_mixer_oss_get_recsrc(stru

    if (mixer == NULL)
    return -EIO;
    + mutex_lock(&mixer->reg_mutex);
    if (mixer->put_recsrc && mixer->get_recsrc) { /* exclusive */
    - int err;
    unsigned int index;
    - err = mixer->get_recsrc(fmixer, &index);
    - if (err < 0)
    - return err;
    + result = mixer->get_recsrc(fmixer, &index);
    + if (result < 0)
    + goto unlock;
    result = 1 << index;
    } else {
    struct snd_mixer_oss_slot *pslot;
    @@ -202,7 +208,10 @@ static int snd_mixer_oss_get_recsrc(stru
    }
    }
    }
    - return mixer->oss_recsrc = result;
    + mixer->oss_recsrc = result;
    + unlock:
    + mutex_unlock(&mixer->reg_mutex);
    + return result;
    }

    static int snd_mixer_oss_set_recsrc(struct snd_mixer_oss_file *fmixer, int recsrc)
    @@ -215,6 +224,7 @@ static int snd_mixer_oss_set_recsrc(stru

    if (mixer == NULL)
    return -EIO;
    + mutex_lock(&mixer->reg_mutex);
    if (mixer->get_recsrc && mixer->put_recsrc) { /* exclusive input */
    if (recsrc & ~mixer->oss_recsrc)
    recsrc &= ~mixer->oss_recsrc;
    @@ -240,6 +250,7 @@ static int snd_mixer_oss_set_recsrc(stru
    }
    }
    }
    + mutex_unlock(&mixer->reg_mutex);
    return result;
    }

    @@ -251,6 +262,7 @@ static int snd_mixer_oss_get_volume(stru

    if (mixer == NULL || slot > 30)
    return -EIO;
    + mutex_lock(&mixer->reg_mutex);
    pslot = &mixer->slots[slot];
    left = pslot->volume[0];
    right = pslot->volume[1];
    @@ -258,15 +270,21 @@ static int snd_mixer_oss_get_volume(stru
    result = pslot->get_volume(fmixer, pslot, &left, &right);
    if (!pslot->stereo)
    right = left;
    - if (snd_BUG_ON(left < 0 || left > 100))
    - return -EIO;
    - if (snd_BUG_ON(right < 0 || right > 100))
    - return -EIO;
    + if (snd_BUG_ON(left < 0 || left > 100)) {
    + result = -EIO;
    + goto unlock;
    + }
    + if (snd_BUG_ON(right < 0 || right > 100)) {
    + result = -EIO;
    + goto unlock;
    + }
    if (result >= 0) {
    pslot->volume[0] = left;
    pslot->volume[1] = right;
    result = (left & 0xff) | ((right & 0xff) << 8);
    }
    + unlock:
    + mutex_unlock(&mixer->reg_mutex);
    return result;
    }

    @@ -279,6 +297,7 @@ static int snd_mixer_oss_set_volume(stru

    if (mixer == NULL || slot > 30)
    return -EIO;
    + mutex_lock(&mixer->reg_mutex);
    pslot = &mixer->slots[slot];
    if (left > 100)
    left = 100;
    @@ -289,10 +308,13 @@ static int snd_mixer_oss_set_volume(stru
    if (pslot->put_volume)
    result = pslot->put_volume(fmixer, pslot, left, right);
    if (result < 0)
    - return result;
    + goto unlock;
    pslot->volume[0] = left;
    pslot->volume[1] = right;
    - return (left & 0xff) | ((right & 0xff) << 8);
    + result = (left & 0xff) | ((right & 0xff) << 8);
    + unlock:
    + mutex_lock(&mixer->reg_mutex);
    + return result;
    }

    static int snd_mixer_oss_ioctl1(struct snd_mixer_oss_file *fmixer, unsigned int cmd, unsigned long arg)

    \
     
     \ /
      Last update: 2021-11-16 00:28    [W:3.507 / U:0.048 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site