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: dcca9b6064 ("ALSA: Add simple refcount helper functions")
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/patchset/20261015071838.31082-1-tiwai%40suse.de
Reviewed-by: Cen Zhang <zzzccc427@gmail.com>
Link: https://patch.msgid.link/20261015112256.3902-1-tiwai@suse.de
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Takashi Iwai 2026-10-15 13:22:41 +02:00
parent 91d0048a97
commit 6904743ab7
2 changed files with 5 additions and 1 deletions

View File

@ -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);

View File

@ -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);