--- /dev/null
+From ed81e6b21790b717cda5f5bab2bdb07d2ce17ab1 Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Wed, 18 Jun 2014 13:32:31 +0200
+Subject: [PATCH] ALSA: control: Protect user controls against concurrent
+ access
+
+commit 07f4d9d74a04aa7c72c5dae0ef97565f28f17b92 upstream.
+
+The user-control put and get handlers as well as the tlv do not protect against
+concurrent access from multiple threads. Since the state of the control is not
+updated atomically it is possible that either two write operations or a write
+and a read operation race against each other. Both can lead to arbitrary memory
+disclosure. This patch introduces a new lock that protects user-controls from
+concurrent access. Since applications typically access controls sequentially
+than in parallel a single lock per card should be fine.
+
+This fixes CVE-2014-4652
+Upstream-Status: Backport
+
+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: Jiri Slaby <jslaby@suse.cz>
+Signed-off-by: Sona Sarmadi <sona.sarmadi@enea.com>
+---
+ include/sound/core.h | 2 ++
+ sound/core/control.c | 31 +++++++++++++++++++++++++------
+ sound/core/init.c | 1 +
+ 3 files changed, 28 insertions(+), 6 deletions(-)
+
+diff --git a/include/sound/core.h b/include/sound/core.h
+index 2a14f1f..d6bc961 100644
+--- a/include/sound/core.h
++++ b/include/sound/core.h
+@@ -121,6 +121,8 @@ struct snd_card {
+ int user_ctl_count; /* count of all user controls */
+ struct list_head controls; /* all controls for this card */
+ struct list_head ctl_files; /* active control files */
++ struct mutex user_ctl_lock; /* protects user controls against
++ concurrent access */
+
+ struct snd_info_entry *proc_root; /* root for soundcard specific files */
+ struct snd_info_entry *proc_id; /* the card id */
+diff --git a/sound/core/control.c b/sound/core/control.c
+index d8aa206..183fab2 100644
+--- a/sound/core/control.c
++++ b/sound/core/control.c
+@@ -992,6 +992,7 @@ static int snd_ctl_elem_unlock(struct snd_ctl_file *file,
+
+ struct user_element {
+ struct snd_ctl_elem_info info;
++ struct snd_card *card;
+ void *elem_data; /* element data */
+ unsigned long elem_data_size; /* size of element data in bytes */
+ void *tlv_data; /* TLV data */
+@@ -1035,7 +1036,9 @@ static int snd_ctl_elem_user_get(struct snd_kcontrol *kcontrol,
+ {
+ struct user_element *ue = kcontrol->private_data;
+
++ mutex_lock(&ue->card->user_ctl_lock);
+ memcpy(&ucontrol->value, ue->elem_data, ue->elem_data_size);
++ mutex_unlock(&ue->card->user_ctl_lock);
+ return 0;
+ }
+
+@@ -1044,10 +1047,12 @@ static int snd_ctl_elem_user_put(struct snd_kcontrol *kcontrol,
+ {
+ int change;
+ struct user_element *ue = kcontrol->private_data;
+-
++
++ mutex_lock(&ue->card->user_ctl_lock);
+ change = memcmp(&ucontrol->value, ue->elem_data, ue->elem_data_size) != 0;
+ if (change)
+ memcpy(ue->elem_data, &ucontrol->value, ue->elem_data_size);
++ mutex_unlock(&ue->card->user_ctl_lock);
+ return change;
+ }
+
+@@ -1067,19 +1072,32 @@ static int snd_ctl_elem_user_tlv(struct snd_kcontrol *kcontrol,
+ new_data = memdup_user(tlv, size);
+ if (IS_ERR(new_data))
+ return PTR_ERR(new_data);
++ mutex_lock(&ue->card->user_ctl_lock);
+ change = ue->tlv_data_size != size;
+ if (!change)
+ change = memcmp(ue->tlv_data, new_data, size);
+ kfree(ue->tlv_data);
+ ue->tlv_data = new_data;
+ ue->tlv_data_size = size;
++ mutex_unlock(&ue->card->user_ctl_lock);
+ } else {
+- if (! ue->tlv_data_size || ! ue->tlv_data)
+- return -ENXIO;
+- if (size < ue->tlv_data_size)
+- return -ENOSPC;
++ int ret = 0;
++
++ mutex_lock(&ue->card->user_ctl_lock);
++ if (!ue->tlv_data_size || !ue->tlv_data) {
++ ret = -ENXIO;
++ goto err_unlock;
++ }
++ if (size < ue->tlv_data_size) {
++ ret = -ENOSPC;
++ goto err_unlock;
++ }
+ if (copy_to_user(tlv, ue->tlv_data, ue->tlv_data_size))
+- return -EFAULT;
++ ret = -EFAULT;
++err_unlock:
++ mutex_unlock(&ue->card->user_ctl_lock);
++ if (ret)
++ return ret;
+ }
+ return change;
+ }
+@@ -1211,6 +1229,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
+ ue = kzalloc(sizeof(struct user_element) + private_size, GFP_KERNEL);
+ if (ue == NULL)
+ return -ENOMEM;
++ ue->card = card;
+ ue->info = *info;
+ ue->info.access = 0;
+ ue->elem_data = (char *)ue + sizeof(*ue);
+diff --git a/sound/core/init.c b/sound/core/init.c
+index d047851..b9268a5 100644
+--- a/sound/core/init.c
++++ b/sound/core/init.c
+@@ -215,6 +215,7 @@ int snd_card_create(int idx, const char *xid,
+ INIT_LIST_HEAD(&card->devices);
+ init_rwsem(&card->controls_rwsem);
+ rwlock_init(&card->ctl_files_rwlock);
++ mutex_init(&card->user_ctl_lock);
+ INIT_LIST_HEAD(&card->controls);
+ INIT_LIST_HEAD(&card->ctl_files);
+ spin_lock_init(&card->files_lock);
+--
+1.9.1
+
--- /dev/null
+From 0bf595fd311aa4d6e82c43879f2c0d0650e83271 Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Wed, 18 Jun 2014 13:32:33 +0200
+Subject: [PATCH] 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.
+
+This fixes CVE-2014-4653
+Upstream-Status: Backport
+
+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: Jiri Slaby <jslaby@suse.cz>
+Signed-off-by: Sona Sarmadi <sona.sarmadi@enea.com>
+---
+ sound/core/control.c | 15 ++++++++++-----
+ 1 file changed, 10 insertions(+), 5 deletions(-)
+
+diff --git a/sound/core/control.c b/sound/core/control.c
+index 15bc844..d4a597f 100644
+--- a/sound/core/control.c
++++ b/sound/core/control.c
+@@ -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 {
+--
+1.9.1
+