diff options
author | Takashi Iwai <tiwai@suse.de> | 2009-09-10 15:32:47 +0200 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-09-10 15:32:47 +0200 |
commit | f604529d0c1c24be025f47b591366e257ee75f66 (patch) | |
tree | 22f09696a541cb561e33e352e47259ff492261a6 /sound/core | |
parent | 124e39b34d9b38cde4cac02077d5b58f6c1f063e (diff) | |
parent | 18dd0aa5afea7dc33953aa87de696e39074bbf78 (diff) | |
download | op-kernel-dev-f604529d0c1c24be025f47b591366e257ee75f66.zip op-kernel-dev-f604529d0c1c24be025f47b591366e257ee75f66.tar.gz |
Merge branch 'topic/ctl-add-remove-fixes' into for-linus
* topic/ctl-add-remove-fixes:
sound: snd_ctl_remove_user_ctl: prevent removal of kernel controls
sound: snd_ctl_remove_unlocked_id: simplify user control counting
sound: snd_ctl_remove_unlocked_id: simplify error paths
sound: snd_ctl_elem_add: fix value count check
Diffstat (limited to 'sound/core')
-rw-r--r-- | sound/core/control.c | 34 |
1 files changed, 17 insertions, 17 deletions
diff --git a/sound/core/control.c b/sound/core/control.c index 17b8d47..a8b7fab 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -414,7 +414,7 @@ int snd_ctl_remove_id(struct snd_card *card, struct snd_ctl_elem_id *id) EXPORT_SYMBOL(snd_ctl_remove_id); /** - * snd_ctl_remove_unlocked_id - remove the unlocked control of the given id and release it + * snd_ctl_remove_user_ctl - remove and release the unlocked user control * @file: active control handle * @id: the control id to remove * @@ -423,8 +423,8 @@ EXPORT_SYMBOL(snd_ctl_remove_id); * * Returns 0 if successful, or a negative error code on failure. */ -static int snd_ctl_remove_unlocked_id(struct snd_ctl_file * file, - struct snd_ctl_elem_id *id) +static int snd_ctl_remove_user_ctl(struct snd_ctl_file * file, + struct snd_ctl_elem_id *id) { struct snd_card *card = file->card; struct snd_kcontrol *kctl; @@ -433,15 +433,23 @@ static int snd_ctl_remove_unlocked_id(struct snd_ctl_file * file, down_write(&card->controls_rwsem); kctl = snd_ctl_find_id(card, id); if (kctl == NULL) { - up_write(&card->controls_rwsem); - return -ENOENT; + ret = -ENOENT; + goto error; + } + if (!(kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_USER)) { + ret = -EINVAL; + goto error; } for (idx = 0; idx < kctl->count; idx++) if (kctl->vd[idx].owner != NULL && kctl->vd[idx].owner != file) { - up_write(&card->controls_rwsem); - return -EBUSY; + ret = -EBUSY; + goto error; } ret = snd_ctl_remove(card, kctl); + if (ret < 0) + goto error; + card->user_ctl_count--; +error: up_write(&card->controls_rwsem); return ret; } @@ -951,7 +959,7 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, if (card->user_ctl_count >= MAX_USER_CONTROLS) return -ENOMEM; - if (info->count > 1024) + if (info->count < 1) return -EINVAL; access = info->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE : (info->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE| @@ -1052,18 +1060,10 @@ static int snd_ctl_elem_remove(struct snd_ctl_file *file, struct snd_ctl_elem_id __user *_id) { struct snd_ctl_elem_id id; - int err; if (copy_from_user(&id, _id, sizeof(id))) return -EFAULT; - err = snd_ctl_remove_unlocked_id(file, &id); - if (! err) { - struct snd_card *card = file->card; - down_write(&card->controls_rwsem); - card->user_ctl_count--; - up_write(&card->controls_rwsem); - } - return err; + return snd_ctl_remove_user_ctl(file, &id); } static int snd_ctl_subscribe_events(struct snd_ctl_file *file, int __user *ptr) |