diff options
author | Lars-Peter Clausen <lars@metafoo.de> | 2014-06-18 07:32:33 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2014-06-18 09:13:07 -0400 |
commit | fd9f26e4eca5d08a27d12c0933fceef76ed9663d (patch) | |
tree | 1b68c534f868ec086cf78e864888c99bdb70f5b5 /sound/core/control.c | |
parent | 82262a46627bebb0febcc26664746c25cef08563 (diff) |
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: Lars-Peter Clausen <lars@metafoo.de>
Acked-by: Jaroslav Kysela <perex@perex.cz>
Cc: <stable@vger.kernel.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/core/control.c')
-rw-r--r-- | sound/core/control.c | 15 |
1 files changed, 10 insertions, 5 deletions
diff --git a/sound/core/control.c b/sound/core/control.c index 1f413c286511..5c49f976fc7b 100644 --- a/sound/core/control.c +++ b/sound/core/control.c | |||
@@ -330,6 +330,7 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol) | |||
330 | { | 330 | { |
331 | struct snd_ctl_elem_id id; | 331 | struct snd_ctl_elem_id id; |
332 | unsigned int idx; | 332 | unsigned int idx; |
333 | unsigned int count; | ||
333 | int err = -EINVAL; | 334 | int err = -EINVAL; |
334 | 335 | ||
335 | if (! kcontrol) | 336 | if (! kcontrol) |
@@ -358,8 +359,9 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol) | |||
358 | card->controls_count += kcontrol->count; | 359 | card->controls_count += kcontrol->count; |
359 | kcontrol->id.numid = card->last_numid + 1; | 360 | kcontrol->id.numid = card->last_numid + 1; |
360 | card->last_numid += kcontrol->count; | 361 | card->last_numid += kcontrol->count; |
362 | count = kcontrol->count; | ||
361 | up_write(&card->controls_rwsem); | 363 | up_write(&card->controls_rwsem); |
362 | for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++) | 364 | for (idx = 0; idx < count; idx++, id.index++, id.numid++) |
363 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id); | 365 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id); |
364 | return 0; | 366 | return 0; |
365 | 367 | ||
@@ -388,6 +390,7 @@ int snd_ctl_replace(struct snd_card *card, struct snd_kcontrol *kcontrol, | |||
388 | bool add_on_replace) | 390 | bool add_on_replace) |
389 | { | 391 | { |
390 | struct snd_ctl_elem_id id; | 392 | struct snd_ctl_elem_id id; |
393 | unsigned int count; | ||
391 | unsigned int idx; | 394 | unsigned int idx; |
392 | struct snd_kcontrol *old; | 395 | struct snd_kcontrol *old; |
393 | int ret; | 396 | int ret; |
@@ -423,8 +426,9 @@ add: | |||
423 | card->controls_count += kcontrol->count; | 426 | card->controls_count += kcontrol->count; |
424 | kcontrol->id.numid = card->last_numid + 1; | 427 | kcontrol->id.numid = card->last_numid + 1; |
425 | card->last_numid += kcontrol->count; | 428 | card->last_numid += kcontrol->count; |
429 | count = kcontrol->count; | ||
426 | up_write(&card->controls_rwsem); | 430 | up_write(&card->controls_rwsem); |
427 | for (idx = 0; idx < kcontrol->count; idx++, id.index++, id.numid++) | 431 | for (idx = 0; idx < count; idx++, id.index++, id.numid++) |
428 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id); | 432 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id); |
429 | return 0; | 433 | return 0; |
430 | 434 | ||
@@ -897,9 +901,9 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file, | |||
897 | result = kctl->put(kctl, control); | 901 | result = kctl->put(kctl, control); |
898 | } | 902 | } |
899 | if (result > 0) { | 903 | if (result > 0) { |
904 | struct snd_ctl_elem_id id = control->id; | ||
900 | up_read(&card->controls_rwsem); | 905 | up_read(&card->controls_rwsem); |
901 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, | 906 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &id); |
902 | &control->id); | ||
903 | return 0; | 907 | return 0; |
904 | } | 908 | } |
905 | } | 909 | } |
@@ -1333,8 +1337,9 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file, | |||
1333 | } | 1337 | } |
1334 | err = kctl->tlv.c(kctl, op_flag, tlv.length, _tlv->tlv); | 1338 | err = kctl->tlv.c(kctl, op_flag, tlv.length, _tlv->tlv); |
1335 | if (err > 0) { | 1339 | if (err > 0) { |
1340 | struct snd_ctl_elem_id id = kctl->id; | ||
1336 | up_read(&card->controls_rwsem); | 1341 | up_read(&card->controls_rwsem); |
1337 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_TLV, &kctl->id); | 1342 | snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_TLV, &id); |
1338 | return 0; | 1343 | return 0; |
1339 | } | 1344 | } |
1340 | } else { | 1345 | } else { |