aboutsummaryrefslogtreecommitdiffstats
path: root/sound/core
diff options
context:
space:
mode:
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>2016-07-07 08:57:10 -0400
committerTakashi Iwai <tiwai@suse.de>2016-07-07 09:47:50 -0400
commit860c1994a70a0d2ab6f87fb7e72e722a8fb2c64c (patch)
treedcd1244adeac93bdd572b790d5945466df84fc58 /sound/core
parentb268c34e5ee92a4cc3099b0caaf26e6bfbdf0f18 (diff)
ALSA: control: add dimension validator for userspace elements
The 'dimen' field in struct snd_ctl_elem_info is used to compose all of members in the element as multi-dimensional matrix. The field has four members. Each member represents the width in each dimension level by element member unit. For example, if the members consist of typical two dimensional matrix, the dimen[0] represents the number of rows and dimen[1] represents the number of columns (or vise-versa). The total members in the matrix should be exactly the same as the number of members in the element, while current implementation has no validator of this information. In a view of userspace applications, the information must be valid so that it cannot cause any bugs such as buffer-over-run. This commit adds a validator of dimension information for userspace applications which add new element sets. When they add the element sets with wrong dimension information, they receive -EINVAL. Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp> Signed-off-by: Takashi Iwai <tiwai@suse.de>
Diffstat (limited to 'sound/core')
-rw-r--r--sound/core/control.c32
1 files changed, 32 insertions, 0 deletions
diff --git a/sound/core/control.c b/sound/core/control.c
index a85d45595d02..9ff081cd03f4 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -805,6 +805,36 @@ static int snd_ctl_elem_list(struct snd_card *card,
805 return 0; 805 return 0;
806} 806}
807 807
808static bool validate_element_member_dimension(struct snd_ctl_elem_info *info)
809{
810 unsigned int members;
811 unsigned int i;
812
813 if (info->dimen.d[0] == 0)
814 return true;
815
816 members = 1;
817 for (i = 0; i < ARRAY_SIZE(info->dimen.d); ++i) {
818 if (info->dimen.d[i] == 0)
819 break;
820 members *= info->dimen.d[i];
821
822 /*
823 * info->count should be validated in advance, to guarantee
824 * calculation soundness.
825 */
826 if (members > info->count)
827 return false;
828 }
829
830 for (++i; i < ARRAY_SIZE(info->dimen.d); ++i) {
831 if (info->dimen.d[i] > 0)
832 return false;
833 }
834
835 return members == info->count;
836}
837
808static int snd_ctl_elem_info(struct snd_ctl_file *ctl, 838static int snd_ctl_elem_info(struct snd_ctl_file *ctl,
809 struct snd_ctl_elem_info *info) 839 struct snd_ctl_elem_info *info)
810{ 840{
@@ -1272,6 +1302,8 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file,
1272 if (info->count < 1 || 1302 if (info->count < 1 ||
1273 info->count > max_value_counts[info->type]) 1303 info->count > max_value_counts[info->type])
1274 return -EINVAL; 1304 return -EINVAL;
1305 if (!validate_element_member_dimension(info))
1306 return -EINVAL;
1275 private_size = value_sizes[info->type] * info->count; 1307 private_size = value_sizes[info->type] * info->count;
1276 1308
1277 /* 1309 /*