summaryrefslogtreecommitdiffstats
path: root/sound/core
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2021-10-20 18:48:46 +0200
committerTakashi Iwai <tiwai@suse.de>2021-10-21 07:03:47 +0200
commit411cef6adfb38a5bb6bd9af3941b28198e7fb680 (patch)
treec4a5edfafc36ef46e1fe1ca2fb0a4bbbe98773b7 /sound/core
parentALSA: usb-audio: Fix microphone sound on Jieli webcam. (diff)
downloadlinux-411cef6adfb38a5bb6bd9af3941b28198e7fb680.tar.xz
linux-411cef6adfb38a5bb6bd9af3941b28198e7fb680.zip
ALSA: mixer: oss: Fix racy access to slots
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>
Diffstat (limited to 'sound/core')
-rw-r--r--sound/core/oss/mixer_oss.c44
1 files changed, 33 insertions, 11 deletions
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c
index 6a5abdd4271b..d5ddc154a735 100644
--- 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 snd_mixer_oss_file *fmixer)
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(struct snd_mixer_oss_file *fmixer)
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 snd_mixer_oss_file *fmixer)
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 snd_mixer_oss_file *fmixer)
result |= 1 << chn;
}
}
+ mutex_unlock(&mixer->reg_mutex);
return result;
}
@@ -182,12 +188,12 @@ static int snd_mixer_oss_get_recsrc(struct snd_mixer_oss_file *fmixer)
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(struct snd_mixer_oss_file *fmixer)
}
}
}
- 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(struct snd_mixer_oss_file *fmixer, int recsr
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(struct snd_mixer_oss_file *fmixer, int recsr
}
}
}
+ mutex_unlock(&mixer->reg_mutex);
return result;
}
@@ -251,6 +262,7 @@ static int snd_mixer_oss_get_volume(struct snd_mixer_oss_file *fmixer, int slot)
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(struct snd_mixer_oss_file *fmixer, int slot)
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(struct snd_mixer_oss_file *fmixer,
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(struct snd_mixer_oss_file *fmixer,
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)