Commit 53372133 authored by Cássio Gabriel's avatar Cássio Gabriel Committed by Takashi Iwai
Browse files

ALSA: core: Serialize deferred fasync state checks



snd_fasync_helper() updates fasync->on under snd_fasync_lock, and
snd_fasync_work_fn() now also evaluates fasync->on under the same
lock. snd_kill_fasync() still tests the flag before taking the lock,
leaving an unsynchronized read against FASYNC enable/disable updates.

Move the enabled-state check into the locked section.

Also clear fasync->on under snd_fasync_lock in snd_fasync_free()
before unlinking the pending entry. Together with the locked sender-side
check, this publishes teardown before flushing the deferred work and
prevents a racing sender from requeueing the entry after free has
started.

Fixes: ef34a0ae ("ALSA: core: Add async signal helpers")
Fixes: 8146cd33 ("ALSA: core: Fix potential data race at fasync handling")
Cc: stable@vger.kernel.org
Signed-off-by: default avatarCássio Gabriel <cassiogabrielcontato@gmail.com>
Link: https://patch.msgid.link/20260506-alsa-core-fasync-on-lock-v1-1-ea48c77d6ca4@gmail.com


Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 01801e20
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -148,9 +148,11 @@ EXPORT_SYMBOL_GPL(snd_fasync_helper);

void snd_kill_fasync(struct snd_fasync *fasync, int signal, int poll)
{
	if (!fasync || !fasync->on)
	if (!fasync)
		return;
	guard(spinlock_irqsave)(&snd_fasync_lock);
	if (!fasync->on)
		return;
	fasync->signal = signal;
	fasync->poll = poll;
	list_move(&fasync->list, &snd_fasync_list);
@@ -163,8 +165,10 @@ void snd_fasync_free(struct snd_fasync *fasync)
	if (!fasync)
		return;

	scoped_guard(spinlock_irq, &snd_fasync_lock)
	scoped_guard(spinlock_irq, &snd_fasync_lock) {
		fasync->on = 0;
		list_del_init(&fasync->list);
	}

	flush_work(&snd_fasync_work);
	kfree(fasync);