Received: by 2002:a25:8b12:0:0:0:0:0 with SMTP id i18csp727365ybl; Sat, 17 Aug 2019 09:19:47 -0700 (PDT) X-Google-Smtp-Source: APXvYqz3r0qCK42phtGBiZOgAajbvoV2XsS4zwiPXyHa0f39Tgmh9OSCZORA/ogMg/2jyYXHsPGh X-Received: by 2002:a62:8344:: with SMTP id h65mr16317469pfe.85.1566058787772; Sat, 17 Aug 2019 09:19:47 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1566058787; cv=none; d=google.com; s=arc-20160816; b=qHMdH4PAsIHOCtHqbs++c7xIrSTIMg3QbwhQb7TS4Wb8NschO2XDogItabQQEym1x7 spfTWIE3eG9pLW3P+ieVOvLTso7TINJUmih6HlcDMjJgY8+YHolgnT6bkbNXoBHbiZWk YMH7oLow1SQh8fqYusMEuQyKdYOQVSWTJVvsYCdhDlV2atWTPuXJ9KFuxcaVRFp2RsTE GvLL7xcs482VxOP0d6zJIUYsjY9bG32HQsnQG+P+iZuJG6KfNVFhc1fLWTaIQo7AwxGy CXLkL0fMGSrSc1R1iqoetfHxEG8Jc3BkfqmgM1eyhEXz/0LaoUQZs23uJqTmNiEyzwny UtYA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:subject:cc:to:from:message-id :date; bh=zM1oxIRWPXyT4i1Ermt6j6KU7nCz08uMO73P+bWGrVc=; b=vITLuxQXTd1h8OuB+CrCQOUtVAFZbJgcBoiM/bQ2FIu5q6z+GoUrTn2SKw65SSqsDX iLLFJgAAaTyC1vc6kQqwss0ya6vEm4kevOS+S/XJwoxDe31zW585wdkBzAhkkRl0ty4O WHD4PH6u+BZfnP6toQsl5wz1LMsSxSmrW5aArqDHjib0qyhWMqBuTwMOz2l3XOE3aZG5 JL7oOOWa3lhBmtHRIdzHV4gRPq3d6AC59p2D3GcqX349xuX0Sqllq/TFxIqzLL/p5Slu cYdVmdCgO7rwUoOs0fpELBDVPyR+mVaJNOaN4s3AkEmXKGPhpxghWtnHkR5U/spA6bL0 XvkQ== 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 s18si716220pjq.46.2019.08.17.09.19.33; Sat, 17 Aug 2019 09:19:47 -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 S1726162AbfHQQSn (ORCPT + 99 others); Sat, 17 Aug 2019 12:18:43 -0400 Received: from mx2.suse.de ([195.135.220.15]:57686 "EHLO mx1.suse.de" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1725784AbfHQQSm (ORCPT ); Sat, 17 Aug 2019 12:18:42 -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 DA8A2AF3B; Sat, 17 Aug 2019 16:18:38 +0000 (UTC) Date: Sat, 17 Aug 2019 18:18:37 +0200 Message-ID: From: Takashi Iwai To: Hui Peng Cc: security@kernel.org, alsa-devel@alsa-project.org, YueHaibing , Thomas Gleixner , Mathias Payer , Jaroslav Kysela , Takashi Iwai , Wenwen Wang , linux-kernel@vger.kernel.org Subject: Re: [PATCH] Fix an OOB bug in uac_mixer_unit_bmControls In-Reply-To: References: <20190817043208.12433-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=UTF-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Sat, 17 Aug 2019 17:57:38 +0200, Hui Peng wrote: > > Looking around, there are other suspicious codes. E.g., in the following > function, it seems to be the same as `uac_mixer_unit_bmControls`, but it is > accessing `desc->bNrInPins + 5`, in case of UAC_VERSION_1. > Is this intended? Yes, this isn't for the mixer unit but for the processing unit. They have different definitions. Now back to the original report: I read the code again but fail to see where is OOB access. Let's see the function: static int uac_mixer_unit_get_channels(struct mixer_build *state, struct uac_mixer_unit_descriptor *desc) { int mu_channels; void *c; if (desc->bLength < sizeof(*desc)) return -EINVAL; if (!desc->bNrInPins) return -EINVAL; if (desc->bLength < sizeof(*desc) + desc->bNrInPins) return -EINVAL; switch (state->mixer->protocol) { case UAC_VERSION_1: case UAC_VERSION_2: default: if (desc->bLength < sizeof(*desc) + desc->bNrInPins + 1) return 0; /* no bmControls -> skip */ mu_channels = uac_mixer_unit_bNrChannels(desc); break; case UAC_VERSION_3: mu_channels = get_cluster_channels_v3(state, uac3_mixer_unit_wClusterDescrID(desc)); break; } if (!mu_channels) return 0; ... until this point, mu_channels is calculated but no actual access happens. Then: c = uac_mixer_unit_bmControls(desc, state->mixer->protocol); ... this returns the *address* of the bmControls bitmap. At this point, it's not accessed yet. Now: if (c - (void *)desc + (mu_channels - 1) / 8 >= desc->bLength) return 0; /* no bmControls -> skip */ ... here we check whether the actual bitmap address plus the max bitmap size overflows bLength. And if it overflows, returns 0, indicating no bitmap available. So the code doesn't access but checks properly beforehand as far as I understand. Is the actual OOB access triggered by some program? thanks, Takashi > > static inline __u8 *uac_processing_unit_bmControls(struct uac_processing_unit_descriptor *desc, > int protocol) > { > switch (protocol) { > case UAC_VERSION_1: > return &desc->baSourceID[desc->bNrInPins + 5]; > case UAC_VERSION_2: > return &desc->baSourceID[desc->bNrInPins + 6]; > case UAC_VERSION_3: > return &desc->baSourceID[desc->bNrInPins + 2]; > default: > return NULL; > } > } > > On Sat, Aug 17, 2019 at 2:55 AM Takashi Iwai wrote: > > On Sat, 17 Aug 2019 06:32:07 +0200, > Hui Peng wrote: > > > > `uac_mixer_unit_get_channels` calls `uac_mixer_unit_bmControls` > > to get pointer to bmControls field. The current implementation of > > `uac_mixer_unit_get_channels` does properly check the size of > > uac_mixer_unit_descriptor descriptor and may allow OOB access > > in `uac_mixer_unit_bmControls`. > > > > Reported-by: Hui Peng > > Reported-by: Mathias Payer > > Signed-off-by: Hui Peng > > Ah a good catch. > > One easier fix in this case would be to get the offset from > uac_mixer_unit_bmControls(), e.g. > >         /* calculate the offset of bmControls field */ >         size_t bmc_offset = uac_mixer_unit_bmControls(NULL, protocol) - > NULL; >         .... >         if (desc->bLength < bmc_offset) >                 return 0; > > thanks, > > Takashi > > > --- > >  sound/usb/mixer.c | 25 ++++++++++++++++++------- > >  1 file changed, 18 insertions(+), 7 deletions(-) > > > > diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c > > index b5927c3d5bc0..00e6274a63c3 100644 > > --- a/sound/usb/mixer.c > > +++ b/sound/usb/mixer.c > > @@ -738,28 +738,39 @@ static int get_cluster_channels_v3(struct > mixer_build *state, unsigned int clust > >  static int uac_mixer_unit_get_channels(struct mixer_build *state, > >                                      struct uac_mixer_unit_descriptor > *desc) > >  { > > -     int mu_channels; > > +     int mu_channels = 0; > >       void *c; > >  > > -     if (desc->bLength < sizeof(*desc)) > > -             return -EINVAL; > >       if (!desc->bNrInPins) > >               return -EINVAL; > > -     if (desc->bLength < sizeof(*desc) + desc->bNrInPins) > > -             return -EINVAL; > >  > >       switch (state->mixer->protocol) { > >       case UAC_VERSION_1: > > +             // limit derived from uac_mixer_unit_bmControls > > +             if (desc->bLength < sizeof(*desc) + desc->bNrInPins + 4) > > +                     return 0; > > + > > +             mu_channels = uac_mixer_unit_bNrChannels(desc); > > +             break; > > + > >       case UAC_VERSION_2: > > -     default: > > -             if (desc->bLength < sizeof(*desc) + desc->bNrInPins + 1) > > +             // limit derived from uac_mixer_unit_bmControls > > +             if (desc->bLength < sizeof(*desc) + desc->bNrInPins + 6) > >                       return 0; /* no bmControls -> skip */ > > + > >               mu_channels = uac_mixer_unit_bNrChannels(desc); > >               break; > >       case UAC_VERSION_3: > > +             // limit derived from uac_mixer_unit_bmControls > > +             if (desc->bLength < sizeof(*desc) + desc->bNrInPins + 2) > > +                     return 0; /* no bmControls -> skip */ > > + > >               mu_channels = get_cluster_channels_v3(state, > >                               uac3_mixer_unit_wClusterDescrID(desc)); > >               break; > > + > > +     default: > > +             break; > >       } > >  > >       if (!mu_channels) > > -- > > 2.22.1 > > > > > >