ALSA: pcm: Move rwsem lock inside snd_ctl_elem_read to prevent UAF
commit56b88b5056
upstream. Takes rwsem lock inside snd_ctl_elem_read instead of snd_ctl_elem_read_user like it was done for write in commit1fa4445f9a
("ALSA: control - introduce snd_ctl_notify_one() helper"). Doing this way we are also fixing the following locking issue happening in the compat path which can be easily triggered and turned into an use-after-free. 64-bits: snd_ctl_ioctl snd_ctl_elem_read_user [takes controls_rwsem] snd_ctl_elem_read [lock properly held, all good] [drops controls_rwsem] 32-bits: snd_ctl_ioctl_compat snd_ctl_elem_write_read_compat ctl_elem_write_read snd_ctl_elem_read [missing lock, not good] CVE-2023-0266 was assigned for this issue. Cc: stable@kernel.org # 5.13+ Signed-off-by: Clement Lecigne <clecigne@google.com> Reviewed-by: Jaroslav Kysela <perex@perex.cz> Link: https://lore.kernel.org/r/20230113120745.25464-1-tiwai@suse.de Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
e8988e878a
commit
d6ad4bd1d8
|
@ -1203,14 +1203,19 @@ static int snd_ctl_elem_read(struct snd_card *card,
|
|||
const u32 pattern = 0xdeadbeef;
|
||||
int ret;
|
||||
|
||||
down_read(&card->controls_rwsem);
|
||||
kctl = snd_ctl_find_id(card, &control->id);
|
||||
if (kctl == NULL)
|
||||
return -ENOENT;
|
||||
if (kctl == NULL) {
|
||||
ret = -ENOENT;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
index_offset = snd_ctl_get_ioff(kctl, &control->id);
|
||||
vd = &kctl->vd[index_offset];
|
||||
if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_READ) || kctl->get == NULL)
|
||||
return -EPERM;
|
||||
if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_READ) || kctl->get == NULL) {
|
||||
ret = -EPERM;
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
snd_ctl_build_ioff(&control->id, kctl, index_offset);
|
||||
|
||||
|
@ -1220,7 +1225,7 @@ static int snd_ctl_elem_read(struct snd_card *card,
|
|||
info.id = control->id;
|
||||
ret = __snd_ctl_elem_info(card, kctl, &info, NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
goto unlock;
|
||||
#endif
|
||||
|
||||
if (!snd_ctl_skip_validation(&info))
|
||||
|
@ -1230,7 +1235,7 @@ static int snd_ctl_elem_read(struct snd_card *card,
|
|||
ret = kctl->get(kctl, control);
|
||||
snd_power_unref(card);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
goto unlock;
|
||||
if (!snd_ctl_skip_validation(&info) &&
|
||||
sanity_check_elem_value(card, control, &info, pattern) < 0) {
|
||||
dev_err(card->dev,
|
||||
|
@ -1238,8 +1243,11 @@ static int snd_ctl_elem_read(struct snd_card *card,
|
|||
control->id.iface, control->id.device,
|
||||
control->id.subdevice, control->id.name,
|
||||
control->id.index);
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto unlock;
|
||||
}
|
||||
unlock:
|
||||
up_read(&card->controls_rwsem);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1253,9 +1261,7 @@ static int snd_ctl_elem_read_user(struct snd_card *card,
|
|||
if (IS_ERR(control))
|
||||
return PTR_ERR(control);
|
||||
|
||||
down_read(&card->controls_rwsem);
|
||||
result = snd_ctl_elem_read(card, control);
|
||||
up_read(&card->controls_rwsem);
|
||||
if (result < 0)
|
||||
goto error;
|
||||
|
||||
|
|
Loading…
Reference in New Issue