| From 411cef6adfb38a5bb6bd9af3941b28198e7fb680 Mon Sep 17 00:00:00 2001 |
| From: Takashi Iwai <tiwai@suse.de> |
| Date: Wed, 20 Oct 2021 18:48:46 +0200 |
| Subject: ALSA: mixer: oss: Fix racy access to slots |
| |
| 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 | 43 +++++++++++++++++++++++++++++++++---------- |
| 1 file changed, 33 insertions(+), 10 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,11 +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; |
| - if ((err = mixer->get_recsrc(fmixer, &index)) < 0) |
| - return err; |
| + result = mixer->get_recsrc(fmixer, &index); |
| + if (result < 0) |
| + goto unlock; |
| result = 1 << index; |
| } else { |
| struct snd_mixer_oss_slot *pslot; |
| @@ -201,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) |
| @@ -214,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; |
| @@ -239,6 +250,7 @@ static int snd_mixer_oss_set_recsrc(stru |
| } |
| } |
| } |
| + mutex_unlock(&mixer->reg_mutex); |
| return result; |
| } |
| |
| @@ -250,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]; |
| @@ -257,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; |
| } |
| |
| @@ -278,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; |
| @@ -288,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) |