ACK: [Lucid][CVE-2014-4652] ALSA: control: Protect user controls against concurrent access
Brad Figg
brad.figg at canonical.com
Thu Jul 17 16:44:52 UTC 2014
On 07/17/2014 08:59 AM, Luis Henriques wrote:
> From: Lars-Peter Clausen <lars at metafoo.de>
>
> 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 at metafoo.de>
> Acked-by: Jaroslav Kysela <perex at perex.cz>
> Cc: <stable at vger.kernel.org>
> Signed-off-by: Takashi Iwai <tiwai at suse.de>
> (cherry picked from commit 07f4d9d74a04aa7c72c5dae0ef97565f28f17b92)
> CVE-2014-4652
> BugLink: http://bugs.launchpad.net/bugs/1339294
> Signed-off-by: Luis Henriques <luis.henriques at canonical.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 a61499c22b0b..3ad641cdc735 100644
> --- 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 */
> diff --git a/sound/core/control.c b/sound/core/control.c
> index 7834a5438f75..b5266f7a1a0a 100644
> --- a/sound/core/control.c
> +++ b/sound/core/control.c
> @@ -873,6 +873,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 */
> @@ -895,7 +896,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;
> }
>
> @@ -904,10 +907,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;
> }
>
> @@ -927,19 +932,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;
> }
> @@ -1028,6 +1046,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 82f350e00cbe..fd8590fefbd9 100644
> --- a/sound/core/init.c
> +++ b/sound/core/init.c
> @@ -206,6 +206,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);
>
--
Brad Figg brad.figg at canonical.com http://www.canonical.com
More information about the kernel-team
mailing list