From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id ADD7A125B2; Mon, 9 Feb 2026 14:36:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770647781; cv=none; b=F4KRiCknRHyKF1OL4YLMPantgHL5MOPhgsJHHZn2CtbMDl8/BDwtaJakUyJSOpdl9JhDyrXed1Xz39pyyfvG8LA8HBv6B9i1kTPJGXXy48TwDI6t91OLdJD2DvZ0keVNTiNyS+Lr6gfDDYqHNuOSRHlJguaoaENDhhOmW4g/x3E= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770647781; c=relaxed/simple; bh=Lapmb8luxq6rxYFn0SW1tDfX3iqIPoSTjSEKhz72v1c=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Bu+N6JLazmnXXBp7hgm6E2dR/hvlB5UV34zmZC8QfmwEctsPMz9FH6fn2xRwFjveVXJ+4AYD7emUC6nEK9VeiI+AwQ+2U9L+BZpIB+MOx/DJyUi4aTKLI3RqhGhaGj784hw/8fQC597fF6O3Ti4UwRk9Dgyp1Q6rGX2fvdeFzMU= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.b=sTjurZNa; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=linuxfoundation.org header.i=@linuxfoundation.org header.b="sTjurZNa" Received: by smtp.kernel.org (Postfix) with ESMTPSA id DC958C116C6; Mon, 9 Feb 2026 14:36:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1770647781; bh=Lapmb8luxq6rxYFn0SW1tDfX3iqIPoSTjSEKhz72v1c=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=sTjurZNal/XnSC3gTbBzOaWyFS+4KZQ+0vEoOPwIkD2k5Oggg2FrenVeidLAuCTEq A2AQjIrxN6bEuuzPPQqztXcnNJEc+zINpgpYVKqvGNFkFQvwTZMvxHE+FOQCJQOXrR 4IRq0dDHL+mfcmV63Q1RBSwPJOuJ/mNVZaG1lnIE= From: Greg Kroah-Hartman To: stable@vger.kernel.org Cc: Greg Kroah-Hartman , patches@lists.linux.dev, syzbot+5f8f3acdee1ec7a7ef7b@syzkaller.appspotmail.com, Takashi Iwai Subject: [PATCH 6.12 005/113] ALSA: aloop: Fix racy access at PCM trigger Date: Mon, 9 Feb 2026 15:22:34 +0100 Message-ID: <20260209142310.403225837@linuxfoundation.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260209142310.204833231@linuxfoundation.org> References: <20260209142310.204833231@linuxfoundation.org> User-Agent: quilt/0.69 X-stable: review X-Patchwork-Hint: ignore Precedence: bulk X-Mailing-List: stable@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit 6.12-stable review patch. If anyone has any objections, please let me know. ------------------ From: Takashi Iwai commit 826af7fa62e347464b1b4e0ba2fe19a92438084f upstream. The PCM trigger callback of aloop driver tries to check the PCM state and stop the stream of the tied substream in the corresponding cable. Since both check and stop operations are performed outside the cable lock, this may result in UAF when a program attempts to trigger frequently while opening/closing the tied stream, as spotted by fuzzers. For addressing the UAF, this patch changes two things: - It covers the most of code in loopback_check_format() with cable->lock spinlock, and add the proper NULL checks. This avoids already some racy accesses. - In addition, now we try to check the state of the capture PCM stream that may be stopped in this function, which was the major pain point leading to UAF. Reported-by: syzbot+5f8f3acdee1ec7a7ef7b@syzkaller.appspotmail.com Closes: https://lore.kernel.org/69783ba1.050a0220.c9109.0011.GAE@google.com Cc: Link: https://patch.msgid.link/20260203141003.116584-1-tiwai@suse.de Signed-off-by: Takashi Iwai Signed-off-by: Greg Kroah-Hartman --- sound/drivers/aloop.c | 62 +++++++++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 26 deletions(-) --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -335,37 +335,43 @@ static bool is_access_interleaved(snd_pc static int loopback_check_format(struct loopback_cable *cable, int stream) { + struct loopback_pcm *dpcm_play, *dpcm_capt; struct snd_pcm_runtime *runtime, *cruntime; struct loopback_setup *setup; struct snd_card *card; + bool stop_capture = false; int check; - if (cable->valid != CABLE_VALID_BOTH) { - if (stream == SNDRV_PCM_STREAM_PLAYBACK) - goto __notify; - return 0; - } - runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]-> - substream->runtime; - cruntime = cable->streams[SNDRV_PCM_STREAM_CAPTURE]-> - substream->runtime; - check = runtime->format != cruntime->format || - runtime->rate != cruntime->rate || - runtime->channels != cruntime->channels || - is_access_interleaved(runtime->access) != - is_access_interleaved(cruntime->access); - if (!check) - return 0; - if (stream == SNDRV_PCM_STREAM_CAPTURE) { - return -EIO; - } else { - snd_pcm_stop(cable->streams[SNDRV_PCM_STREAM_CAPTURE]-> - substream, SNDRV_PCM_STATE_DRAINING); - __notify: - runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]-> - substream->runtime; - setup = get_setup(cable->streams[SNDRV_PCM_STREAM_PLAYBACK]); - card = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->loopback->card; + scoped_guard(spinlock_irqsave, &cable->lock) { + dpcm_play = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]; + dpcm_capt = cable->streams[SNDRV_PCM_STREAM_CAPTURE]; + + if (cable->valid != CABLE_VALID_BOTH) { + if (stream == SNDRV_PCM_STREAM_CAPTURE || !dpcm_play) + return 0; + } else { + if (!dpcm_play || !dpcm_capt) + return -EIO; + runtime = dpcm_play->substream->runtime; + cruntime = dpcm_capt->substream->runtime; + if (!runtime || !cruntime) + return -EIO; + check = runtime->format != cruntime->format || + runtime->rate != cruntime->rate || + runtime->channels != cruntime->channels || + is_access_interleaved(runtime->access) != + is_access_interleaved(cruntime->access); + if (!check) + return 0; + if (stream == SNDRV_PCM_STREAM_CAPTURE) + return -EIO; + else if (cruntime->state == SNDRV_PCM_STATE_RUNNING) + stop_capture = true; + } + + setup = get_setup(dpcm_play); + card = dpcm_play->loopback->card; + runtime = dpcm_play->substream->runtime; if (setup->format != runtime->format) { snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &setup->format_id); @@ -388,6 +394,10 @@ static int loopback_check_format(struct setup->access = runtime->access; } } + + if (stop_capture) + snd_pcm_stop(dpcm_capt->substream, SNDRV_PCM_STATE_DRAINING); + return 0; }