From: Greg Kroah-Hartman Date: Tue, 24 Jun 2014 14:36:09 +0000 (-0400) Subject: 3.10-stable patches X-Git-Tag: v3.4.95~6 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=76ff10f7ab86c1f932a8063ca856bbfd18fe61ef;p=thirdparty%2Fkernel%2Fstable-queue.git 3.10-stable patches 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 --- diff --git a/queue-3.10/alsa-control-don-t-access-controls-outside-of-protected-regions.patch b/queue-3.10/alsa-control-don-t-access-controls-outside-of-protected-regions.patch new file mode 100644 index 00000000000..b9435a44ad0 --- /dev/null +++ b/queue-3.10/alsa-control-don-t-access-controls-outside-of-protected-regions.patch @@ -0,0 +1,85 @@ +From fd9f26e4eca5d08a27d12c0933fceef76ed9663d Mon Sep 17 00:00:00 2001 +From: Lars-Peter Clausen +Date: Wed, 18 Jun 2014 13:32:33 +0200 +Subject: ALSA: control: Don't access controls outside of protected regions + +From: Lars-Peter Clausen + +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 +Acked-by: Jaroslav Kysela +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman + +--- + sound/core/control.c | 15 ++++++++++----- + 1 file changed, 10 insertions(+), 5 deletions(-) + +--- a/sound/core/control.c ++++ b/sound/core/control.c +@@ -331,6 +331,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) +@@ -359,8 +360,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; + +@@ -389,6 +391,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; +@@ -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 + 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_ + } + 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.10/alsa-control-fix-replacing-user-controls.patch b/queue-3.10/alsa-control-fix-replacing-user-controls.patch new file mode 100644 index 00000000000..ea433e252ac --- /dev/null +++ b/queue-3.10/alsa-control-fix-replacing-user-controls.patch @@ -0,0 +1,88 @@ +From 82262a46627bebb0febcc26664746c25cef08563 Mon Sep 17 00:00:00 2001 +From: Lars-Peter Clausen +Date: Wed, 18 Jun 2014 13:32:32 +0200 +Subject: ALSA: control: Fix replacing user controls + +From: Lars-Peter Clausen + +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 +Acked-by: Jaroslav Kysela +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman + +--- + sound/core/control.c | 25 +++++++++---------------- + 1 file changed, 9 insertions(+), 16 deletions(-) + +--- a/sound/core/control.c ++++ b/sound/core/control.c +@@ -1155,8 +1155,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 : +@@ -1165,21 +1163,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.10/alsa-control-handle-numid-overflow.patch b/queue-3.10/alsa-control-handle-numid-overflow.patch new file mode 100644 index 00000000000..443a2aba54a --- /dev/null +++ b/queue-3.10/alsa-control-handle-numid-overflow.patch @@ -0,0 +1,40 @@ +From ac902c112d90a89e59916f751c2745f4dbdbb4bd Mon Sep 17 00:00:00 2001 +From: Lars-Peter Clausen +Date: Wed, 18 Jun 2014 13:32:34 +0200 +Subject: ALSA: control: Handle numid overflow + +From: Lars-Peter Clausen + +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 +Acked-by: Jaroslav Kysela +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman + +--- + sound/core/control.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/sound/core/control.c ++++ b/sound/core/control.c +@@ -289,6 +289,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.10/alsa-control-make-sure-that-id-index-does-not-overflow.patch b/queue-3.10/alsa-control-make-sure-that-id-index-does-not-overflow.patch new file mode 100644 index 00000000000..4d732004046 --- /dev/null +++ b/queue-3.10/alsa-control-make-sure-that-id-index-does-not-overflow.patch @@ -0,0 +1,37 @@ +From 883a1d49f0d77d30012f114b2e19fc141beb3e8e Mon Sep 17 00:00:00 2001 +From: Lars-Peter Clausen +Date: Wed, 18 Jun 2014 13:32:35 +0200 +Subject: ALSA: control: Make sure that id->index does not overflow + +From: Lars-Peter Clausen + +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 +Acked-by: Jaroslav Kysela +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman + +--- + sound/core/control.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/sound/core/control.c ++++ b/sound/core/control.c +@@ -343,6 +343,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.10/alsa-control-protect-user-controls-against-concurrent-access.patch b/queue-3.10/alsa-control-protect-user-controls-against-concurrent-access.patch new file mode 100644 index 00000000000..a42a82da1eb --- /dev/null +++ b/queue-3.10/alsa-control-protect-user-controls-against-concurrent-access.patch @@ -0,0 +1,129 @@ +From 07f4d9d74a04aa7c72c5dae0ef97565f28f17b92 Mon Sep 17 00:00:00 2001 +From: Lars-Peter Clausen +Date: Wed, 18 Jun 2014 13:32:31 +0200 +Subject: ALSA: control: Protect user controls against concurrent access + +From: Lars-Peter Clausen + +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 +Acked-by: Jaroslav Kysela +Signed-off-by: Takashi Iwai +Signed-off-by: Greg Kroah-Hartman + +--- + 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 +@@ -120,6 +120,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 +@@ -992,6 +992,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 */ +@@ -1035,7 +1036,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; + } + +@@ -1044,10 +1047,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; + } + +@@ -1067,19 +1072,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; + } +@@ -1211,6 +1229,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 +@@ -208,6 +208,7 @@ int snd_card_create(int idx, const char + 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); diff --git a/queue-3.10/series b/queue-3.10/series index b6e086d4df0..1d3e9d94b9b 100644 --- a/queue-3.10/series +++ b/queue-3.10/series @@ -45,3 +45,8 @@ nohz-fix-another-inconsistency-between-config_no_hz-n-and-nohz-off.patch alsa-compress-cancel-the-optimization-of-compiler-and-fix.patch alsa-hda-realtek-add-support-of-alc891-codec.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