| From f939c5a3711f931faa89dcb4c1326b1221958811 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Fri, 7 Mar 2025 09:42:42 +0100 |
| Subject: ALSA: seq: Improve data consistency at polling |
| |
| From: Takashi Iwai <tiwai@suse.de> |
| |
| [ Upstream commit e3cd33ab17c33bd8f1a9df66ec83a15dd8f7afbb ] |
| |
| snd_seq_poll() calls snd_seq_write_pool_allocated() that reads out a |
| field in client->pool object, while it can be updated concurrently via |
| ioctls, as reported by syzbot. The data race itself is harmless, as |
| it's merely a poll() call, and the state is volatile. OTOH, the read |
| out of poll object info from the caller side is fragile, and we can |
| leave it better in snd_seq_pool_poll_wait() alone. |
| |
| A similar pattern is seen in snd_seq_kernel_client_write_poll(), too, |
| which is called from the OSS sequencer. |
| |
| This patch drops the pool checks from the caller side and add the |
| pool->lock in snd_seq_pool_poll_wait() for better data consistency. |
| |
| Reported-by: syzbot+2d373c9936c00d7e120c@syzkaller.appspotmail.com |
| Closes: https://lore.kernel.org/67c88903.050a0220.15b4b9.0028.GAE@google.com |
| Link: https://patch.msgid.link/20250307084246.29271-1-tiwai@suse.de |
| Signed-off-by: Takashi Iwai <tiwai@suse.de> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| sound/core/seq/seq_clientmgr.c | 5 +---- |
| sound/core/seq/seq_memory.c | 1 + |
| 2 files changed, 2 insertions(+), 4 deletions(-) |
| |
| diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c |
| index 0ae01b85bb18c..198683a69a534 100644 |
| --- a/sound/core/seq/seq_clientmgr.c |
| +++ b/sound/core/seq/seq_clientmgr.c |
| @@ -1164,8 +1164,7 @@ static __poll_t snd_seq_poll(struct file *file, poll_table * wait) |
| if (snd_seq_file_flags(file) & SNDRV_SEQ_LFLG_OUTPUT) { |
| |
| /* check if data is available in the pool */ |
| - if (!snd_seq_write_pool_allocated(client) || |
| - snd_seq_pool_poll_wait(client->pool, file, wait)) |
| + if (snd_seq_pool_poll_wait(client->pool, file, wait)) |
| mask |= EPOLLOUT | EPOLLWRNORM; |
| } |
| |
| @@ -2600,8 +2599,6 @@ int snd_seq_kernel_client_write_poll(int clientid, struct file *file, poll_table |
| if (client == NULL) |
| return -ENXIO; |
| |
| - if (! snd_seq_write_pool_allocated(client)) |
| - return 1; |
| if (snd_seq_pool_poll_wait(client->pool, file, wait)) |
| return 1; |
| return 0; |
| diff --git a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c |
| index 20155e3e87c6a..ccde0ca3d2082 100644 |
| --- a/sound/core/seq/seq_memory.c |
| +++ b/sound/core/seq/seq_memory.c |
| @@ -427,6 +427,7 @@ int snd_seq_pool_poll_wait(struct snd_seq_pool *pool, struct file *file, |
| poll_table *wait) |
| { |
| poll_wait(file, &pool->output_sleep, wait); |
| + guard(spinlock_irq)(&pool->lock); |
| return snd_seq_output_ok(pool); |
| } |
| |
| -- |
| 2.39.5 |
| |