diff mbox

[alsa-lib,v2] ctl: add dimension validator

Message ID 1467927197-14454-1-git-send-email-o-takashi@sakamocchi.jp (mailing list archive)
State New, archived
Headers show

Commit Message

Takashi Sakamoto July 7, 2016, 9:33 p.m. UTC
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>
---
 src/control/control.c | 42 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

Comments

Takashi Iwai July 7, 2016, 9:49 p.m. UTC | #1
On Thu, 07 Jul 2016 23:33:17 +0200,
Takashi Sakamoto wrote:
> 
> 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>

Applied, thanks.


Takashi
diff mbox

Patch

diff --git a/src/control/control.c b/src/control/control.c
index 2ad3e0d..85485aa 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);
 }