Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fd9f26e4 authored by Lars-Peter Clausen's avatar Lars-Peter Clausen Committed by Takashi Iwai
Browse files

ALSA: control: Don't access controls outside of protected regions



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: default avatarLars-Peter Clausen <lars@metafoo.de>
Acked-by: default avatarJaroslav Kysela <perex@perex.cz>
Cc: <stable@vger.kernel.org>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 82262a46
Loading
Loading
Loading
Loading
+10 −5
Original line number Diff line number Diff line
@@ -330,6 +330,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)
@@ -358,8 +359,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;

@@ -388,6 +390,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;
@@ -423,8 +426,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;

@@ -897,9 +901,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;
		}
	}
@@ -1333,8 +1337,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 {