Skip to content

Commit c589544

Browse files
takaswiemikeNG
authored andcommitted
ALSA: control: code refactoring for ELEM_READ/ELEM_WRITE operations
commit becf9e5 upstream. ALSA control core handles ELEM_READ/ELEM_WRITE requests within lock acquisition of a counting semaphore. The lock is acquired in helper functions in the end of call path before calling implementations of each driver. ioctl(2) with SNDRV_CTL_ELEM_READ ... ->snd_ctl_ioctl() ->snd_ctl_elem_read_user() ->snd_ctl_elem_read() ->down_read(controls_rwsem) ->snd_ctl_find_id() ->struct snd_kcontrol.get() ->up_read(controls_rwsem) ioctl(2) with SNDRV_CTL_ELEM_WRITE ... ->snd_ctl_ioctl() ->snd_ctl_elem_write_user() ->snd_ctl_elem_write() ->down_read(controls_rwsem) ->snd_ctl_find_id() ->struct snd_kcontrol.put() ->up_read(controls_rwsem) This commit moves the lock acquisition to middle of the call graph to simplify the helper functions. As a result: ioctl(2) with SNDRV_CTL_ELEM_READ ... ->snd_ctl_ioctl() ->snd_ctl_elem_read_user() ->down_read(controls_rwsem) ->snd_ctl_elem_read() ->snd_ctl_find_id() ->struct snd_kcontrol.get() ->up_read(controls_rwsem) ioctl(2) with SNDRV_CTL_ELEM_WRITE ... ->snd_ctl_ioctl() ->snd_ctl_elem_write_user() ->down_read(controls_rwsem) ->snd_ctl_elem_write() ->snd_ctl_find_id() ->struct snd_kcontrol.put() ->up_read(controls_rwsem) Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> Signed-off-by: Takashi Iwai <tiwai@suse.de> Fixes: e8064dec769e6 "ALSA: pcm: Move rwsem lock inside snd_ctl_elem_read to prevent UAF" Signed-off-by: Alexander Grund <theflamefire89@gmail.com> [uli: added upstream commit id] Signed-off-by: Ulrich Hecht <uli+cip@fpond.eu> Change-Id: I72ea6a8b828938b56935fc4ce08021e5e91135a1
1 parent 7094a28 commit c589544

1 file changed

Lines changed: 38 additions & 40 deletions

File tree

sound/core/control.c

Lines changed: 38 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -907,24 +907,18 @@ static int snd_ctl_elem_read(struct snd_card *card,
907907
struct snd_kcontrol *kctl;
908908
struct snd_kcontrol_volatile *vd;
909909
unsigned int index_offset;
910-
int result;
911910

912-
down_read(&card->controls_rwsem);
913911
kctl = snd_ctl_find_id(card, &control->id);
914-
if (kctl == NULL) {
915-
result = -ENOENT;
916-
} else {
917-
index_offset = snd_ctl_get_ioff(kctl, &control->id);
918-
vd = &kctl->vd[index_offset];
919-
if ((vd->access & SNDRV_CTL_ELEM_ACCESS_READ) &&
920-
kctl->get != NULL) {
921-
snd_ctl_build_ioff(&control->id, kctl, index_offset);
922-
result = kctl->get(kctl, control);
923-
} else
924-
result = -EPERM;
925-
}
926-
up_read(&card->controls_rwsem);
927-
return result;
912+
if (kctl == NULL)
913+
return -ENOENT;
914+
915+
index_offset = snd_ctl_get_ioff(kctl, &control->id);
916+
vd = &kctl->vd[index_offset];
917+
if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_READ) && kctl->get == NULL)
918+
return -EPERM;
919+
920+
snd_ctl_build_ioff(&control->id, kctl, index_offset);
921+
return kctl->get(kctl, control);
928922
}
929923

930924
static int snd_ctl_elem_read_user(struct snd_card *card,
@@ -939,8 +933,11 @@ static int snd_ctl_elem_read_user(struct snd_card *card,
939933

940934
snd_power_lock(card);
941935
result = snd_power_wait(card, SNDRV_CTL_POWER_D0);
942-
if (result >= 0)
936+
if (result >= 0) {
937+
down_read(&card->controls_rwsem);
943938
result = snd_ctl_elem_read(card, control);
939+
up_read(&card->controls_rwsem);
940+
}
944941
snd_power_unlock(card);
945942
if (result >= 0)
946943
if (copy_to_user(_control, control, sizeof(*control)))
@@ -957,30 +954,28 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
957954
unsigned int index_offset;
958955
int result;
959956

960-
down_read(&card->controls_rwsem);
961957
kctl = snd_ctl_find_id(card, &control->id);
962-
if (kctl == NULL) {
963-
result = -ENOENT;
964-
} else {
965-
index_offset = snd_ctl_get_ioff(kctl, &control->id);
966-
vd = &kctl->vd[index_offset];
967-
if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_WRITE) ||
968-
kctl->put == NULL ||
969-
(file && vd->owner && vd->owner != file)) {
970-
result = -EPERM;
971-
} else {
972-
snd_ctl_build_ioff(&control->id, kctl, index_offset);
973-
result = kctl->put(kctl, control);
974-
}
975-
if (result > 0) {
976-
struct snd_ctl_elem_id id = control->id;
977-
up_read(&card->controls_rwsem);
978-
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &id);
979-
return 0;
980-
}
958+
if (kctl == NULL)
959+
return -ENOENT;
960+
961+
index_offset = snd_ctl_get_ioff(kctl, &control->id);
962+
vd = &kctl->vd[index_offset];
963+
if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_WRITE) || kctl->put == NULL ||
964+
(file && vd->owner && vd->owner != file)) {
965+
return -EPERM;
981966
}
982-
up_read(&card->controls_rwsem);
983-
return result;
967+
968+
snd_ctl_build_ioff(&control->id, kctl, index_offset);
969+
result = kctl->put(kctl, control);
970+
if (result < 0)
971+
return result;
972+
973+
if (result > 0) {
974+
struct snd_ctl_elem_id id = control->id;
975+
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &id);
976+
}
977+
978+
return 0;
984979
}
985980

986981
static int snd_ctl_elem_write_user(struct snd_ctl_file *file,
@@ -997,8 +992,11 @@ static int snd_ctl_elem_write_user(struct snd_ctl_file *file,
997992
card = file->card;
998993
snd_power_lock(card);
999994
result = snd_power_wait(card, SNDRV_CTL_POWER_D0);
1000-
if (result >= 0)
995+
if (result >= 0) {
996+
down_read(&card->controls_rwsem);
1001997
result = snd_ctl_elem_write(card, file, control);
998+
up_read(&card->controls_rwsem);
999+
}
10021000
snd_power_unlock(card);
10031001
if (result >= 0)
10041002
if (copy_to_user(_control, control, sizeof(*control)))

0 commit comments

Comments
 (0)