From 680be9f82d4977d3410c513d3bfe912d100f64fc Mon Sep 17 00:00:00 2001 From: Cen Zhang Date: Sun, 18 Oct 2026 22:07:26 +0800 Subject: [PATCH] ALSA: pcm: Protect the unregister notifier traversal 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 Signed-off-by: Takashi Iwai Link: https://patch.msgid.link/pm-pmb-26d66390a25fec9fad6c-v6-5be251a3ac8832955a31-1@gmail.com --- 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, ®ister_mutex) + pcm_call_notify(pcm, n_unregister); + } if (pcm->private_free) pcm->private_free(pcm); snd_pcm_lib_preallocate_free_for_all(pcm);