--- /dev/null
+From fd9f26e4eca5d08a27d12c0933fceef76ed9663d Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Wed, 18 Jun 2014 13:32:33 +0200
+Subject: ALSA: control: Don't access controls outside of protected regions
+
+From: Lars-Peter Clausen <lars@metafoo.de>
+
+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>
+Signed-off-by: Takashi Iwai <tiwai@suse.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ sound/core/control.c | 15 ++++++++++-----
+ 1 file changed, 10 insertions(+), 5 deletions(-)
+
+--- a/sound/core/control.c
++++ b/sound/core/control.c
+@@ -330,6 +330,7 @@ int snd_ctl_add(struct snd_card *card, s
+ {
+ 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, s
+ 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 *car
+ 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
+ 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_
+ }
+ 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 {
--- /dev/null
+From 82262a46627bebb0febcc26664746c25cef08563 Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Wed, 18 Jun 2014 13:32:32 +0200
+Subject: ALSA: control: Fix replacing user controls
+
+From: Lars-Peter Clausen <lars@metafoo.de>
+
+commit 82262a46627bebb0febcc26664746c25cef08563 upstream.
+
+There are two issues with the current implementation for replacing user
+controls. The first is that the code does not check if the control is actually a
+user control and neither does it check if the control is owned by the process
+that tries to remove it. That allows userspace applications to remove arbitrary
+controls, which can cause a user after free if a for example a driver does not
+expect a control to be removed from under its feed.
+
+The second issue is that on one hand when a control is replaced the
+user_ctl_count limit is not checked and on the other hand the user_ctl_count is
+increased (even though the number of user controls does not change). This allows
+userspace, once the user_ctl_count limit as been reached, to repeatedly replace
+a control until user_ctl_count overflows. Once that happens new controls can be
+added effectively bypassing the user_ctl_count limit.
+
+Both issues can be fixed by instead of open-coding the removal of the control
+that is to be replaced to use snd_ctl_remove_user_ctl(). This function does
+proper permission checks as well as decrements user_ctl_count after the control
+has been removed.
+
+Note that by using snd_ctl_remove_user_ctl() the check which returns -EBUSY at
+beginning of the function if the control already exists is removed. This is not
+a problem though since the check is quite useless, because the lock that is
+protecting the control list is released between the check and before adding the
+new control to the list, which means that it is possible that a different
+control with the same settings is added to the list after the check. Luckily
+there is another check that is done while holding the lock in snd_ctl_add(), so
+we'll rely on that to make sure that the same control is not added twice.
+
+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>
+
+---
+ sound/core/control.c | 25 +++++++++----------------
+ 1 file changed, 9 insertions(+), 16 deletions(-)
+
+--- a/sound/core/control.c
++++ b/sound/core/control.c
+@@ -1154,8 +1154,6 @@ static int snd_ctl_elem_add(struct snd_c
+ struct user_element *ue;
+ int idx, err;
+
+- if (!replace && card->user_ctl_count >= MAX_USER_CONTROLS)
+- return -ENOMEM;
+ if (info->count < 1)
+ return -EINVAL;
+ access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE :
+@@ -1164,21 +1162,16 @@ static int snd_ctl_elem_add(struct snd_c
+ SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE));
+ info->id.numid = 0;
+ memset(&kctl, 0, sizeof(kctl));
+- down_write(&card->controls_rwsem);
+- _kctl = snd_ctl_find_id(card, &info->id);
+- err = 0;
+- if (_kctl) {
+- if (replace)
+- err = snd_ctl_remove(card, _kctl);
+- else
+- err = -EBUSY;
+- } else {
+- if (replace)
+- err = -ENOENT;
++
++ if (replace) {
++ err = snd_ctl_remove_user_ctl(file, &info->id);
++ if (err)
++ return err;
+ }
+- up_write(&card->controls_rwsem);
+- if (err < 0)
+- return err;
++
++ if (card->user_ctl_count >= MAX_USER_CONTROLS)
++ return -ENOMEM;
++
+ memcpy(&kctl.id, &info->id, sizeof(info->id));
+ kctl.count = info->owner ? info->owner : 1;
+ access |= SNDRV_CTL_ELEM_ACCESS_USER;
--- /dev/null
+From ac902c112d90a89e59916f751c2745f4dbdbb4bd Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Wed, 18 Jun 2014 13:32:34 +0200
+Subject: ALSA: control: Handle numid overflow
+
+From: Lars-Peter Clausen <lars@metafoo.de>
+
+commit ac902c112d90a89e59916f751c2745f4dbdbb4bd upstream.
+
+Each control gets automatically assigned its numids when the control is created.
+The allocation is done by incrementing the numid by the amount of allocated
+numids per allocation. This means that excessive creation and destruction of
+controls (e.g. via SNDRV_CTL_IOCTL_ELEM_ADD/REMOVE) can cause the id to
+eventually overflow. Currently when this happens for the control that caused the
+overflow kctl->id.numid + kctl->count will also over flow causing it to be
+smaller than kctl->id.numid. Most of the code assumes that this is something
+that can not happen, so we need to make sure that it won't happen
+
+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>
+
+---
+ sound/core/control.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/sound/core/control.c
++++ b/sound/core/control.c
+@@ -288,6 +288,10 @@ static bool snd_ctl_remove_numid_conflic
+ {
+ struct snd_kcontrol *kctl;
+
++ /* Make sure that the ids assigned to the control do not wrap around */
++ if (card->last_numid >= UINT_MAX - count)
++ card->last_numid = 0;
++
+ list_for_each_entry(kctl, &card->controls, list) {
+ if (kctl->id.numid < card->last_numid + 1 + count &&
+ kctl->id.numid + kctl->count > card->last_numid + 1) {
--- /dev/null
+From 883a1d49f0d77d30012f114b2e19fc141beb3e8e Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Wed, 18 Jun 2014 13:32:35 +0200
+Subject: ALSA: control: Make sure that id->index does not overflow
+
+From: Lars-Peter Clausen <lars@metafoo.de>
+
+commit 883a1d49f0d77d30012f114b2e19fc141beb3e8e upstream.
+
+The ALSA control code expects that the range of assigned indices to a control is
+continuous and does not overflow. Currently there are no checks to enforce this.
+If a control with a overflowing index range is created that control becomes
+effectively inaccessible and unremovable since snd_ctl_find_id() will not be
+able to find it. This patch adds a check that makes sure that controls with a
+overflowing index range can not be created.
+
+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>
+
+---
+ sound/core/control.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/sound/core/control.c
++++ b/sound/core/control.c
+@@ -342,6 +342,9 @@ int snd_ctl_add(struct snd_card *card, s
+ if (snd_BUG_ON(!card || !kcontrol->info))
+ goto error;
+ id = kcontrol->id;
++ if (id.index > UINT_MAX - kcontrol->count)
++ goto error;
++
+ down_write(&card->controls_rwsem);
+ if (snd_ctl_find_id(card, &id)) {
+ up_write(&card->controls_rwsem);
--- /dev/null
+From 07f4d9d74a04aa7c72c5dae0ef97565f28f17b92 Mon Sep 17 00:00:00 2001
+From: Lars-Peter Clausen <lars@metafoo.de>
+Date: Wed, 18 Jun 2014 13:32:31 +0200
+Subject: ALSA: control: Protect user controls against concurrent access
+
+From: Lars-Peter Clausen <lars@metafoo.de>
+
+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.
+
+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>
+
+---
+ include/sound/core.h | 2 ++
+ sound/core/control.c | 31 +++++++++++++++++++++++++------
+ sound/core/init.c | 1 +
+ 3 files changed, 28 insertions(+), 6 deletions(-)
+
+--- a/include/sound/core.h
++++ b/include/sound/core.h
+@@ -116,6 +116,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 */
+--- a/sound/core/control.c
++++ b/sound/core/control.c
+@@ -991,6 +991,7 @@ static int snd_ctl_elem_unlock(struct sn
+
+ 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 */
+@@ -1034,7 +1035,9 @@ static int snd_ctl_elem_user_get(struct
+ {
+ 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;
+ }
+
+@@ -1043,10 +1046,12 @@ static int snd_ctl_elem_user_put(struct
+ {
+ 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;
+ }
+
+@@ -1066,19 +1071,32 @@ static int snd_ctl_elem_user_tlv(struct
+ 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;
+ }
+@@ -1210,6 +1228,7 @@ static int snd_ctl_elem_add(struct snd_c
+ 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);
+--- a/sound/core/init.c
++++ b/sound/core/init.c
+@@ -232,6 +232,7 @@ int snd_card_new(struct device *parent,
+ 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);
alsa-hda-realtek-add-more-entry-for-enable-hp-mute-led.patch
alsa-hda-verify-pin-converter-connection-on-unsol-event-for-hsw-and-vlv.patch
alsa-hda-add-quirk-for-external-mic-on-lifebook-u904.patch
+alsa-control-protect-user-controls-against-concurrent-access.patch
+alsa-control-fix-replacing-user-controls.patch
+alsa-control-don-t-access-controls-outside-of-protected-regions.patch
+alsa-control-handle-numid-overflow.patch
+alsa-control-make-sure-that-id-index-does-not-overflow.patch