[alsa-devel] [PATCH 2/3] ALSA: control: add dimension validator for userspace element
Takashi Sakamoto
o-takashi at sakamocchi.jp
Wed Jul 6 15:07:41 CEST 2016
Sorry to be late. I had a short vacation.
On Jul 2 2016 16:56, Takashi Iwai wrote:
> On Fri, 01 Jul 2016 14:29:37 +0200,
> Takashi Sakamoto wrote:
>>
>> On Jul 1 2016 20:10, Takashi Sakamoto wrote:
>>> 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 within 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 at sakamocchi.jp>
>>> ---
>>> sound/core/control.c | 30 ++++++++++++++++++++++++++++++
>>> 1 file changed, 30 insertions(+)
>>>
>>> diff --git a/sound/core/control.c b/sound/core/control.c
>>> index a85d455..54da910 100644
>>> --- a/sound/core/control.c
>>> +++ b/sound/core/control.c
>>> @@ -805,6 +805,34 @@ 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 = 0;
>
> Unnecessary initialization.
>
>>> +
>>> + 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)
>>> + return false;
>>
>> Mmm... info->dimen.d is declared with 'unsigned short' type. Thus,
>> negative value check is needless...
>>
>> struct snd_ctl_elem_info {
>> ...
>> union {
>> unsigned short d[4];
>> ..
>> };
>> ...
>> };
>>
>> Please abandon this patchset. I'll post new one tomorrow.
>
> Indeed, somehow I overlooked it, too.
>
> While we're at it: maybe it's even safer to check more strictly the
> result whether it matches with info->count. I don't think there is
> any reason to have an unaligned info->count value when the dimen array
> is given. It must be a bug.
>
> That is:
>>> + 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 true;
>
> Here will be
> return members == info->count;
I don't mind to be strict here. It's the same as my initial idea (not
posted).
But here, I have a question related to next patch (3rd patch). The
validation logic depends on reliability of info->count. In a case of
user-defined control element set, info->count is validated in advance,
therefore it's reasonable. But in a case of each kernel driver,
info->count is not validated yet, here. Thus, reliability of the
calculation is lost, I think. The result depends on implementation of
each driver and it can bring disadvantages to userspace.
When I think back, this is the main reason that I'm unwilling to use
info->count for prevention of arithmetic overflow. If we apply the same
logic to each kernel drivers, we need more validators for info->count.
For example:
'''
static int snd_ctl_elem_info(struct snd_ctl_file *ctl,
struct snd_ctl_elem_info *info)
{
...
if (info->type < SNDRV_CTL_ELEM_TYPE_BOOLEAN ||
info->type > SNDRV_CTL_ELEM_TYPE_INTEGER64) {
dev_err(card->dev,
"This module has a bug of invalid element type.\n");
result = -ENODATA;
goto end;
}
if (info->count < 1 ||
info->count > max_element_members[info->type]) {
dev_err(card->dev,
"This module has a bug of invalid member count.\n");
result = -ENODATA;
goto end;
}
/* This is a driver bug. */
if (!validate_element_member_dimension(info)) {
dev_err(card->dev,
"This module has a bug of invalid dimention info.\n");
result = -ENODATA;
goto end;
}
...
'''
Assume 'max_element_members' is precomputed table about the maximum
number of members in an element, like:
http://git.kernel.org/cgit/linux/kernel/git/tiwai/sound.git/tree/sound/core/control.c#n1209
What do you think about it?
Regards
Takashi Sakamoto
More information about the Alsa-devel
mailing list