mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-05 02:21:52 +09:00
ALSA: control: Don't access controls outside of protected regions
commit fd9f26e4ec upstream.
A control that is visible on the card->controls list can be freed at any time.
This means we must not access any of its memory while not holding the
controls_rw_lock. Otherwise we risk a use after free access.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Acked-by: Jaroslav Kysela <perex@perex.cz>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
adbb1449cc
commit
9abd948621
@@ -331,6 +331,7 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
|
||||
{
|
||||
struct snd_ctl_elem_id id;
|
||||
unsigned int idx;
|
||||
unsigned int count;
|
||||
int err = -EINVAL;
|
||||
|
||||
if (! kcontrol)
|
||||
@@ -359,8 +360,9 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
|
||||
card->controls_count += kcontrol->count;
|
||||
kcontrol->id.numid = card->last_numid + 1;
|
||||
card->last_numid += kcontrol->count;
|
||||
count = kcontrol->count;
|
||||
up_write(&card->controls_rwsem);
|
||||
for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++)
|
||||
for (idx = 0; idx < count; idx++, id.index++, id.numid++)
|
||||
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id);
|
||||
return 0;
|
||||
|
||||
@@ -389,6 +391,7 @@ int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol,
|
||||
bool add_on_replace)
|
||||
{
|
||||
struct snd_ctl_elem_id id;
|
||||
unsigned int count;
|
||||
unsigned int idx;
|
||||
struct snd_kcontrol *old;
|
||||
int ret;
|
||||
@@ -424,8 +427,9 @@ add:
|
||||
card->controls_count += kcontrol->count;
|
||||
kcontrol->id.numid = card->last_numid + 1;
|
||||
card->last_numid += kcontrol->count;
|
||||
count = kcontrol->count;
|
||||
up_write(&card->controls_rwsem);
|
||||
for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++)
|
||||
for (idx = 0; idx < count; idx++, id.index++, id.numid++)
|
||||
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id);
|
||||
return 0;
|
||||
|
||||
@@ -898,9 +902,9 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
|
||||
result = kctl->put(kctl, control);
|
||||
}
|
||||
if (result > 0) {
|
||||
struct snd_ctl_elem_id id = control->id;
|
||||
up_read(&card->controls_rwsem);
|
||||
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE,
|
||||
&control->id);
|
||||
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &id);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -1334,8 +1338,9 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file,
|
||||
}
|
||||
err = kctl->tlv.c(kctl, op_flag, tlv.length, _tlv->tlv);
|
||||
if (err > 0) {
|
||||
struct snd_ctl_elem_id id = kctl->id;
|
||||
up_read(&card->controls_rwsem);
|
||||
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_TLV, &kctl->id);
|
||||
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_TLV, &id);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user