Received: by 2002:a05:6a10:413:0:0:0:0 with SMTP id 19csp3581832pxp; Wed, 23 Mar 2022 01:20:48 -0700 (PDT) X-Google-Smtp-Source: ABdhPJw1IzaTN6pDNu1KCgGw5Cnb5cWgtB+ydTVwXxX1aa8gnJU7ctjXZZI6/2Z0QPM8XrffCn1C X-Received: by 2002:a63:fa43:0:b0:382:53c4:ca7c with SMTP id g3-20020a63fa43000000b0038253c4ca7cmr14179033pgk.33.1648023648172; Wed, 23 Mar 2022 01:20:48 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1648023648; cv=none; d=google.com; s=arc-20160816; b=KGg1ykMViC32UuPuMiQ9X6DTxPe8QjpIRzzaDW3M2So8gpNk517Q6rNtGziA/yqlJL IE92ewD1mdEdZ5tm0H3MdpSxPCHHh8p5aQaap+6Pe1mZPt81VeuaP+GLw384ogSdgYIP 0VGyHJRobaB2m6+YnlBdVIFo3MFqT6vXI73Wb+e/rHiDVE0zkgC1fZIbvkxWwy2aruXu e4sI8N+/JcKkpVsy9AYN7fzVGKN5DdbJJOty66jy5vDmPMN9ZyNk51t6F1JnnnkY7zY5 4CbKHZgTESgBL7vCbpo+bRzLDpQBw+gT8p8HV9xftoPLwWcY33VePHnYzsaqXvbN2DUw Jf+w== 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 :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature:dkim-signature; bh=6fbhaIjiu6I6EYFCJgaK9dNKTeI2PHW3Jz9RETaj5Jk=; b=mTQrNeLkHM6CHRaX3uOJ5fLG38eOehIBOUIuavSuey+vkhFN0TK3LPy7z36YlVxs6E Unrobrz7M9XP+8dFxYTFFx8yL4pmPCywc0EkXMEKvdBRFPORoSPI/7RuTf383LT+8j8f cu+NTLdel+vlm1qLq2I0+9H/YdX9ZDb9vyBMbbkR85XMgyU1FZej693e/0H5Qc815wOa jyn06jh0TMDEbi0OsQKCBCvWsM7kC2RiEqfPHoEvSu0+gsLdRfkbTv+8L7os1hJeSHDJ qsxs1YmH3Fd97WJ2EDg/ErB2t/+JrVHG7X3OUtJroKZHNvfzNR+y63GPjqBjeUMGlW+c k4pQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@suse.de header.s=susede2_rsa header.b=axLGYK+2; dkim=neutral (no key) header.i=@suse.de header.s=susede2_ed25519 header.b=aX3VigDl; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 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 out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id p21-20020a170902a41500b00153b2d165b2si14654265plq.442.2022.03.23.01.20.33; Wed, 23 Mar 2022 01:20:48 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@suse.de header.s=susede2_rsa header.b=axLGYK+2; dkim=neutral (no key) header.i=@suse.de header.s=susede2_ed25519 header.b=aX3VigDl; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=suse.de Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S239361AbiCVRJR (ORCPT + 99 others); Tue, 22 Mar 2022 13:09:17 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41674 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231186AbiCVRJQ (ORCPT ); Tue, 22 Mar 2022 13:09:16 -0400 Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.220.29]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 705ED71ECE for ; Tue, 22 Mar 2022 10:07:48 -0700 (PDT) Received: from relay2.suse.de (relay2.suse.de [149.44.160.134]) by smtp-out2.suse.de (Postfix) with ESMTP id 275341F388; Tue, 22 Mar 2022 17:07:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_rsa; t=1647968867; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=6fbhaIjiu6I6EYFCJgaK9dNKTeI2PHW3Jz9RETaj5Jk=; b=axLGYK+2eJqTAJT6AHwmEIH2U+zTkwMYlcdhFT7LRom+FJXzPKxvwg+RaCCZc503Re/r5C kq9E+oxOaRFihY8MoEqPkouhqiqpetEgtorCvY2jvEeu1zPgOom4ShlSk3Rr4XRQ/JFAP7 2yze0edDeIIrOxb3xK53QZHsc6NwDPo= DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=suse.de; s=susede2_ed25519; t=1647968867; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=6fbhaIjiu6I6EYFCJgaK9dNKTeI2PHW3Jz9RETaj5Jk=; b=aX3VigDl4w5EpjgURghWRhJ2jtP/06Qj1oO4MCdBmYw+Eawp0xU3uOmfyup3bVh2hYpgUf apeQK+8RRo1jHkCg== Received: from alsa1.nue.suse.com (alsa1.suse.de [10.160.4.42]) by relay2.suse.de (Postfix) with ESMTP id 14899A3B88; Tue, 22 Mar 2022 17:07:47 +0000 (UTC) From: Takashi Iwai To: alsa-devel@alsa-project.org Cc: Hu Jiahui , linux-kernel@vger.kernel.org Subject: [PATCH 1/4] ALSA: pcm: Fix races among concurrent hw_params and hw_free calls Date: Tue, 22 Mar 2022 18:07:17 +0100 Message-Id: <20220322170720.3529-2-tiwai@suse.de> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20220322170720.3529-1-tiwai@suse.de> References: <20220322170720.3529-1-tiwai@suse.de> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-4.4 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_MED,SPF_HELO_NONE, SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=ham 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 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: Signed-off-by: Takashi Iwai --- include/sound/pcm.h | 1 + sound/core/pcm.c | 2 ++ sound/core/pcm_native.c | 61 ++++++++++++++++++++++++++--------------- 3 files changed, 42 insertions(+), 22 deletions(-) diff --git a/include/sound/pcm.h b/include/sound/pcm.h index 36da42cd0774..314f2779cab5 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h @@ -401,6 +401,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; diff --git a/sound/core/pcm.c b/sound/core/pcm.c index ba4a987ed1c6..edd9849210f2 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -969,6 +969,7 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, 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_pcm_substream *substream) } else { substream->runtime = NULL; } + mutex_destroy(&runtime->buffer_mutex); kfree(runtime); put_pid(substream->pid); substream->pid = NULL; diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index a056b3ef3c84..266895374b83 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -685,33 +685,40 @@ static int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm, 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); @@ -799,16 +806,21 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, 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; } @@ -848,26 +860,31 @@ static int do_hw_free(struct snd_pcm_substream *substream) 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; } -- 2.31.1