Skip to content

Commit 54c0a77

Browse files
Clement LecigneDinh Nguyen
Clement Lecigne
authored and
Dinh Nguyen
committed
ALSA: pcm: Move rwsem lock inside snd_ctl_elem_read to prevent UAF
[upstream commit 56b88b5] Takes rwsem lock inside snd_ctl_elem_read instead of snd_ctl_elem_read_user like it was done for write in commit 1fa4445 ("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: [email protected] # 5.13+ Signed-off-by: Clement Lecigne <[email protected]> Reviewed-by: Jaroslav Kysela <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Takashi Iwai <[email protected]>
1 parent c8628ae commit 54c0a77

File tree

1 file changed

+15
-9
lines changed

1 file changed

+15
-9
lines changed

sound/core/control.c

+15-9
Original file line numberDiff line numberDiff line change
@@ -1203,14 +1203,19 @@ static int snd_ctl_elem_read(struct snd_card *card,
12031203
const u32 pattern = 0xdeadbeef;
12041204
int ret;
12051205

1206+
down_read(&card->controls_rwsem);
12061207
kctl = snd_ctl_find_id(card, &control->id);
1207-
if (kctl == NULL)
1208-
return -ENOENT;
1208+
if (kctl == NULL) {
1209+
ret = -ENOENT;
1210+
goto unlock;
1211+
}
12091212

12101213
index_offset = snd_ctl_get_ioff(kctl, &control->id);
12111214
vd = &kctl->vd[index_offset];
1212-
if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_READ) || kctl->get == NULL)
1213-
return -EPERM;
1215+
if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_READ) || kctl->get == NULL) {
1216+
ret = -EPERM;
1217+
goto unlock;
1218+
}
12141219

12151220
snd_ctl_build_ioff(&control->id, kctl, index_offset);
12161221

@@ -1220,7 +1225,7 @@ static int snd_ctl_elem_read(struct snd_card *card,
12201225
info.id = control->id;
12211226
ret = __snd_ctl_elem_info(card, kctl, &info, NULL);
12221227
if (ret < 0)
1223-
return ret;
1228+
goto unlock;
12241229
#endif
12251230

12261231
if (!snd_ctl_skip_validation(&info))
@@ -1230,16 +1235,19 @@ static int snd_ctl_elem_read(struct snd_card *card,
12301235
ret = kctl->get(kctl, control);
12311236
snd_power_unref(card);
12321237
if (ret < 0)
1233-
return ret;
1238+
goto unlock;
12341239
if (!snd_ctl_skip_validation(&info) &&
12351240
sanity_check_elem_value(card, control, &info, pattern) < 0) {
12361241
dev_err(card->dev,
12371242
"control %i:%i:%i:%s:%i: access overflow\n",
12381243
control->id.iface, control->id.device,
12391244
control->id.subdevice, control->id.name,
12401245
control->id.index);
1241-
return -EINVAL;
1246+
ret = -EINVAL;
1247+
goto unlock;
12421248
}
1249+
unlock:
1250+
up_read(&card->controls_rwsem);
12431251
return ret;
12441252
}
12451253

@@ -1253,9 +1261,7 @@ static int snd_ctl_elem_read_user(struct snd_card *card,
12531261
if (IS_ERR(control))
12541262
return PTR_ERR(control);
12551263

1256-
down_read(&card->controls_rwsem);
12571264
result = snd_ctl_elem_read(card, control);
1258-
up_read(&card->controls_rwsem);
12591265
if (result < 0)
12601266
goto error;
12611267

0 commit comments

Comments
 (0)