diff options
Diffstat (limited to 'sound/core')
-rw-r--r-- | sound/core/control.c | 32 |
1 files changed, 32 insertions, 0 deletions
diff --git a/sound/core/control.c b/sound/core/control.c index a85d455..9ff081c 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, return 0; } +static bool validate_element_member_dimension(struct snd_ctl_elem_info *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]; + + /* + * info->count should be validated in advance, to guarantee + * calculation soundness. + */ + 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; +} + static int snd_ctl_elem_info(struct snd_ctl_file *ctl, struct snd_ctl_elem_info *info) { @@ -1272,6 +1302,8 @@ static int snd_ctl_elem_add(struct snd_ctl_file *file, if (info->count < 1 || info->count > max_value_counts[info->type]) return -EINVAL; + if (!validate_element_member_dimension(info)) + return -EINVAL; private_size = value_sizes[info->type] * info->count; /* |