aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars-Peter Clausen <lars@metafoo.de>2014-06-18 13:32:33 +0200
committerStefan Bader <stefan.bader@canonical.com>2014-12-15 15:00:57 +0100
commitd3dc18fa8bb2c4ece6fc954447a80b64d0ab5bc7 (patch)
treea079d2eacbc3d78ade77d9c5039bfe9e1509c454
parent487f6cb94d4122cf3510ee91784f68f8a6291bf7 (diff)
downloadlinux-2.6.32.y-drm33.z-d3dc18fa8bb2c4ece6fc954447a80b64d0ab5bc7.tar.gz
ALSA: control: Don't access controls outside of protected regions
(commit fd9f26e4eca5d08a27d12c0933fceef76ed9663d 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> Cc: <stable@vger.kernel.org> Signed-off-by: Takashi Iwai <tiwai@suse.de> [wt: fixes CVE-2014-4653] Signed-off-by: Willy Tarreau <w@1wt.eu> Signed-off-by: Stefan Bader <stefan.bader@canonical.com>
-rw-r--r--sound/core/control.c8
1 files changed, 5 insertions, 3 deletions
diff --git a/sound/core/control.c b/sound/core/control.c
index 8bf3a6d1ebe241..e91d79a9ec4b89 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -325,6 +325,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)
@@ -356,8 +357,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;
@@ -784,9 +786,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;
}
}