Received: by 2002:a05:6a10:2726:0:0:0:0 with SMTP id ib38csp2155285pxb; Fri, 25 Mar 2022 12:04:45 -0700 (PDT) X-Google-Smtp-Source: ABdhPJzeNy7q6KFA3/b94sJPWicYvTH7sbhmoe6OZcWFlac0VkGWRsC/Qif5o+WpmBRzQFmFN9mX X-Received: by 2002:a17:90b:4b01:b0:1c7:8a37:bfd3 with SMTP id lx1-20020a17090b4b0100b001c78a37bfd3mr14344484pjb.115.1648235085365; Fri, 25 Mar 2022 12:04:45 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1648235085; cv=none; d=google.com; s=arc-20160816; b=WJ9xqonguuO86dzCBlLd9q2aI/IMfuYHxD2kiOYb4SacZDAUxd8/odoDfSSl1QERjz 3pluy3G0ehs6jx5cr0+YM9ueuz9WfaWPcdBZWGw8549dLVWU0f9LNX405YojgRyy+yNh M5B95InBfZY/roJ5z4rhfAGeOnYHCJf6ccbiPgcCkXWaito1dHfD9Lwkr9AlyZ4IhWzb oKF5TdZ0OnqDnifp0ug4sKJld4HhaQ9DZOfbi8eyy8EWR6/kiY97o1IHYjSeykE7dwmY 64Blr37tITEhaxZ0fMBQY1HpcamDf3SwSh9QY+bMrpqxxShSMWupePlI9Icd0PCGZZQ1 zO+g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=Wre54moI9dka0HLj0lN3OOXiXcdZuncSbOtWIlKfUBc=; b=W3clM/r0mwR+TXOJc+b9enVcWpNFA3TXB6PFzEdiFmnGiWPQlMy/51HXB+q4ESYgkV l+PIV3rpM87jZ/HJZnEJFMmXNJ+gT1JVehHj4Z+McHB2qf/GjWNgJ/nURG3tsvAvIbcs PflB+Tdd37LGyhnGxonj+GGgV5673XMbp0JZDw5UUv11uR9sWqSz2nai6dOx/d+RlOwE q/6m4Yy7oo4K2z5mfpz9Ez3OhxN7qFJBzcI0QlFumA3B/z4nqF4iMoHe3I5+gA6Zld0N qN/pZcIHdgBU7dSdX9cFOMHVh/u0xq9giFg3DK83AonyJyOd5rbp5PKb9VHsatwh881q zLnw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=jcj7jxuU; 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=linuxfoundation.org Return-Path: Received: from lindbergh.monkeyblade.net (lindbergh.monkeyblade.net. [2620:137:e000::1:18]) by mx.google.com with ESMTPS id h12-20020a056a00230c00b004fa3a8e0072si3932285pfh.297.2022.03.25.12.04.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 25 Mar 2022 12:04:45 -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=@linuxfoundation.org header.s=korg header.b=jcj7jxuU; 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=linuxfoundation.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 5BADE1D916A; Fri, 25 Mar 2022 11:12:53 -0700 (PDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1356132AbiCYPV2 (ORCPT + 99 others); Fri, 25 Mar 2022 11:21:28 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38858 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1376371AbiCYPS6 (ORCPT ); Fri, 25 Mar 2022 11:18:58 -0400 Received: from dfw.source.kernel.org (dfw.source.kernel.org [IPv6:2604:1380:4641:c500::1]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5B6C9DEBAB; Fri, 25 Mar 2022 08:15:08 -0700 (PDT) Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by dfw.source.kernel.org (Postfix) with ESMTPS id 064A560A73; Fri, 25 Mar 2022 15:14:59 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 0C168C340E9; Fri, 25 Mar 2022 15:14:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1648221298; bh=q4yisZHCankKIcaEBoaOV+QCs/SEnOGaAYxROdpfo3g=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=jcj7jxuU+qWbyiw+vjDN/DEr0vb9lNqVook5gQvXCIZXLhvi2ZQIZVwizuwt6Z2eG De8O0YtyJhBq+WNRAHNsX6GYBPG+JibqEJA8PgcykTTheeXRxJ+cG1YqR0D9hrecX7 vsqIsrsWS1yi6ftxXLFUl8jxd6LzxjsZEBySPtmI= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Hu Jiahui , Jaroslav Kysela , Takashi Iwai Subject: [PATCH 5.15 13/37] ALSA: pcm: Fix races among concurrent hw_params and hw_free calls Date: Fri, 25 Mar 2022 16:14:14 +0100 Message-Id: <20220325150420.313873846@linuxfoundation.org> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20220325150419.931802116@linuxfoundation.org> References: <20220325150419.931802116@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-3.1 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, 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=unavailable 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 From: Takashi Iwai commit 92ee3c60ec9fe64404dc035e7c41277d74aa26cb upstream. Currently we have neither proper check nor protection against the concurrent calls of PCM hw_params and hw_free ioctls, which may result in a UAF. Since the existing PCM stream lock can't be used for protecting the whole ioctl operations, we need a new mutex to protect those racy calls. This patch introduced a new mutex, runtime->buffer_mutex, and applies it to both hw_params and hw_free ioctl code paths. Along with it, the both functions are slightly modified (the mmap_count check is moved into the state-check block) for code simplicity. Reported-by: Hu Jiahui Cc: Reviewed-by: Jaroslav Kysela Link: https://lore.kernel.org/r/20220322170720.3529-2-tiwai@suse.de Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- include/sound/pcm.h | 1 sound/core/pcm.c | 2 + sound/core/pcm_native.c | 61 ++++++++++++++++++++++++++++++------------------ 3 files changed, 42 insertions(+), 22 deletions(-) --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -398,6 +398,7 @@ struct snd_pcm_runtime { wait_queue_head_t tsleep; /* transfer sleep */ struct fasync_struct *fasync; bool stop_operating; /* sync_stop will be called */ + struct mutex buffer_mutex; /* protect for buffer changes */ /* -- private section -- */ void *private_data; --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -969,6 +969,7 @@ int snd_pcm_attach_substream(struct snd_ init_waitqueue_head(&runtime->tsleep); runtime->status->state = SNDRV_PCM_STATE_OPEN; + mutex_init(&runtime->buffer_mutex); substream->runtime = runtime; substream->private_data = pcm->private_data; @@ -1002,6 +1003,7 @@ void snd_pcm_detach_substream(struct snd } else { substream->runtime = NULL; } + mutex_destroy(&runtime->buffer_mutex); kfree(runtime); put_pid(substream->pid); substream->pid = NULL; --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -672,33 +672,40 @@ static int snd_pcm_hw_params_choose(stru return 0; } +#if IS_ENABLED(CONFIG_SND_PCM_OSS) +#define is_oss_stream(substream) ((substream)->oss.oss) +#else +#define is_oss_stream(substream) false +#endif + static int snd_pcm_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) { struct snd_pcm_runtime *runtime; - int err, usecs; + int err = 0, usecs; unsigned int bits; snd_pcm_uframes_t frames; if (PCM_RUNTIME_CHECK(substream)) return -ENXIO; runtime = substream->runtime; + mutex_lock(&runtime->buffer_mutex); snd_pcm_stream_lock_irq(substream); switch (runtime->status->state) { case SNDRV_PCM_STATE_OPEN: case SNDRV_PCM_STATE_SETUP: case SNDRV_PCM_STATE_PREPARED: + if (!is_oss_stream(substream) && + atomic_read(&substream->mmap_count)) + err = -EBADFD; break; default: - snd_pcm_stream_unlock_irq(substream); - return -EBADFD; + err = -EBADFD; + break; } snd_pcm_stream_unlock_irq(substream); -#if IS_ENABLED(CONFIG_SND_PCM_OSS) - if (!substream->oss.oss) -#endif - if (atomic_read(&substream->mmap_count)) - return -EBADFD; + if (err) + goto unlock; snd_pcm_sync_stop(substream, true); @@ -786,16 +793,21 @@ static int snd_pcm_hw_params(struct snd_ if (usecs >= 0) cpu_latency_qos_add_request(&substream->latency_pm_qos_req, usecs); - return 0; + err = 0; _error: - /* hardware might be unusable from this time, - so we force application to retry to set - the correct hardware parameter settings */ - snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN); - if (substream->ops->hw_free != NULL) - substream->ops->hw_free(substream); - if (substream->managed_buffer_alloc) - snd_pcm_lib_free_pages(substream); + if (err) { + /* hardware might be unusable from this time, + * so we force application to retry to set + * the correct hardware parameter settings + */ + snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN); + if (substream->ops->hw_free != NULL) + substream->ops->hw_free(substream); + if (substream->managed_buffer_alloc) + snd_pcm_lib_free_pages(substream); + } + unlock: + mutex_unlock(&runtime->buffer_mutex); return err; } @@ -835,26 +847,31 @@ static int do_hw_free(struct snd_pcm_sub static int snd_pcm_hw_free(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime; - int result; + int result = 0; if (PCM_RUNTIME_CHECK(substream)) return -ENXIO; runtime = substream->runtime; + mutex_lock(&runtime->buffer_mutex); snd_pcm_stream_lock_irq(substream); switch (runtime->status->state) { case SNDRV_PCM_STATE_SETUP: case SNDRV_PCM_STATE_PREPARED: + if (atomic_read(&substream->mmap_count)) + result = -EBADFD; break; default: - snd_pcm_stream_unlock_irq(substream); - return -EBADFD; + result = -EBADFD; + break; } snd_pcm_stream_unlock_irq(substream); - if (atomic_read(&substream->mmap_count)) - return -EBADFD; + if (result) + goto unlock; result = do_hw_free(substream); snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN); cpu_latency_qos_remove_request(&substream->latency_pm_qos_req); + unlock: + mutex_unlock(&runtime->buffer_mutex); return result; }