[PATCH v3 1/2] ALSA: pcm: Protect the unregister notifier traversal

From: Cen Zhang

Date: Sun Oct 18 2026 - 10:08:17 EST


snd_pcm_free() traverses snd_pcm_notify_list and calls n_unregister
without register_mutex, although snd_pcm_notify() takes that mutex to
add and remove notifiers. PCM disconnect releases the mutex before the
free callback runs, so it does not protect this later traversal.

With no open OSS file, normal snd-pcm-oss removal can overlap PCM card
teardown, for example when unbinding snd-dummy:

PCM card teardown snd-pcm-oss unload
----------------- ------------------
snd_pcm_dev_disconnect()
remove PCM under register_mutex
unlock register_mutex
snd_pcm_free()
fetch notifier
snd_pcm_notify(..., 1)
unlink notifier under mutex
free module storage
read notifier->n_unregister
invoke callback

The free path can then read the notifier from released module storage
or call its unloaded code.

Hold register_mutex across the unregister traversal and its callbacks.
Notifier removal must wait until both have finished. This also protects
the traversal if a callback releases the last module reference: module
exit cannot unlink its notifier until the free path releases the mutex.
Drop the mutex before private_free and the remaining stream cleanup.

Fixes: c461482c8072 ("[ALSA] Unregister device files at disconnection")
Assisted-by: LLM
Signed-off-by: Cen Zhang <zzzccc427@xxxxxxxxx>
---
sound/core/pcm.c | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index c133f23418fe..35ece386d1a2 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -853,8 +853,10 @@ static int snd_pcm_free(struct snd_pcm *pcm)
{
if (!pcm)
return 0;
- if (!pcm->internal)
- pcm_call_notify(pcm, n_unregister);
+ if (!pcm->internal) {
+ scoped_guard(mutex, &register_mutex)
+ pcm_call_notify(pcm, n_unregister);
+ }
if (pcm->private_free)
pcm->private_free(pcm);
snd_pcm_lib_preallocate_free_for_all(pcm);

base-commit: f6e8d5ebde5ceb7d3c0eef6e9e4d82862b503ade
--
2.43.0