From: Sasha Levin <sashal@kernel.org>
To: stable@vger.kernel.org
Cc: "Cássio Gabriel" <cassiogabrielcontato@gmail.com>,
syzbot+8fa95c41eafbc9d2ff6f@syzkaller.appspotmail.com,
"Takashi Iwai" <tiwai@suse.com>, "Takashi Iwai" <tiwai@suse.de>,
"Sasha Levin" <sashal@kernel.org>
Subject: [PATCH 5.10.y] ALSA: aloop: Fix peer runtime UAF during format-change stop
Date: Sun, 10 May 2026 09:38:00 -0400 [thread overview]
Message-ID: <20260510133800.4137265-1-sashal@kernel.org> (raw)
In-Reply-To: <2026050447-aerospace-stingy-18bd@gregkh>
From: Cássio Gabriel <cassiogabrielcontato@gmail.com>
[ Upstream commit e5c33cdc6f402eab8abd36ecf436b22c9d3a8aff ]
loopback_check_format() may stop the capture side when playback starts
with parameters that no longer match a running capture stream. Commit
826af7fa62e3 ("ALSA: aloop: Fix racy access at PCM trigger") moved
the peer lookup under cable->lock, but the actual snd_pcm_stop() still
runs after dropping that lock.
A concurrent close can clear the capture entry from cable->streams[] and
detach or free its runtime while the playback trigger path still holds a
stale peer substream pointer.
Keep a per-cable count of in-flight peer stops before dropping
cable->lock, and make free_cable() wait for those stops before
detaching the runtime. This preserves the existing behavior while
making the peer runtime lifetime explicit.
Reported-by: syzbot+8fa95c41eafbc9d2ff6f@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=8fa95c41eafbc9d2ff6f
Fixes: 597603d615d2 ("ALSA: introduce the snd-aloop module for the PCM loopback")
Cc: stable@vger.kernel.org
Suggested-by: Takashi Iwai <tiwai@suse.com>
Signed-off-by: Cássio Gabriel <cassiogabrielcontato@gmail.com>
Link: https://patch.msgid.link/20260424-alsa-aloop-peer-stop-uaf-v2-1-94e68101db8a@gmail.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
[ collapsed inc/snd_pcm_stop/dec into the existing inline call site and used spin_lock_irq/unlock_irq instead of scoped_guard ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
sound/drivers/aloop.c | 40 +++++++++++++++++++++++++++-------------
1 file changed, 27 insertions(+), 13 deletions(-)
diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c
index fb45a32d99cd9..314ced32efbbc 100644
--- a/sound/drivers/aloop.c
+++ b/sound/drivers/aloop.c
@@ -99,6 +99,9 @@ struct loopback_ops {
struct loopback_cable {
spinlock_t lock;
struct loopback_pcm *streams[2];
+ /* in-flight peer stops running outside cable->lock */
+ atomic_t stop_count;
+ wait_queue_head_t stop_wait;
struct snd_pcm_hardware hw;
/* flags */
unsigned int valid;
@@ -342,8 +345,12 @@ static int loopback_check_format(struct loopback_cable *cable, int stream)
if (stream == SNDRV_PCM_STREAM_CAPTURE) {
return -EIO;
} else {
+ /* close must not free the peer runtime below */
+ atomic_inc(&cable->stop_count);
snd_pcm_stop(cable->streams[SNDRV_PCM_STREAM_CAPTURE]->
substream, SNDRV_PCM_STATE_DRAINING);
+ if (atomic_dec_and_test(&cable->stop_count))
+ wake_up(&cable->stop_wait);
__notify:
runtime = cable->streams[SNDRV_PCM_STREAM_PLAYBACK]->
substream->runtime;
@@ -995,24 +1002,29 @@ static void free_cable(struct snd_pcm_substream *substream)
struct loopback *loopback = substream->private_data;
int dev = get_cable_index(substream);
struct loopback_cable *cable;
+ struct loopback_pcm *dpcm;
+ bool other_alive;
cable = loopback->cables[substream->number][dev];
if (!cable)
return;
- if (cable->streams[!substream->stream]) {
- /* other stream is still alive */
- spin_lock_irq(&cable->lock);
- cable->streams[substream->stream] = NULL;
- spin_unlock_irq(&cable->lock);
- } else {
- struct loopback_pcm *dpcm = substream->runtime->private_data;
- if (cable->ops && cable->ops->close_cable && dpcm)
- cable->ops->close_cable(dpcm);
- /* free the cable */
- loopback->cables[substream->number][dev] = NULL;
- kfree(cable);
- }
+ spin_lock_irq(&cable->lock);
+ cable->streams[substream->stream] = NULL;
+ other_alive = cable->streams[!substream->stream] != NULL;
+ spin_unlock_irq(&cable->lock);
+
+ /* Pair with the stop_count increment in loopback_check_format(). */
+ wait_event(cable->stop_wait, !atomic_read(&cable->stop_count));
+ if (other_alive)
+ return;
+
+ dpcm = substream->runtime->private_data;
+ if (cable->ops && cable->ops->close_cable && dpcm)
+ cable->ops->close_cable(dpcm);
+ /* free the cable */
+ loopback->cables[substream->number][dev] = NULL;
+ kfree(cable);
}
static int loopback_jiffies_timer_open(struct loopback_pcm *dpcm)
@@ -1207,6 +1219,8 @@ static int loopback_open(struct snd_pcm_substream *substream)
goto unlock;
}
spin_lock_init(&cable->lock);
+ atomic_set(&cable->stop_count, 0);
+ init_waitqueue_head(&cable->stop_wait);
cable->hw = loopback_pcm_hardware;
if (loopback->timer_source)
cable->ops = &loopback_snd_timer_ops;
--
2.53.0
prev parent reply other threads:[~2026-05-10 13:38 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-04 12:45 FAILED: patch "[PATCH] ALSA: aloop: Fix peer runtime UAF during format-change stop" failed to apply to 5.10-stable tree gregkh
2026-05-10 13:38 ` Sasha Levin [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260510133800.4137265-1-sashal@kernel.org \
--to=sashal@kernel.org \
--cc=cassiogabrielcontato@gmail.com \
--cc=stable@vger.kernel.org \
--cc=syzbot+8fa95c41eafbc9d2ff6f@syzkaller.appspotmail.com \
--cc=tiwai@suse.com \
--cc=tiwai@suse.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox