Received: by 2002:a25:8b12:0:0:0:0:0 with SMTP id i18csp1762554ybl; Thu, 15 Aug 2019 00:27:43 -0700 (PDT) X-Google-Smtp-Source: APXvYqxaQH4zqgSZI5GUnSb+M04O0Iqary5GMS5gfibEt3npR4/AOfJ56I7jfxqBo16AHXWDWBU0 X-Received: by 2002:a63:e901:: with SMTP id i1mr2409767pgh.451.1565854063693; Thu, 15 Aug 2019 00:27:43 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1565854063; cv=none; d=google.com; s=arc-20160816; b=VXnnumlAXzBRjbcpfGgx4xedIhpSpQ/OA4+S3ACHvIyd3lTOnY13Oaw5sMe0TkpE/6 kDcL9vQAgjQdM561eiuPJl7PoPH6jaecXLGstHmXVUMbD0RIYTUKlD4k3bPwOVoQsO+K 8+WXQ1QRYCMmn1/UUv22K3D46gV1Sgt3bG5HkPLjolPTEnog8Cu9hukMD54VnjqnCmZZ mT3cHDPhZL4Qt8I526zt67e05j/D0/X2pi6BeYeyFEnsOXMOdWaGJ+rWotVb23ErQzz0 kYgPjPTqLVryVOgjCpQWsa8EXe7WaY9J7IYx9ggGWN1BCmKMkF3OMFT8Ug5jm/zw71Z6 4Uqg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:mime-version:user-agent:references :in-reply-to:subject:cc:to:from:message-id:date; bh=Dt7Q91hvfVdrGOIhMwz8FlGsAYHLEMeB2xPxrRqrM70=; b=nsS9c6xosDnykz8pl3jhHL4hEU2t9jmxT2eenSehfksxTmg0zzYBy5mpyQpLgaODvt ewcbhq3xXMgL/q6EwpxD48f1SW1FBADuPrUy82SSwcTHU/Vy4uk6uTTitGnaVuB7iBxW eyaMVkcgrN/rFe8HlwetWrFOy3X27Ht1azpplgcKaBDOia3Nd3kzZzW1tJU9RCDD+6+J 7ZzpbKxhBks3RXF6RJuC/V/aKpJ2Xnlal3t/OlIe3N8idQBR5XPsIsZPc5ySaFNC2Gv6 V6T6Snj1N0JZvHn02M19U1WJFp6RBFcEDlklzTXi9E1kWLo3AblUVsjHP72TvO2d5V6b tuAA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id s21si1450520pfe.204.2019.08.15.00.27.26; Thu, 15 Aug 2019 00:27:43 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729967AbfHOGOA (ORCPT + 99 others); Thu, 15 Aug 2019 02:14:00 -0400 Received: from mx2.suse.de ([195.135.220.15]:38584 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1725977AbfHOGOA (ORCPT ); Thu, 15 Aug 2019 02:14:00 -0400 X-Virus-Scanned: by amavisd-new at test-mx.suse.de Received: from relay2.suse.de (unknown [195.135.220.254]) by mx1.suse.de (Postfix) with ESMTP id 01415AC68; Thu, 15 Aug 2019 06:13:57 +0000 (UTC) Date: Thu, 15 Aug 2019 08:13:57 +0200 Message-ID: From: Takashi Iwai To: "Hui Peng" Cc: , , "YueHaibing" , "Thomas Gleixner" , "Allison Randal" , "Mathias Payer" , "Jaroslav Kysela" , "Takashi Iwai" , "Wenwen Wang" , Subject: Re: [PATCH] Fix a stack buffer overflow bug check_input_term In-Reply-To: <20190815043554.16623-1-benquike@gmail.com> References: <20190815043554.16623-1-benquike@gmail.com> User-Agent: Wanderlust/2.15.9 (Almost Unreal) SEMI/1.14.6 (Maruoka) FLIM/1.14.9 (=?UTF-8?B?R29qxY0=?=) APEL/10.8 Emacs/25.3 (x86_64-suse-linux-gnu) MULE/6.0 (HANACHIRUSATO) MIME-Version: 1.0 (generated by SEMI 1.14.6 - "Maruoka") Content-Type: text/plain; charset=US-ASCII Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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? thanks, Takashi --- 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; @@ -773,14 +774,15 @@ 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; - memset(term, 0, sizeof(*term)); + if (test_and_set_bit(id, state->termbitmap)) + return 0; while ((p1 = find_audio_control_unit(state, id)) != NULL) { unsigned char *hdr = p1; term->id = id; @@ -800,7 +802,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; @@ -834,7 +836,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 */ @@ -897,7 +899,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; @@ -948,7 +950,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 */ @@ -964,7 +966,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; @@ -982,6 +984,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 */