[alsa-devel] [PATCH] Fix a stack buffer overflow bug check_input_term
Hui Peng
benquike at gmail.com
Thu Aug 15 20:11:50 CEST 2019
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
Hi, Takashi:
The new patch is confirmed (I made it to return -EINVAL if a endless
recursive call is detected).
Can you have a look.
Thanks.
On 8/15/19 1:38 PM, Takashi Iwai wrote:
> On Thu, 15 Aug 2019 19:19:10 +0200,
> Hui Peng wrote:
>> Hi, Takashi:
>>
>> One point I want to be clear: if an endless recursive loop is
detected, should
>> we return 0, or a negative error code?
> An error might be more appropriate, but it's no big deal, as you'll
> likely hit other errors sooner or later at parsing further :)
>
>
> thanks,
>
> Takashi
>
>> On Thu, Aug 15, 2019 at 2:58 AM Takashi Iwai wrote:
>>
>> On Thu, 15 Aug 2019 08:13:57 +0200,
>> Takashi Iwai wrote:
>> >
>> > On Thu, 15 Aug 2019 06:35:49 +0200,
>> > Hui Peng wrote:
>> > >
>> > > `check_input_term` recursively calls itself with input
>> > > from device side (e.g., uac_input_terminal_descriptor.bCSourceID)
>> > > as argument (id). In `check_input_term`, if `check_input_term`
>> > > is called with the same `id` argument as the caller, it triggers
>> > > endless recursive call, resulting kernel space stack overflow.
>> > >
>> > > This patch fixes the bug by adding a bitmap to `struct mixer_build`
>> > > to keep track of the checked ids by `check_input_term` and stop
>> > > the execution if some id has been checked (similar to how
>> > > parse_audio_unit handles unitid argument).
>> > >
>> > > Reported-by: Hui Peng
>> > > Reported-by: Mathias Payer
>> > > Signed-off-by: Hui Peng
>> >
>> > The fix looks almost good, but we need to be careful about the
>> > bitmap check. In theory, it's possible that multiple nodes point to
>> > the same input terminal, and your patch would break that scenario.
>> > For fixing that, we need to zero-clear the termbitmap at each first
>> > invocation of check_input_term(), something like below.
>> >
>> > Could you check whether this works?
>>
>> Thinking of this further, there is another possible infinite loop.
>> Namely, when the feature unit in the input terminal chain points to
>> itself as the source, it'll loop endlessly without the stack
>> overflow.
>>
>> So the check of the termbitmap should be inside the loop.
>> The revised patch is below.
>>
>> thanks,
>>
>> Takashi
>>
>> -- 8< --
>> From: Hui Peng
>> Subject: [PATCH] ALSA: usb-audio: Fix a stack buffer overflow bug
>> check_input_term
>>
>> `check_input_term` recursively calls itself with input
>> from device side (e.g., uac_input_terminal_descriptor.bCSourceID)
>> as argument (id). In `check_input_term`, if `check_input_term`
>> is called with the same `id` argument as the caller, it triggers
>> endless recursive call, resulting kernel space stack overflow.
>>
>> This patch fixes the bug by adding a bitmap to `struct mixer_build`
>> to keep track of the checked ids by `check_input_term` and stop
>> the execution if some id has been checked (similar to how
>> parse_audio_unit handles unitid argument).
>>
>> [ The termbitmap needs to be cleared at each first check of the input
>> terminal, so the function got split now. Also, for catching another
>> endless loop in the input terminal chain -- where the feature unit
>> points to itself as its source -- the termbitmap check is moved
>> inside the parser loop. -- tiwai ]
>>
>> Reported-by: Hui Peng
>> Reported-by: Mathias Payer
>> Signed-off-by: Hui Peng
>> Cc:
>> Signed-off-by: Takashi Iwai
>> ---
>> sound/usb/mixer.c | 36 ++++++++++++++++++++++++++----------
>> 1 file changed, 26 insertions(+), 10 deletions(-)
>>
>> diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
>> index ea487378be17..aa8b046aa91f 100644
>> --- a/sound/usb/mixer.c
>> +++ b/sound/usb/mixer.c
>> @@ -68,6 +68,7 @@ struct mixer_build {
>> unsigned char *buffer;
>> unsigned int buflen;
>> DECLARE_BITMAP(unitbitmap, MAX_ID_ELEMS);
>> + DECLARE_BITMAP(termbitmap, MAX_ID_ELEMS);
>> struct usb_audio_term oterm;
>> const struct usbmix_name_map *map;
>> const struct usbmix_selector_map *selector_map;
>> @@ -775,16 +776,23 @@ static int uac_mixer_unit_get_channels(struct
>> mixer_build *state,
>> * parse the source unit recursively until it reaches to a terminal
>> * or a branched unit.
>> */
>> -static int check_input_term(struct mixer_build *state, int id,
>> - struct usb_audio_term *term)
>> +static int __check_input_term(struct mixer_build *state, int id,
>> + struct usb_audio_term *term)
>> {
>> int protocol = state->mixer->protocol;
>> int err;
>> void *p1;
>> + unsigned char *hdr;
>>
>> - memset(term, 0, sizeof(*term));
>> - while ((p1 = find_audio_control_unit(state, id)) != NULL) {
>> - unsigned char *hdr = p1;
>> + for (;;) {
>> + /* a loop in the terminal chain? */
>> + if (test_and_set_bit(id, state->termbitmap))
>> + break;
>> +
>> + p1 = find_audio_control_unit(state, id);
>> + if (!p1)
>> + break;
>> + hdr = p1;
>> term->id = id;
>>
>> if (protocol == UAC_VERSION_1 || protocol ==
>> UAC_VERSION_2) {
>> @@ -802,7 +810,7 @@ static int check_input_term(struct mixer_build
*state,
>> int id,
>>
>> /* call recursively to verify
that
>> the
>> * referenced clock entity is
>> valid */
>> - err = check_input_term(state, d->
>> bCSourceID, term);
>> + err = __check_input_term(state,
>> d->bCSourceID, term);
>> if (err < 0)
>> return err;
>>
>> @@ -836,7 +844,7 @@ static int check_input_term(struct mixer_build
*state,
>> int id,
>> case UAC2_CLOCK_SELECTOR: {
>> struct uac_selector_unit_descriptor *d =
>> p1;
>> /* call recursively to retrieve the
>> channel info */
>> - err = check_input_term(state, d->
>> baSourceID[0], term);
>> + err = __check_input_term(state, d->
>> baSourceID[0], term);
>> if (err < 0)
>> return err;
>> term->type = UAC3_SELECTOR_UNIT << 16; /*
>> virtual type */
>> @@ -899,7 +907,7 @@ static int check_input_term(struct mixer_build
*state,
>> int id,
>>
>> /* call recursively to verify that the
>> * referenced clock entity is valid */
>> - err = check_input_term(state, d->
>> bCSourceID, term);
>> + err = __check_input_term(state, d->
>> bCSourceID, term);
>> if (err < 0)
>> return err;
>>
>> @@ -950,7 +958,7 @@ static int check_input_term(struct mixer_build
*state,
>> int id,
>> case UAC3_CLOCK_SELECTOR: {
>> struct uac_selector_unit_descriptor *d =
>> p1;
>> /* call recursively to retrieve the
>> channel info */
>> - err = check_input_term(state, d->
>> baSourceID[0], term);
>> + err = __check_input_term(state, d->
>> baSourceID[0], term);
>> if (err < 0)
>> return err;
>> term->type = UAC3_SELECTOR_UNIT << 16; /*
>> virtual type */
>> @@ -966,7 +974,7 @@ static int check_input_term(struct mixer_build
*state,
>> int id,
>> return -EINVAL;
>>
>> /* call recursively to retrieve the
>> channel info */
>> - err = check_input_term(state, d->
>> baSourceID[0], term);
>> + err = __check_input_term(state, d->
>> baSourceID[0], term);
>> if (err < 0)
>> return err;
>>
>> @@ -984,6 +992,14 @@ static int check_input_term(struct mixer_build
>> *state, int id,
>> return -ENODEV;
>> }
>>
>> +static int check_input_term(struct mixer_build *state, int id,
>> + struct usb_audio_term *term)
>> +{
>> + memset(term, 0, sizeof(*term));
>> + memset(state->termbitmap, 0, sizeof(state->termbitmap));
>> + return __check_input_term(state, id, term);
>> +}
>> +
>> /*
>> * Feature Unit
>> */
>> --
>> 2.16.4
>>
>>
-----BEGIN PGP SIGNATURE-----
iQEzBAEBCgAdFiEE1BqveDE4xg/g0AwHIp/nqknaPR4FAl1VoGYACgkQIp/nqkna
PR7begf/VLHveyoRopqc2MMhJ7aSH9837dNvss2JV/QVvUrdRvpKDpLNLx9EkxSu
U8FXWTl7HImaDBszTwtOJG8Peh/6L8G3ouAtiFIMhq9AsLqMOKS2p3wIvkJwGiCM
hjSZ3U7A8jaIjdUnUz2bVMvLVLfZH7dI8kIUuKtqh7qtBBnRL6w2RhfO1GdMnxvU
etczHfl4anKuQbfMZpI9Xv1ruFkYewUQOBhK4Kp/De00GqqtaINm73WYVqY3gf6I
Txk8zrLBsgFk3wJI6qi1NeITiZ4z8kd7wJL84rj8PraqtFpmkn7p7QfVzDSLibvP
V2HZfnaVwXrAf/FZrxYjpqfoZH44JA==
=MKbq
-----END PGP SIGNATURE-----
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-Fix-a-stack-buffer-overflow-bug-in-check_input_term.patch
Type: text/x-patch
Size: 4555 bytes
Desc: not available
URL: <http://mailman.alsa-project.org/pipermail/alsa-devel/attachments/20190815/af3bd6fb/attachment.bin>
More information about the Alsa-devel
mailing list