* [PATCH 6.1.y 0/2] ALSA: aloop: fix trigger/close UAFs
[not found] <2026050445-connector-rebuff-f713@gregkh>
@ 2026-09-01 9:13 ` Karl Mehltretter
2026-09-01 9:13 ` [PATCH 6.1.y 1/2] ALSA: aloop: Fix racy access at PCM trigger Karl Mehltretter
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Karl Mehltretter @ 2026-09-01 9:13 UTC (permalink / raw)
To: stable
Cc: Karl Mehltretter, Greg Kroah-Hartman, Jaroslav Kysela,
Takashi Iwai, Cássio Gabriel, linux-sound, linux-kernel
Backport the two ordered aloop fixes for the trigger/close peer-runtime
races. Both carry Cc: stable and each fixes a separate syzbot-reported
UAF, but neither reached this tree.
826af7fa62e3 ("ALSA: aloop: Fix racy access at PCM trigger") covers the
peer lookup and state checks with cable->lock. e5c33cdc6f40 ("ALSA:
aloop: Fix peer runtime UAF during format-change stop") pins an in-flight
peer stop across snd_pcm_stop(), which still runs after that lock is
dropped, so it applies only on top of the first.
The failed-apply report for this branch named only the second fix.
The series applies to v6.1.186 and v6.1.187-rc1. Patch 1 omits
access-mode support absent from this tree; patch 2 matches the 6.12.y
backport by patch-id. The identical 6.6.y backport is submitted
separately. 6.12.y and newer already contain both fixes.
KASAN/QEMU functional A/B tests passed: 4096 captured frames matched
byte-for-byte; control notifications, mismatch handling, and 32
open/close iterations passed; no KASAN, Oops, or WARNING was reported.
As upstream, a prepared-but-idle capture remains PREPARED when
mismatched playback starts instead of being forced to DRAINING.
Cássio Gabriel (1):
ALSA: aloop: Fix peer runtime UAF during format-change stop
Takashi Iwai (1):
ALSA: aloop: Fix racy access at PCM trigger
sound/drivers/aloop.c | 98 +++++++++++++++++++++++++++----------------
1 file changed, 62 insertions(+), 36 deletions(-)
--
2.53.0
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH 6.1.y 1/2] ALSA: aloop: Fix racy access at PCM trigger
2026-09-01 9:13 ` [PATCH 6.1.y 0/2] ALSA: aloop: fix trigger/close UAFs Karl Mehltretter
@ 2026-09-01 9:13 ` Karl Mehltretter
2026-09-01 9:13 ` [PATCH 6.1.y 2/2] ALSA: aloop: Fix peer runtime UAF during format-change stop Karl Mehltretter
2026-09-02 22:14 ` [PATCH 6.1.y 0/2] ALSA: aloop: fix trigger/close UAFs Sasha Levin
2 siblings, 0 replies; 4+ messages in thread
From: Karl Mehltretter @ 2026-09-01 9:13 UTC (permalink / raw)
To: stable
Cc: Karl Mehltretter, Greg Kroah-Hartman, Jaroslav Kysela,
Takashi Iwai, Cássio Gabriel, linux-sound, linux-kernel,
syzbot+5f8f3acdee1ec7a7ef7b, Takashi Iwai
From: Takashi Iwai <tiwai@suse.de>
[ Upstream commit 826af7fa62e347464b1b4e0ba2fe19a92438084f ]
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: <stable@vger.kernel.org>
Link: https://patch.msgid.link/20260203141003.116584-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
[ Karl Mehltretter: dropped the access-mode comparison and notification
(462494565c27, e299a9fd433f, cdac6e1f7164). ]
Assisted-by: LLM
Signed-off-by: Karl Mehltretter <kmehltretter@gmail.com>
---
sound/drivers/aloop.c | 58 +++++++++++++++++++++++++------------------
1 file changed, 34 insertions(+), 24 deletions(-)
diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c
index a38e602b4fc60..67bbadcec02b0 100644
--- a/sound/drivers/aloop.c
+++ b/sound/drivers/aloop.c
@@ -319,35 +319,41 @@ static int loopback_snd_timer_close_cable(struct loopback_pcm *dpcm)
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;
- 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;
+ 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);
@@ -364,6 +370,10 @@ static int loopback_check_format(struct loopback_cable *cable, int stream)
setup->channels = runtime->channels;
}
}
+
+ if (stop_capture)
+ snd_pcm_stop(dpcm_capt->substream, SNDRV_PCM_STATE_DRAINING);
+
return 0;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH 6.1.y 2/2] ALSA: aloop: Fix peer runtime UAF during format-change stop
2026-09-01 9:13 ` [PATCH 6.1.y 0/2] ALSA: aloop: fix trigger/close UAFs Karl Mehltretter
2026-09-01 9:13 ` [PATCH 6.1.y 1/2] ALSA: aloop: Fix racy access at PCM trigger Karl Mehltretter
@ 2026-09-01 9:13 ` Karl Mehltretter
2026-09-02 22:14 ` [PATCH 6.1.y 0/2] ALSA: aloop: fix trigger/close UAFs Sasha Levin
2 siblings, 0 replies; 4+ messages in thread
From: Karl Mehltretter @ 2026-09-01 9:13 UTC (permalink / raw)
To: stable
Cc: Karl Mehltretter, Greg Kroah-Hartman, Jaroslav Kysela,
Takashi Iwai, Cássio Gabriel, linux-sound, linux-kernel,
syzbot+8fa95c41eafbc9d2ff6f, Takashi Iwai, Sasha Levin
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>
[ used scoped_guard(spinlock_irq) instead of guard(spinlock_irq) ]
Signed-off-by: Sasha Levin <sashal@kernel.org>
[ Karl Mehltretter: 6.12.y commit 03f52a9c1704 applies to 6.1.y/6.6.y
unchanged; identical patch-id. ]
Assisted-by: LLM
Signed-off-by: Karl Mehltretter <kmehltretter@gmail.com>
---
sound/drivers/aloop.c | 44 +++++++++++++++++++++++++++++--------------
1 file changed, 30 insertions(+), 14 deletions(-)
diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c
index 67bbadcec02b0..64870381d66ec 100644
--- a/sound/drivers/aloop.c
+++ b/sound/drivers/aloop.c
@@ -98,6 +98,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;
@@ -347,8 +350,11 @@ static int loopback_check_format(struct loopback_cable *cable, int stream)
return 0;
if (stream == SNDRV_PCM_STREAM_CAPTURE)
return -EIO;
- else if (cruntime->state == SNDRV_PCM_STATE_RUNNING)
+ else if (cruntime->state == SNDRV_PCM_STATE_RUNNING) {
+ /* close must not free the peer runtime below */
+ atomic_inc(&cable->stop_count);
stop_capture = true;
+ }
}
setup = get_setup(dpcm_play);
@@ -371,8 +377,11 @@ static int loopback_check_format(struct loopback_cable *cable, int stream)
}
}
- if (stop_capture)
+ if (stop_capture) {
snd_pcm_stop(dpcm_capt->substream, SNDRV_PCM_STATE_DRAINING);
+ if (atomic_dec_and_test(&cable->stop_count))
+ wake_up(&cable->stop_wait);
+ }
return 0;
}
@@ -1004,24 +1013,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);
+ scoped_guard(spinlock_irq, &cable->lock) {
+ cable->streams[substream->stream] = NULL;
+ other_alive = cable->streams[!substream->stream];
}
+
+ /* 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)
@@ -1216,6 +1230,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
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH 6.1.y 0/2] ALSA: aloop: fix trigger/close UAFs
2026-09-01 9:13 ` [PATCH 6.1.y 0/2] ALSA: aloop: fix trigger/close UAFs Karl Mehltretter
2026-09-01 9:13 ` [PATCH 6.1.y 1/2] ALSA: aloop: Fix racy access at PCM trigger Karl Mehltretter
2026-09-01 9:13 ` [PATCH 6.1.y 2/2] ALSA: aloop: Fix peer runtime UAF during format-change stop Karl Mehltretter
@ 2026-09-02 22:14 ` Sasha Levin
2 siblings, 0 replies; 4+ messages in thread
From: Sasha Levin @ 2026-09-02 22:14 UTC (permalink / raw)
To: stable
Cc: Sasha Levin, Karl Mehltretter, Greg Kroah-Hartman,
Jaroslav Kysela, Takashi Iwai, Cássio Gabriel, linux-sound,
linux-kernel
> Backport the two ordered aloop fixes for the trigger/close peer-runtime
> races. Both carry Cc: stable and each fixes a separate syzbot-reported
> UAF, but neither reached this tree.
Queued for 6.1, thanks.
--
Thanks,
Sasha
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-09-02 22:14 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
[not found] <2026050445-connector-rebuff-f713@gregkh>
2026-09-01 9:13 ` [PATCH 6.1.y 0/2] ALSA: aloop: fix trigger/close UAFs Karl Mehltretter
2026-09-01 9:13 ` [PATCH 6.1.y 1/2] ALSA: aloop: Fix racy access at PCM trigger Karl Mehltretter
2026-09-01 9:13 ` [PATCH 6.1.y 2/2] ALSA: aloop: Fix peer runtime UAF during format-change stop Karl Mehltretter
2026-09-02 22:14 ` [PATCH 6.1.y 0/2] ALSA: aloop: fix trigger/close UAFs Sasha Levin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox