Skip to content

Commit c520ff3

Browse files
committed
ALSA: seq: Fix racy cell insertions during snd_seq_pool_done()
When snd_seq_pool_done() is called, it marks the closing flag to refuse the further cell insertions. But snd_seq_pool_done() itself doesn't clear the cells but just waits until all cells are cleared by the caller side. That is, it's racy, and this leads to the endless stall as syzkaller spotted. This patch addresses the racy by splitting the setup of pool->closing flag out of snd_seq_pool_done(), and calling it properly before snd_seq_pool_done(). BugLink: http://lkml.kernel.org/r/CACT4Y+aqqy8bZA1fFieifNxR2fAfFQQABcBHj801+u5ePV0URw@mail.gmail.com Reported-and-tested-by: Dmitry Vyukov <[email protected]> Cc: <[email protected]> Signed-off-by: Takashi Iwai <[email protected]>
1 parent c6736a9 commit c520ff3

File tree

4 files changed

+18
-4
lines changed

4 files changed

+18
-4
lines changed

sound/core/seq/seq_clientmgr.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1832,6 +1832,7 @@ static int snd_seq_ioctl_set_client_pool(struct snd_seq_client *client,
18321832
info->output_pool != client->pool->size)) {
18331833
if (snd_seq_write_pool_allocated(client)) {
18341834
/* remove all existing cells */
1835+
snd_seq_pool_mark_closing(client->pool);
18351836
snd_seq_queue_client_leave_cells(client->number);
18361837
snd_seq_pool_done(client->pool);
18371838
}

sound/core/seq/seq_fifo.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ void snd_seq_fifo_delete(struct snd_seq_fifo **fifo)
7272
return;
7373
*fifo = NULL;
7474

75+
if (f->pool)
76+
snd_seq_pool_mark_closing(f->pool);
77+
7578
snd_seq_fifo_clear(f);
7679

7780
/* wake up clients if any */

sound/core/seq/seq_memory.c

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -415,6 +415,18 @@ int snd_seq_pool_init(struct snd_seq_pool *pool)
415415
return 0;
416416
}
417417

418+
/* refuse the further insertion to the pool */
419+
void snd_seq_pool_mark_closing(struct snd_seq_pool *pool)
420+
{
421+
unsigned long flags;
422+
423+
if (snd_BUG_ON(!pool))
424+
return;
425+
spin_lock_irqsave(&pool->lock, flags);
426+
pool->closing = 1;
427+
spin_unlock_irqrestore(&pool->lock, flags);
428+
}
429+
418430
/* remove events */
419431
int snd_seq_pool_done(struct snd_seq_pool *pool)
420432
{
@@ -425,10 +437,6 @@ int snd_seq_pool_done(struct snd_seq_pool *pool)
425437
return -EINVAL;
426438

427439
/* wait for closing all threads */
428-
spin_lock_irqsave(&pool->lock, flags);
429-
pool->closing = 1;
430-
spin_unlock_irqrestore(&pool->lock, flags);
431-
432440
if (waitqueue_active(&pool->output_sleep))
433441
wake_up(&pool->output_sleep);
434442

@@ -485,6 +493,7 @@ int snd_seq_pool_delete(struct snd_seq_pool **ppool)
485493
*ppool = NULL;
486494
if (pool == NULL)
487495
return 0;
496+
snd_seq_pool_mark_closing(pool);
488497
snd_seq_pool_done(pool);
489498
kfree(pool);
490499
return 0;

sound/core/seq/seq_memory.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ static inline int snd_seq_total_cells(struct snd_seq_pool *pool)
8484
int snd_seq_pool_init(struct snd_seq_pool *pool);
8585

8686
/* done pool - free events */
87+
void snd_seq_pool_mark_closing(struct snd_seq_pool *pool);
8788
int snd_seq_pool_done(struct snd_seq_pool *pool);
8889

8990
/* create pool */

0 commit comments

Comments
 (0)