]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.15-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 24 Jun 2014 14:36:27 +0000 (10:36 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 24 Jun 2014 14:36:27 +0000 (10:36 -0400)
added patches:
alsa-control-don-t-access-controls-outside-of-protected-regions.patch
alsa-control-fix-replacing-user-controls.patch
alsa-control-handle-numid-overflow.patch
alsa-control-make-sure-that-id-index-does-not-overflow.patch
alsa-control-protect-user-controls-against-concurrent-access.patch

queue-3.15/alsa-control-don-t-access-controls-outside-of-protected-regions.patch [new file with mode: 0644]
queue-3.15/alsa-control-fix-replacing-user-controls.patch [new file with mode: 0644]
queue-3.15/alsa-control-handle-numid-overflow.patch [new file with mode: 0644]
queue-3.15/alsa-control-make-sure-that-id-index-does-not-overflow.patch [new file with mode: 0644]
queue-3.15/alsa-control-protect-user-controls-against-concurrent-access.patch [new file with mode: 0644]
queue-3.15/series

diff --git a/queue-3.15/alsa-control-don-t-access-controls-outside-of-protected-regions.patch b/queue-3.15/alsa-control-don-t-access-controls-outside-of-protected-regions.patch
new file mode 100644 (file)
index 0000000..e85657a
--- /dev/null
@@ -0,0 +1,85 @@
+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 {
diff --git a/queue-3.15/alsa-control-fix-replacing-user-controls.patch b/queue-3.15/alsa-control-fix-replacing-user-controls.patch
new file mode 100644 (file)
index 0000000..75acd2b
--- /dev/null
@@ -0,0 +1,88 @@
+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;
diff --git a/queue-3.15/alsa-control-handle-numid-overflow.patch b/queue-3.15/alsa-control-handle-numid-overflow.patch
new file mode 100644 (file)
index 0000000..01dba5f
--- /dev/null
@@ -0,0 +1,40 @@
+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) {
diff --git a/queue-3.15/alsa-control-make-sure-that-id-index-does-not-overflow.patch b/queue-3.15/alsa-control-make-sure-that-id-index-does-not-overflow.patch
new file mode 100644 (file)
index 0000000..325898e
--- /dev/null
@@ -0,0 +1,37 @@
+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);
diff --git a/queue-3.15/alsa-control-protect-user-controls-against-concurrent-access.patch b/queue-3.15/alsa-control-protect-user-controls-against-concurrent-access.patch
new file mode 100644 (file)
index 0000000..02296a2
--- /dev/null
@@ -0,0 +1,129 @@
+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);
index 623a29b997604b7adff93bbedf31683de2efedd9..358fc164bdbe56553fdabd65bd62a7c01fce618b 100644 (file)
@@ -52,3 +52,8 @@ alsa-hda-realtek-add-support-of-alc891-codec.patch
 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