Received: by 2002:a05:6a10:413:0:0:0:0 with SMTP id 19csp1612701pxp; Thu, 17 Mar 2022 12:42:54 -0700 (PDT) X-Google-Smtp-Source: ABdhPJw0/dylB8HEnptCPrNDynuhQLQmlhy9l8U6wSvNq5atA7T4FG7PPNn3e46/ZUiRF+fDLyk4 X-Received: by 2002:a17:90a:67c3:b0:1bc:9cdf:1ee9 with SMTP id g3-20020a17090a67c300b001bc9cdf1ee9mr7163877pjm.203.1647546174719; Thu, 17 Mar 2022 12:42:54 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1647546174; cv=none; d=google.com; s=arc-20160816; b=z68bavJckS1LURBU0SrhkeATYZcw24cwkNW2H+WmfY8Ts2kbju3MHgia1tGVv4Yhgz cjexGpuIsZvlUXv1gYFs+rjqdjrwl8VqYhKkXafd858g2UQ3ic5NSQsqmRSuMKNL/TkA 2NifiZI20v7qxY4UouDM1AeZodusiCM1TjlmnMYegLMeAgEsoaMIKTkXF8MzFJiSt7eR U0uvKffUKx067Pa65aOSuwu51fYjGlaEnsZ+x555TvlMuG2My7fwtqF56zUjfV7NOB7s +z4fwFXsVVVhmC4JAgAnE9S7b7I+7KUe68VLHTmlaZYlbYSw4lL7rOPMCGi78+AxgxHO Js+w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:mime-version:user-agent:references:in-reply-to :subject:cc:to:from:message-id:date:dkim-signature:dkim-signature; bh=6edWcSlDuE7GBRxOnbjiZrVj1Ut4eAAnls2UvqT8a+Q=; b=lyNX73FBzVWxI52wbWYpSTAjnpBUKkKkhdxByWPSDfS4RzBJ20MOKmcGsIk0s0chB9 xWF9RIdEM1cPJWIuw/Wi6QXsXY8Ss8BR2amBY8bNLETJivzCBGEZrjfdL/27sY1XRr60 jkvFfXhJ8KXUDNRyoFGasOt3/iJdDTOglEsbaFTx1hpnifdckFqU/FB0S0RSQ10iGfsh r3hC+NYWIC9cYPc+D0x68dwnId/ZZIMD4fwCySpd+Fqfxi6QgShx33905OXsTVNGBAOC p/JUby9n8j/b2kzqB76/ceQMJqe8025PNYvpF0W1Hg5jHPpQhUFGMQlUReOV8n8y83DH vMlQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@suse.de header.s=susede2_rsa header.b=FAMppHJS; dkim=neutral (no key) header.i=@suse.de header.s=susede2_ed25519 header.b=RlrA0+u4; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=suse.de Return-Path: Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net. [2620:137:e000::1:18]) by mx.google.com with ESMTPS id c15-20020a65618f000000b003816043ef50si2966742pgv.325.2022.03.17.12.42.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 17 Mar 2022 12:42:54 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:18 as permitted sender) client-ip=2620:137:e000::1:18; Authentication-Results: mx.google.com; dkim=pass header.i=@suse.de header.s=susede2_rsa header.b=FAMppHJS; dkim=neutral (no key) header.i=@suse.de header.s=susede2_ed25519 header.b=RlrA0+u4; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=suse.de Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 2A01E23D44B; Thu, 17 Mar 2022 12:42:49 -0700 (PDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234413AbiCQOOc (ORCPT + 99 others); Thu, 17 Mar 2022 10:14:32 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42444 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233290AbiCQOOa (ORCPT ); Thu, 17 Mar 2022 10:14:30 -0400 Received: from smtp-out1.suse.de (smtp-out1.suse.de [195.135.220.28]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id ECDAB9F3BC for ; Thu, 17 Mar 2022 07:13:13 -0700 (PDT) Received: from relay2.suse.de (relay2.suse.de [149.44.160.134]) by smtp-out1.suse.de (Postfix) with ESMTP id A2EE0210FD; Thu, 17 Mar 2022 14:13:12 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1647526392; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=6edWcSlDuE7GBRxOnbjiZrVj1Ut4eAAnls2UvqT8a+Q=; b=FAMppHJSN0V7e808pZpLTejB737rs6wrDw4F+QAUAjQvE39Iq3dR9B7E+X5Xyy7bnED19g y830BefgyDDYNcT8A46hHRCu9EcAUF2XZkWqSQYkFn2nmYiFanE+x5vLUF5A8IqUihbk9g aVd2D/QtfdZ/WGM7DTAlonNis9L5cs4= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1647526392; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version:content-type:content-type: in-reply-to:in-reply-to:references:references; bh=6edWcSlDuE7GBRxOnbjiZrVj1Ut4eAAnls2UvqT8a+Q=; b=RlrA0+u4HufMDNPznh8PItdhiWY8jeQoUb1gmKrbv7iScUP6D36pXKGac8cc1iwPmEHv3a +/nY1pssqG3sBFBQ== Received: from alsa1.suse.de (alsa1.suse.de [10.160.4.42]) by relay2.suse.de (Postfix) with ESMTP id 6A704A3BE5; Thu, 17 Mar 2022 14:13:12 +0000 (UTC) Date: Thu, 17 Mar 2022 15:13:12 +0100 Message-ID: From: Takashi Iwai To: Linus Torvalds Cc: syzbot , Jaroslav Kysela , Takashi Iwai , Andrew Morton , alsa-devel@alsa-project.org, Linux Kernel Mailing List , Linux-MM , syzkaller-bugs , Willy Tarreau Subject: Re: [syzbot] WARNING: kmalloc bug in snd_pcm_plugin_alloc (2) In-Reply-To: References: <00000000000085b1b305da5a66f3@google.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 X-Spam-Status: No, score=-2.0 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, MAILING_LIST_MULTI,RDNS_NONE,SPF_HELO_NONE,T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org On Wed, 16 Mar 2022 20:28:46 +0100, Linus Torvalds wrote: > > On Wed, Mar 16, 2022 at 11:51 AM syzbot > wrote: > > > > WARNING: CPU: 1 PID: 3761 at mm/util.c:591 kvmalloc_node+0x121/0x130 mm/util.c:591 > > snd_pcm_plugin_alloc+0x570/0x770 sound/core/oss/pcm_plugin.c:71 > > snd_pcm_plug_alloc+0x20d/0x310 sound/core/oss/pcm_plugin.c:118 > > snd_pcm_oss_change_params_locked+0x19db/0x3bf0 sound/core/oss/pcm_oss.c:1041 > > snd_pcm_oss_change_params sound/core/oss/pcm_oss.c:1104 [inline] > > snd_pcm_oss_get_active_substream+0x164/0x1c0 sound/core/oss/pcm_oss.c:1121 > > snd_pcm_oss_get_rate sound/core/oss/pcm_oss.c:1778 [inline] > > snd_pcm_oss_set_rate sound/core/oss/pcm_oss.c:1770 [inline] > > snd_pcm_oss_ioctl+0x144f/0x3430 sound/core/oss/pcm_oss.c:2632 > > Well, that looks like a real bug in the sound subsystem, and the > warning is appropriate. > > It looks like > > size = frames * format->channels * width; > > can overflow 32 bits, and this is presumably user-triggerable with > snd_pcm_oss_ioctl(). > > Maybe there's some range check at an upper layer that is supposed to > catch this, but I'm not seeing it. > > I think the simple fix is to do > > size = array3_size(frames, format->channels, width); > > instead, which clamps the values at the maximum size_t. > > Then you can trivially check for that overflow value (SIZE_MAX), but > you can - and probably should - just check for some sane value. > INT_MAX comes to mind, since that's what the allocation routine will > warn about. > > But you can also say "Ok, I have now used the 'array_size()' function > to make sure any overflow will clamp to a very high value, so I know > I'll get an allocation failure, and I'd rather just make the allocator > do the size checking, so I'll add __GFP_NOWARN at allocation time and > just return -ENOMEM when that fails". > > But that __GFP_NOWARN is *ONLY* acceptable if you have actually made > sure that "yes, all my size calculations have checked for overflow > and/or done that SIZE_MAX clamping". > > Alternatively, you can just do each multiplication carefully, and use > "check_mul_overflow()" by hand, but it's a lot more inconvenient and > the end result tends to look horrible. There's a reason we have those > "array_size()" and "array3_size()" helpers. > > There is also some very odd and suspicious-looking code in > snd_pcm_oss_change_params_locked(): > > oss_period_size *= oss_frame_size; > > oss_buffer_size = oss_period_size * runtime->oss.periods; > if (oss_buffer_size < 0) { > err = -EINVAL; > goto failure; > } > > which seems to think that checking the end result for being negative > is how you check for overflow. But that's actually after the > snd_pcm_plug_alloc() call. > > It looks like all of this should use "check_mul_overflow()", but it > presumably also wants fixing (and also would like to use the > 'array_size()' helpers, but note that those take a 'size_t', so you do > want to check for negative values *before* if you allow zeroes > anywhere else) > > If you don't mind "multiplying by zero will hide a negative > intermediate value", you can pass in 'ssize_t' arguments, do the > multiplication as unsigned, put the result in a 'ssize_t' value, and > just check for a negative result. > > That would seem to be acceptable here, and that > snd_pcm_oss_change_params_locked() code could also just be > > oss_period_size = array_size(oss_period_size, oss_frame_size); > oss_buffer_size = array_size(oss_period_size, runtime->oss.periods); > if (oss_buffer_size < 0) { > ... > > but I would suggest checking for a zero result too, because that can > hide the sub-parts having been some invalid crazy values that can also > cause problems later. Indeed there seem missing value limit checks. Currently we rely on the fact that the parameters of the underlying PCM device have been already configured properly, and it assures that the original values are fine. OTOH, this PCM OSS layer does also conversions and it allocates temporary buffers for that. The problem happens with those converted parameters; depending on the sample rate, channels, and format, it may increases significantly, and this was the reason of the 31bit overflow. And, we want not only avoiding the overflow but also limiting the actual size, too. Practically seen, more than 1MB temporary buffer is unrealistic, and better to bail if more than that is requested. Blow is the fix patch. It works fine for local testing. thanks, Takashi -- 8< -- From: Takashi Iwai Date: Thu, 17 Mar 2022 11:29:39 +0100 Subject: [PATCH] ALSA: oss: Fix PCM OSS buffer allocation overflow We've got syzbot reports hitting INT_MAX overflow at vmalloc() allocation that is called from snd_pcm_plug_alloc(). Although we apply the restrictions to input parameters, it's based only on the hw_params of the underlying PCM device. Since the PCM OSS layer allocates a temporary buffer for the data conversion, the size may become unexpectedly large when more channels or higher rates is given; in the reported case, it went over INT_MAX, hence it hits WARN_ON(). This patch is an attempt to avoid such an overflow and an allocation for too large buffers. First off, it adds the limit of 1MB as the upper bound for period bytes. This must be large enough for all use cases, and we really don't want to handle a larger temporary buffer than this size. The size check is performed at two places, where the original period bytes is calculated and where the plugin buffer size is calculated. In addition, the driver uses array_size() and array3_size() for multiplications to catch overflows for the converted period size and buffer bytes. Reported-by: syzbot+72732c532ac1454eeee9@syzkaller.appspotmail.com Suggested-by: Linus Torvalds Cc: Link: https://lore.kernel.org/r/00000000000085b1b305da5a66f3@google.com Signed-off-by: Takashi Iwai --- sound/core/oss/pcm_oss.c | 12 ++++++++---- sound/core/oss/pcm_plugin.c | 5 ++++- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 3ee9edf85815..f158f0abd25d 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c @@ -774,6 +774,11 @@ static int snd_pcm_oss_period_size(struct snd_pcm_substream *substream, if (oss_period_size < 16) return -EINVAL; + + /* don't allocate too large period; 1MB period must be enough */ + if (oss_period_size > 1024 * 1024) + return -ENOMEM; + runtime->oss.period_bytes = oss_period_size; runtime->oss.period_frames = 1; runtime->oss.periods = oss_periods; @@ -1043,10 +1048,9 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream) goto failure; } #endif - oss_period_size *= oss_frame_size; - - oss_buffer_size = oss_period_size * runtime->oss.periods; - if (oss_buffer_size < 0) { + oss_period_size = array_size(oss_period_size, oss_frame_size); + oss_buffer_size = array_size(oss_period_size, runtime->oss.periods); + if (oss_buffer_size <= 0) { err = -EINVAL; goto failure; } diff --git a/sound/core/oss/pcm_plugin.c b/sound/core/oss/pcm_plugin.c index 061ba06bc926..82e180c776ae 100644 --- a/sound/core/oss/pcm_plugin.c +++ b/sound/core/oss/pcm_plugin.c @@ -62,7 +62,10 @@ static int snd_pcm_plugin_alloc(struct snd_pcm_plugin *plugin, snd_pcm_uframes_t width = snd_pcm_format_physical_width(format->format); if (width < 0) return width; - size = frames * format->channels * width; + size = array3_size(frames, format->channels, width); + /* check for too large period size once again */ + if (size > 1024 * 1024) + return -ENOMEM; if (snd_BUG_ON(size % 8)) return -ENXIO; size /= 8; -- 2.34.1