Skip to content

Commit

Permalink
ALSA: control: add dimension validator for userspace elements
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Takashi Sakamoto authored and Takashi Iwai committed Jul 7, 2016
1 parent b268c34 commit 860c199
Showing 1 changed file with 32 additions and 0 deletions.
32 changes: 32 additions & 0 deletions sound/core/control.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down Expand Up @@ -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;

/*
Expand Down

0 comments on commit 860c199

Please sign in to comment.