diff options
author | Takashi Sakamoto <o-takashi@sakamocchi.jp> | 2016-07-08 06:33:17 +0900 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2016-07-07 23:48:41 +0200 |
commit | 025e451b833efeb0b930f9041c827ea244ea4586 (patch) | |
tree | adcf83983ded1ffcb19c14c846ea649a2d7ffdbd | |
parent | 3ef712844f3a93f34f269114e341915ae7efece2 (diff) | |
download | alsa-lib-025e451b833efeb0b930f9041c827ea244ea4586.tar.gz |
ctl: add dimension validator
Linux 4.7 or former have no validator of dimension information. This can
causes an issue related to user-defined element set. For example, When
calculated total members in multi-dimensional matrix is larger than actual
capacity of snd_ctl_elem_value_t, processes to handle the element can
cause buffer-over-run.
For backward portability of this userspace library, this commit adds a
validator of dimension information. When userspace applications give
invalid dimension information to APIs to add element set, they receive
-EINVAL.
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r-- | src/control/control.c | 42 |
1 files changed, 42 insertions, 0 deletions
diff --git a/src/control/control.c b/src/control/control.c index 2ad3e0d5..85485aac 100644 --- a/src/control/control.c +++ b/src/control/control.c @@ -91,6 +91,7 @@ I/O operations. #include <fcntl.h> #include <signal.h> #include <sys/poll.h> +#include <stdbool.h> #include "control_local.h" /** @@ -302,6 +303,32 @@ int snd_ctl_elem_info(snd_ctl_t *ctl, snd_ctl_elem_info_t *info) return ctl->ops->element_info(ctl, info); } +static bool validate_element_member_dimension(snd_ctl_elem_info_t *info) +{ + unsigned int members; + unsigned int i; + + if (info->dimen.d[0] == 0) + return true; + + members = 1; + for (i = 0; i < ARRAY_SIZE(info->dimen.d); ++i) { + if (info->dimen.d[i] == 0) + break; + members *= info->dimen.d[i]; + + if (members > info->count) + return false; + } + + for (++i; i < ARRAY_SIZE(info->dimen.d); ++i) { + if (info->dimen.d[i] > 0) + return false; + } + + return members == info->count; +} + /** * \brief Create and add some user-defined control elements of integer type. * \param ctl A handle of backend module for control interface. @@ -366,6 +393,9 @@ int snd_ctl_elem_add_integer_set(snd_ctl_t *ctl, snd_ctl_elem_info_t *info, info->value.integer.max = max; info->value.integer.step = step; + if (!validate_element_member_dimension(info)) + return -EINVAL; + err = ctl->ops->element_add(ctl, info); if (err < 0) return err; @@ -451,6 +481,9 @@ int snd_ctl_elem_add_integer64_set(snd_ctl_t *ctl, snd_ctl_elem_info_t *info, info->value.integer64.max = max; info->value.integer64.step = step; + if (!validate_element_member_dimension(info)) + return -EINVAL; + err = ctl->ops->element_add(ctl, info); if (err < 0) return err; @@ -524,6 +557,9 @@ int snd_ctl_elem_add_boolean_set(snd_ctl_t *ctl, snd_ctl_elem_info_t *info, info->value.integer.min = 0; info->value.integer.max = 1; + if (!validate_element_member_dimension(info)) + return -EINVAL; + return ctl->ops->element_add(ctl, info); } @@ -605,6 +641,9 @@ int snd_ctl_elem_add_enumerated_set(snd_ctl_t *ctl, snd_ctl_elem_info_t *info, p += strlen(labels[i]) + 1; } + if (!validate_element_member_dimension(info)) + return -EINVAL; + err = ctl->ops->element_add(ctl, info); free(buf); @@ -663,6 +702,9 @@ int snd_ctl_elem_add_bytes_set(snd_ctl_t *ctl, snd_ctl_elem_info_t *info, info->owner = element_count; info->count = member_count; + if (!validate_element_member_dimension(info)) + return -EINVAL; + return ctl->ops->element_add(ctl, info); } |