lkml.org 
[lkml]   [2019]   [Aug]   [22]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.19 12/85] ALSA: usb-audio: Fix a stack buffer overflow bug in check_input_term
    Date
    From: Hui Peng <benquike@gmail.com>

    commit 19bce474c45be69a284ecee660aa12d8f1e88f18 upstream.

    `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 and stop the execution if some id
    has been checked (similar to how parse_audio_unit handles unitid
    argument).

    Reported-by: Hui Peng <benquike@gmail.com>
    Reported-by: Mathias Payer <mathias.payer@nebelwelt.net>
    Signed-off-by: Hui Peng <benquike@gmail.com>
    Cc: <stable@vger.kernel.org>
    Signed-off-by: Takashi Iwai <tiwai@suse.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    sound/usb/mixer.c | 35 +++++++++++++++++++++++++++--------
    1 file changed, 27 insertions(+), 8 deletions(-)

    --- a/sound/usb/mixer.c
    +++ b/sound/usb/mixer.c
    @@ -83,6 +83,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;
    @@ -788,16 +789,25 @@ static int uac_mixer_unit_get_channels(s
    * 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,
    +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))
    + return -EINVAL;
    +
    + p1 = find_audio_control_unit(state, id);
    + if (!p1)
    + break;
    +
    + hdr = p1;
    term->id = id;

    if (protocol == UAC_VERSION_1 || protocol == UAC_VERSION_2) {
    @@ -815,7 +825,7 @@ static int check_input_term(struct mixer

    /* 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;

    @@ -849,7 +859,7 @@ static int check_input_term(struct mixer
    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 */
    @@ -912,7 +922,7 @@ static int check_input_term(struct mixer

    /* 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;

    @@ -963,7 +973,7 @@ static int check_input_term(struct mixer
    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 */
    @@ -979,7 +989,7 @@ static int check_input_term(struct mixer
    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;

    @@ -997,6 +1007,15 @@ static int check_input_term(struct mixer
    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
    */

    \
     
     \ /
      Last update: 2019-08-22 19:56    [W:4.206 / U:0.012 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site