From 6904743ab77e0684dff319f3806ef982e5eea6cf Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 15 Oct 2026 13:22:41 +0200 Subject: [PATCH] ALSA: core: Serialize snd_refcount put and sync When a thread tries to sync-and-destroy the resource with snd_refcount_sync(), it might lead to a UAF in a very slight time window. Namely, snd_refount_put() calls wake_up() after atomic_dec_and_test(), but wait_event() in snd_refcount_sync() checks the condition via atomic_test() without serialization, hence the thread that called snd_refcount_sync() can continue immediately to release the resource before another thread calls wake_up(). For avoiding the race above, introduce the spinlock and take it at snd_refcount_put() and snd_refcount_sync() in order to serialize the operations. Fixes: dcca9b6064c3 ("ALSA: Add simple refcount helper functions") Reported-by: Sashiko Closes: https://sashiko.dev/#/patchset/20261015071838.31082-1-tiwai%40suse.de Reviewed-by: Cen Zhang Link: https://patch.msgid.link/20261015112256.3902-1-tiwai@suse.de Signed-off-by: Takashi Iwai --- include/sound/core.h | 1 + sound/core/misc.c | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/include/sound/core.h b/include/sound/core.h index daa91a46a16b..657b12e1e95b 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -84,6 +84,7 @@ struct snd_device { struct snd_refcount { atomic_t count; wait_queue_head_t waiter; + spinlock_t lock; }; void snd_refcount_init(struct snd_refcount *ref); diff --git a/sound/core/misc.c b/sound/core/misc.c index 066fb9ecdcdc..6fe199e76e83 100644 --- a/sound/core/misc.c +++ b/sound/core/misc.c @@ -183,11 +183,13 @@ void snd_refcount_init(struct snd_refcount *ref) { atomic_set(&ref->count, 0); init_waitqueue_head(&ref->waiter); + spin_lock_init(&ref->lock); } EXPORT_SYMBOL_GPL(snd_refcount_init); void snd_refcount_put(struct snd_refcount *ref) { + guard(spinlock_irqsave)(&ref->lock); if (atomic_dec_and_test(&ref->count)) wake_up(&ref->waiter); } @@ -195,6 +197,7 @@ EXPORT_SYMBOL_GPL(snd_refcount_put); void snd_refcount_sync(struct snd_refcount *ref) { - wait_event(ref->waiter, !atomic_read(&ref->count)); + guard(spinlock_irq)(&ref->lock); + wait_event_lock_irq(ref->waiter, !atomic_read(&ref->count), ref->lock); } EXPORT_SYMBOL_GPL(snd_refcount_sync);