Received: by 2002:a17:90a:bc8d:0:0:0:0 with SMTP id x13csp1570472pjr; Mon, 18 May 2020 16:41:35 -0700 (PDT) X-Google-Smtp-Source: ABdhPJw2Qa2v/xyN3u8VkLlkXBppvFQSs6b8cKENDCxQMGiqHOkpW+7tSSSl8AU+HsBnMMmHPDrq X-Received: by 2002:aa7:d1c6:: with SMTP id g6mr16005695edp.303.1589845295460; Mon, 18 May 2020 16:41:35 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1589845295; cv=none; d=google.com; s=arc-20160816; b=L/HwED5ffrKit8Zac5oU4X/868L8sVWvoZWs4Jniv7bCMNLw1rJn/5zNQrHPMkmrqk M3lNC65pTqPt2009Khavzi8B0XCgG7Fa7+l76A/6/q2MIL1eBry08fuljDNXq+g1WFh0 2MtgmEF4BC7aQ4tyoSaZ3tUljmOPYyvizbN1mU019kTvtP+UkgO2ptyrfpTv1LAoXnq1 oMWoaa9FYLfJH7CmoUnkqeXDO0Jk7xA0QpnzLvASzTMnnA6nbg00W3Yka7Iye09ZGRrK c29bOnSUlFF6TDSbx+ouhB4qcZv7x5wEttU/BAMCV9AOMTazitrco0EESlP/kXb2nQna EsrQ== 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:message-id:date:subject:cc:to :from:dkim-signature; bh=k7r09E80tIZKyjonVRJ9U3osd+U+5xq0WWg1pkdYbHs=; b=EivsL9lB0JthkyFS+eSgLr+n7Sati5Wev2ktOgpyLOOKFarbrpNF8OcwQqplYy2JTq x/Z1JZc1MZWHIRoGw95Xz3IJ9qjkNhZuV8ZXWUc2UXyJtRgWGF1nMVMxdkSs/ftd63J7 xB5ZcS0q8x2N4HCbVcI2xC6x+swFWyPklZMwtv9yHmzZWcH2pp0RqLoHoWMFOl2v6zLE gBmb3Ct711w/5fETrJYxH+HaIjyOngK0sTOGOcI0BEHBuJMQ0XTwCWeTEdNbdrUmVAc8 fEPDwv58pHORv85DSSXFoNiXa+Zm0i3i8g8y0DTc9x+rvm0wWW+KebfvFiFZ9xxsRa+8 CFqw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=2BsQYLEE; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id m30si8080204edb.193.2020.05.18.16.41.13; Mon, 18 May 2020 16:41:35 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=2BsQYLEE; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1729303AbgERRoz (ORCPT + 99 others); Mon, 18 May 2020 13:44:55 -0400 Received: from mail.kernel.org ([198.145.29.99]:43202 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1729786AbgERRoo (ORCPT ); Mon, 18 May 2020 13:44:44 -0400 Received: from localhost (83-86-89-107.cable.dynamic.v4.ziggo.nl [83.86.89.107]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id C80F020715; Mon, 18 May 2020 17:44:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1589823883; bh=typIq0/seAP8Czi1rdqH4ZdtGRHRMXR+6Z2dgm9bv+g=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=2BsQYLEEswHdjuPmgitsSZ0w2VlwNV+qA4cOxcNfaIllPGSsQmYTEED3IzFVPxgg+ zPP2YPvebZZQGRI2aIwklc4ozGOQgaz1dpCKxVcCxtijrh04tf5p694zEFIcdlcMc7 tgemK46UDvzl038POsmDyFIr9cyj/MOSqui9BGnM= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, butt3rflyh4ck , Takashi Iwai Subject: [PATCH 4.9 75/90] ALSA: rawmidi: Fix racy buffer resize under concurrent accesses Date: Mon, 18 May 2020 19:36:53 +0200 Message-Id: <20200518173506.527439760@linuxfoundation.org> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200518173450.930655662@linuxfoundation.org> References: <20200518173450.930655662@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 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 From: Takashi Iwai commit c1f6e3c818dd734c30f6a7eeebf232ba2cf3181d upstream. The rawmidi core allows user to resize the runtime buffer via ioctl, and this may lead to UAF when performed during concurrent reads or writes: the read/write functions unlock the runtime lock temporarily during copying form/to user-space, and that's the race window. This patch fixes the hole by introducing a reference counter for the runtime buffer read/write access and returns -EBUSY error when the resize is performed concurrently against read/write. Note that the ref count field is a simple integer instead of refcount_t here, since the all contexts accessing the buffer is basically protected with a spinlock, hence we need no expensive atomic ops. Also, note that this busy check is needed only against read / write functions, and not in receive/transmit callbacks; the race can happen only at the spinlock hole mentioned in the above, while the whole function is protected for receive / transmit callbacks. Reported-by: butt3rflyh4ck Cc: Link: https://lore.kernel.org/r/CAFcO6XMWpUVK_yzzCpp8_XP7+=oUpQvuBeCbMffEDkpe8jWrfg@mail.gmail.com Link: https://lore.kernel.org/r/s5heerw3r5z.wl-tiwai@suse.de Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- include/sound/rawmidi.h | 1 + sound/core/rawmidi.c | 31 +++++++++++++++++++++++++++---- 2 files changed, 28 insertions(+), 4 deletions(-) --- a/include/sound/rawmidi.h +++ b/include/sound/rawmidi.h @@ -76,6 +76,7 @@ struct snd_rawmidi_runtime { size_t avail_min; /* min avail for wakeup */ size_t avail; /* max used buffer for wakeup */ size_t xruns; /* over/underruns counter */ + int buffer_ref; /* buffer reference count */ /* misc */ spinlock_t lock; wait_queue_head_t sleep; --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -108,6 +108,17 @@ static void snd_rawmidi_input_event_work runtime->event(runtime->substream); } +/* buffer refcount management: call with runtime->lock held */ +static inline void snd_rawmidi_buffer_ref(struct snd_rawmidi_runtime *runtime) +{ + runtime->buffer_ref++; +} + +static inline void snd_rawmidi_buffer_unref(struct snd_rawmidi_runtime *runtime) +{ + runtime->buffer_ref--; +} + static int snd_rawmidi_runtime_create(struct snd_rawmidi_substream *substream) { struct snd_rawmidi_runtime *runtime; @@ -654,6 +665,11 @@ int snd_rawmidi_output_params(struct snd if (!newbuf) return -ENOMEM; spin_lock_irq(&runtime->lock); + if (runtime->buffer_ref) { + spin_unlock_irq(&runtime->lock); + kfree(newbuf); + return -EBUSY; + } oldbuf = runtime->buffer; runtime->buffer = newbuf; runtime->buffer_size = params->buffer_size; @@ -962,8 +978,10 @@ static long snd_rawmidi_kernel_read1(str long result = 0, count1; struct snd_rawmidi_runtime *runtime = substream->runtime; unsigned long appl_ptr; + int err = 0; spin_lock_irqsave(&runtime->lock, flags); + snd_rawmidi_buffer_ref(runtime); while (count > 0 && runtime->avail) { count1 = runtime->buffer_size - runtime->appl_ptr; if (count1 > count) @@ -982,16 +1000,19 @@ static long snd_rawmidi_kernel_read1(str if (userbuf) { spin_unlock_irqrestore(&runtime->lock, flags); if (copy_to_user(userbuf + result, - runtime->buffer + appl_ptr, count1)) { - return result > 0 ? result : -EFAULT; - } + runtime->buffer + appl_ptr, count1)) + err = -EFAULT; spin_lock_irqsave(&runtime->lock, flags); + if (err) + goto out; } result += count1; count -= count1; } + out: + snd_rawmidi_buffer_unref(runtime); spin_unlock_irqrestore(&runtime->lock, flags); - return result; + return result > 0 ? result : err; } long snd_rawmidi_kernel_read(struct snd_rawmidi_substream *substream, @@ -1262,6 +1283,7 @@ static long snd_rawmidi_kernel_write1(st return -EAGAIN; } } + snd_rawmidi_buffer_ref(runtime); while (count > 0 && runtime->avail > 0) { count1 = runtime->buffer_size - runtime->appl_ptr; if (count1 > count) @@ -1293,6 +1315,7 @@ static long snd_rawmidi_kernel_write1(st } __end: count1 = runtime->avail < runtime->buffer_size; + snd_rawmidi_buffer_unref(runtime); spin_unlock_irqrestore(&runtime->lock, flags); if (count1) snd_rawmidi_output_trigger(substream, 1);