aboutsummaryrefslogtreecommitdiffstats
path: root/sound/core/control.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/core/control.c')
-rw-r--r--sound/core/control.c70
1 files changed, 25 insertions, 45 deletions
diff --git a/sound/core/control.c b/sound/core/control.c
index 6362da17ac3f..3c6be1452e35 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -747,65 +747,45 @@ static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl,
747static int snd_ctl_elem_list(struct snd_card *card, 747static int snd_ctl_elem_list(struct snd_card *card,
748 struct snd_ctl_elem_list __user *_list) 748 struct snd_ctl_elem_list __user *_list)
749{ 749{
750 struct list_head *plist;
751 struct snd_ctl_elem_list list; 750 struct snd_ctl_elem_list list;
752 struct snd_kcontrol *kctl; 751 struct snd_kcontrol *kctl;
753 struct snd_ctl_elem_id *dst, *id; 752 struct snd_ctl_elem_id id;
754 unsigned int offset, space, jidx; 753 unsigned int offset, space, jidx;
754 int err = 0;
755 755
756 if (copy_from_user(&list, _list, sizeof(list))) 756 if (copy_from_user(&list, _list, sizeof(list)))
757 return -EFAULT; 757 return -EFAULT;
758 offset = list.offset; 758 offset = list.offset;
759 space = list.space; 759 space = list.space;
760 /* try limit maximum space */ 760
761 if (space > 16384) 761 down_read(&card->controls_rwsem);
762 return -ENOMEM; 762 list.count = card->controls_count;
763 list.used = 0;
763 if (space > 0) { 764 if (space > 0) {
764 /* allocate temporary buffer for atomic operation */ 765 list_for_each_entry(kctl, &card->controls, list) {
765 dst = vmalloc(space * sizeof(struct snd_ctl_elem_id)); 766 if (offset >= kctl->count) {
766 if (dst == NULL) 767 offset -= kctl->count;
767 return -ENOMEM; 768 continue;
768 down_read(&card->controls_rwsem); 769 }
769 list.count = card->controls_count; 770 for (jidx = offset; jidx < kctl->count; jidx++) {
770 plist = card->controls.next; 771 snd_ctl_build_ioff(&id, kctl, jidx);
771 while (plist != &card->controls) { 772 if (copy_to_user(list.pids + list.used, &id,
772 if (offset == 0) 773 sizeof(id))) {
773 break; 774 err = -EFAULT;
774 kctl = snd_kcontrol(plist); 775 goto out;
775 if (offset < kctl->count) 776 }
776 break;
777 offset -= kctl->count;
778 plist = plist->next;
779 }
780 list.used = 0;
781 id = dst;
782 while (space > 0 && plist != &card->controls) {
783 kctl = snd_kcontrol(plist);
784 for (jidx = offset; space > 0 && jidx < kctl->count; jidx++) {
785 snd_ctl_build_ioff(id, kctl, jidx);
786 id++;
787 space--;
788 list.used++; 777 list.used++;
778 if (!--space)
779 goto out;
789 } 780 }
790 plist = plist->next;
791 offset = 0; 781 offset = 0;
792 } 782 }
793 up_read(&card->controls_rwsem);
794 if (list.used > 0 &&
795 copy_to_user(list.pids, dst,
796 list.used * sizeof(struct snd_ctl_elem_id))) {
797 vfree(dst);
798 return -EFAULT;
799 }
800 vfree(dst);
801 } else {
802 down_read(&card->controls_rwsem);
803 list.count = card->controls_count;
804 up_read(&card->controls_rwsem);
805 } 783 }
806 if (copy_to_user(_list, &list, sizeof(list))) 784 out:
807 return -EFAULT; 785 up_read(&card->controls_rwsem);
808 return 0; 786 if (!err && copy_to_user(_list, &list, sizeof(list)))
787 err = -EFAULT;
788 return err;
809} 789}
810 790
811static bool validate_element_member_dimension(struct snd_ctl_elem_info *info) 791static bool validate_element_member_dimension(struct snd_ctl_elem_info *info)