[alsa-devel] sound: uninterruptible hang in snd_seq_oss_writeq_sync
Hello,
The following program creates an unkillable process:
// autogenerated by syzkaller (http://github.com/google/syzkaller) #include <pthread.h> #include <stdint.h> #include <string.h> #include <sys/syscall.h> #include <unistd.h>
#ifndef SYS_mmap #define SYS_mmap 9 #endif #ifndef SYS_syz_open_dev #define SYS_syz_open_dev 1000001 #endif #ifndef SYS_write #define SYS_write 1 #endif #ifndef SYS_read #define SYS_read 0 #endif #ifndef SYS_sync_file_range #define SYS_sync_file_range 277 #endif
long r[61];
int main() { memset(r, -1, sizeof(r)); r[0] = syscall(SYS_mmap, 0x20000000ul, 0x5e000ul, 0x3ul, 0x32ul, 0xfffffffffffffffful, 0x0ul); r[2] = syscall(SYS_open, "/dev/sequencer", 0x202ul, 0, 0, 0); *(uint8_t*)0x20057000 = (uint8_t)0x7; *(uint8_t*)0x20057001 = (uint8_t)0x6; *(uint8_t*)0x20057002 = (uint8_t)0x3; *(uint8_t*)0x20057003 = (uint8_t)0x99be; *(uint32_t*)0x2005700c = (uint32_t)0x4; *(uint8_t*)0x20057010 = (uint8_t)0x5; *(uint8_t*)0x20057011 = (uint8_t)0xffffffffffffffff; *(uint8_t*)0x20057012 = (uint8_t)0x100; *(uint8_t*)0x20057013 = (uint8_t)0x1; *(uint8_t*)0x20057024 = (uint8_t)0x8; *(uint8_t*)0x20057025 = (uint8_t)0xabe4; *(uint16_t*)0x20057026 = (uint16_t)0x3; *(uint64_t*)0x20057028 = (uint64_t)0x2005055c; *(uint8_t*)0x20057030 = (uint8_t)0xffffffffffffffe0; *(uint8_t*)0x20057031 = (uint8_t)0xffffffffffffffb8; *(uint8_t*)0x20057032 = (uint8_t)0x8; *(uint8_t*)0x20057033 = (uint8_t)0x7; *(uint32_t*)0x2005703c = (uint32_t)0x5; *(uint8_t*)0x20057040 = (uint8_t)0x5; *(uint8_t*)0x20057041 = (uint8_t)0x401; *(uint8_t*)0x20057042 = (uint8_t)0x8; *(uint8_t*)0x20057043 = (uint8_t)0x4; *(uint8_t*)0x2005704c = (uint8_t)0x0; *(uint8_t*)0x2005704d = (uint8_t)0x3; *(uint8_t*)0x2005704e = (uint8_t)0x200; *(uint8_t*)0x2005704f = (uint8_t)0xee; *(uint8_t*)0x20057050 = (uint8_t)0x2; *(uint8_t*)0x20057051 = (uint8_t)0x8; *(uint8_t*)0x20057052 = (uint8_t)0x800; *(uint8_t*)0x20057053 = (uint8_t)0xfffffffffffff000; *(uint64_t*)0x20057068 = (uint64_t)0x77359400; *(uint64_t*)0x20057070 = (uint64_t)0x0; *(uint8_t*)0x20057078 = (uint8_t)0x10000; *(uint8_t*)0x20057079 = (uint8_t)0x946; *(uint8_t*)0x2005707a = (uint8_t)0x1; *(uint8_t*)0x2005707b = (uint8_t)0x1ff; *(uint8_t*)0x2005708c = (uint8_t)0x3; *(uint32_t*)0x20057090 = (uint32_t)0x7; *(uint32_t*)0x20057094 = (uint32_t)0x1; *(uint8_t*)0x20057098 = (uint8_t)0x2; *(uint8_t*)0x20057099 = (uint8_t)0x7ff; *(uint8_t*)0x2005709a = (uint8_t)0x8; *(uint8_t*)0x2005709b = (uint8_t)0xdd8; *(uint64_t*)0x200570b0 = (uint64_t)0x1; *(uint64_t*)0x200570b8 = (uint64_t)0x0; *(uint8_t*)0x200570c0 = (uint8_t)0x9; *(uint8_t*)0x200570c1 = (uint8_t)0x3; *(uint8_t*)0x200570c2 = (uint8_t)0x7ff; *(uint8_t*)0x200570c3 = (uint8_t)0x8; *(uint32_t*)0x200570d4 = (uint32_t)0xec; *(uint64_t*)0x200570d8 = (uint64_t)0x20053f14; memcpy((void*)0x2005055c, "\xa4\x62\xd2\xb0\x88\xe0\x2b\xbd\xea\xa1\xa5\xf7\x7b\x89\xca" "\xb0\x43\xca\x19\x6d\x70\xb6\xa6\xcd\x30\xaa\x98\x07\xb3\xf3" "\xea\xf8\x44\x19\xc8\x83\xbc\xb7\x33\xd1\xd0\x5e\x8f\x34\x12" "\x82\xb4\xf8\xbd\x02\x63\x0b\xe7\x45\x23\x40\xa4\x51\x40\x23" "\x01\xcc\x57\x89\x40\x9c\xc1\x29\x36\xe2\xc0\x70\xe5\xda\xc9" "\x1f\x40\x25\xe0\x74\x98\x07\x75\xe9\x5a\xfc\x0e\x10\x3f\xd9" "\x4b\xc3\xc2\x48\xfa\x18\xb8\xda\x49\x3e\xeb\x69\x2c\x4b\xd2" "\xb7\xac\xc6\x5a\x1c\xfd", 111); memcpy((void*)0x20053f14, "\x1b\x4b\xa5\x94\xeb\xe1\xd9\x4b\x57\xf2\xeb\xab\xdd\xe5\xba" "\x24\xf2\xc8\x36\x90\x88\x21\x2c\xec\x8e\x5a\x0d\x24\x0f\x48" "\xcc\x0d\x3c\xab\x21\x8e\xfa\x8f\x0d\xcd\x8d\x14\x99\xc3\x64" "\xea\x7f\xf3\x88\xe9\xf7\x4f\x4c\x12\xe9\x0e\x23\xad\x73\x7d" "\xa3\x4c\x45\x3f\xb3\x48\xb7\x44\x89\x41\x20\x7b\x2c\xbd\xf2" "\x89\x16\x1f\xbd\x80\x24\x72\xa1\x8d\x4b\x13\x74\xb2\xf4\xdf" "\x49\xe0\x6c\x40\x0d\xf2\x7c\x8a\xbf\xf2\xb1\x62\xe0\x7e\x51" "\x9a\xd4\x60\x64\x49\x96\x4b\x83\x91\xe5\x51\x50\x94\x3c\x41" "\xf6\xd1\xef\x1f\x90\x5a\x48\xa5\xe2\xf8\xe3\xd9\xf9\x82\x5e" "\xa1\x5c\x85\x1c\xbe\x47\xa2\x29\xb7\x5a\xf4\x14\x24\x92\x11" "\x4b\x6b\x54\x95\x5e\x9f\x1b\xda\x02\xa3\x84\xb3\x2b\x07\x13" "\x18\x6b\x31\xb4\xc1\x04\x30\x5f\xa0\xa2\xe9\xe6\x50\x6f\xed" "\x15\x10\xf5\xda\xa1\xe5\x06\xaf\x28\xe0\x53\xea\x88\x49\xf8" "\x97\x52\x4b\xe8\xa2\xce\x9f\xc7\x47\x4f\xd6\xc0\xe2\xb7\xc1" "\x7f\xa9\x54\x3d\x11\xe4\x99\x28\x65\x39\xb1\xf3\xec\x48\x43" "\x58\x19\x12\xf6\x38\x5b\xee\xca\x33\x8e\x4d", 236); r[56] = syscall(SYS_write, r[2], 0x20057000ul, 0x9cul, 0, 0, 0); memcpy((void*)0x2005bfa7, "\x2f\x64\x65\x76\x2f\x76\x68\x63\x69\x00", 10); return 0; }
The hang stack is:
[<ffffffff85309f77>] snd_seq_oss_writeq_sync+0x327/0x790 sound/core/seq/oss/seq_oss_writeq.c:121 [<ffffffff852fa353>] snd_seq_oss_drain_write+0x113/0x160 sound/core/seq/oss/seq_oss_init.c:448 [<ffffffff852f8d04>] odev_release+0x44/0x80 sound/core/seq/oss/seq_oss.c:152 [<ffffffff817ccdc6>] __fput+0x236/0x780 fs/file_table.c:208 [<ffffffff817cd395>] ____fput+0x15/0x20 fs/file_table.c:244 [<ffffffff813b8db0>] task_work_run+0x170/0x210 kernel/task_work.c:115 [< inline >] exit_task_work include/linux/task_work.h:21 [<ffffffff81363ca0>] do_exit+0xaf0/0x2d20 kernel/exit.c:748 [<ffffffff81366048>] do_group_exit+0x108/0x330 kernel/exit.c:878 [< inline >] SYSC_exit_group kernel/exit.c:889 [<ffffffff8136628d>] SyS_exit_group+0x1d/0x20 kernel/exit.c:887 [<ffffffff866a3236>] entry_SYSCALL_64_fastpath+0x16/0x7a arch/x86/entry/entry_64.S:185
On commit fc77dbd34c5c99bce46d40a2491937c3bcbd10af (4.5-rc6).
On Tue, 01 Mar 2016 13:33:27 +0100, Dmitry Vyukov wrote:
Hello,
The following program creates an unkillable process:
.....
The hang stack is:
[<ffffffff85309f77>] snd_seq_oss_writeq_sync+0x327/0x790 sound/core/seq/oss/seq_oss_writeq.c:121
This is wait_event_interruptible_timeout(q->sync_sleep, ! q->sync_event_put, HZ);
and this should return zero if (signal_pending(current)) /* interrupted - return 0 to finish sync */ q->sync_event_put = 0; if (! q->sync_event_put || q->sync_time >= time) return 0; return 1;
[<ffffffff852fa353>] snd_seq_oss_drain_write+0x113/0x160
... and this loop should break: while (snd_seq_oss_writeq_sync(dp->writeq)) ;
So, I see no obvious error in the code, so far.
I'm running your test program now with 8 parallel runs, but I couldn't reproduce it. Any other specifics?
thanks,
Takashi
On Tue, Mar 1, 2016 at 3:44 PM, Takashi Iwai tiwai@suse.de wrote:
On Tue, 01 Mar 2016 13:33:27 +0100, Dmitry Vyukov wrote:
Hello,
The following program creates an unkillable process:
.....
The hang stack is:
[<ffffffff85309f77>] snd_seq_oss_writeq_sync+0x327/0x790 sound/core/seq/oss/seq_oss_writeq.c:121
This is wait_event_interruptible_timeout(q->sync_sleep, ! q->sync_event_put, HZ);
and this should return zero if (signal_pending(current)) /* interrupted - return 0 to finish sync */ q->sync_event_put = 0; if (! q->sync_event_put || q->sync_time >= time) return 0; return 1;
[<ffffffff852fa353>] snd_seq_oss_drain_write+0x113/0x160
... and this loop should break: while (snd_seq_oss_writeq_sync(dp->writeq)) ;
So, I see no obvious error in the code, so far.
I'm running your test program now with 8 parallel runs, but I couldn't reproduce it. Any other specifics?
thanks,
Takashi
On Tue, Mar 1, 2016 at 4:01 PM, Dmitry Vyukov dvyukov@google.com wrote:
On Tue, Mar 1, 2016 at 3:44 PM, Takashi Iwai tiwai@suse.de wrote:
On Tue, 01 Mar 2016 13:33:27 +0100, Dmitry Vyukov wrote:
Hello,
The following program creates an unkillable process:
.....
The hang stack is:
[<ffffffff85309f77>] snd_seq_oss_writeq_sync+0x327/0x790 sound/core/seq/oss/seq_oss_writeq.c:121
This is wait_event_interruptible_timeout(q->sync_sleep, ! q->sync_event_put, HZ);
and this should return zero if (signal_pending(current)) /* interrupted - return 0 to finish sync */ q->sync_event_put = 0; if (! q->sync_event_put || q->sync_time >= time) return 0; return 1;
[<ffffffff852fa353>] snd_seq_oss_drain_write+0x113/0x160
... and this loop should break: while (snd_seq_oss_writeq_sync(dp->writeq)) ;
So, I see no obvious error in the code, so far.
I'm running your test program now with 8 parallel runs, but I couldn't reproduce it. Any other specifics?
Hummm.. for me this process hangs every time, even if I just run it once from console. I've now retested in on clean commit fc77dbd34c5c99bce46d40a2491937c3bcbd10af (without KASAN/KCOV and with release gcc) and also got the same hang. I can only think of a different config. I've attached mine, please try with it.
Are signals delivered if we are already in process of dying? When I kill -9 this process it does not react, so presumably wait is not unblocked...
On Tue, 01 Mar 2016 16:04:43 +0100, Dmitry Vyukov wrote:
On Tue, Mar 1, 2016 at 4:01 PM, Dmitry Vyukov dvyukov@google.com wrote:
On Tue, Mar 1, 2016 at 3:44 PM, Takashi Iwai tiwai@suse.de wrote:
On Tue, 01 Mar 2016 13:33:27 +0100, Dmitry Vyukov wrote:
Hello,
The following program creates an unkillable process:
.....
The hang stack is:
[<ffffffff85309f77>] snd_seq_oss_writeq_sync+0x327/0x790 sound/core/seq/oss/seq_oss_writeq.c:121
This is wait_event_interruptible_timeout(q->sync_sleep, ! q->sync_event_put, HZ);
and this should return zero if (signal_pending(current)) /* interrupted - return 0 to finish sync */ q->sync_event_put = 0; if (! q->sync_event_put || q->sync_time >= time) return 0; return 1;
[<ffffffff852fa353>] snd_seq_oss_drain_write+0x113/0x160
... and this loop should break: while (snd_seq_oss_writeq_sync(dp->writeq)) ;
So, I see no obvious error in the code, so far.
I'm running your test program now with 8 parallel runs, but I couldn't reproduce it. Any other specifics?
Hummm.. for me this process hangs every time, even if I just run it once from console. I've now retested in on clean commit fc77dbd34c5c99bce46d40a2491937c3bcbd10af (without KASAN/KCOV and with release gcc) and also got the same hang. I can only think of a different config. I've attached mine, please try with it.
Are signals delivered if we are already in process of dying? When I kill -9 this process it does not react, so presumably wait is not unblocked...
Good point.
But above all, it doesn't make much sense to loop this sync call. When wait_event*() returns, it should go out. So, the patch like below should be good enough and fix your issue, too.
Takashi
--- diff --git a/sound/core/seq/oss/seq_oss_writeq.c b/sound/core/seq/oss/seq_oss_writeq.c index 1f6788a18444..4014a5469d1a 100644 --- a/sound/core/seq/oss/seq_oss_writeq.c +++ b/sound/core/seq/oss/seq_oss_writeq.c @@ -119,12 +119,7 @@ snd_seq_oss_writeq_sync(struct seq_oss_writeq *q) }
wait_event_interruptible_timeout(q->sync_sleep, ! q->sync_event_put, HZ); - if (signal_pending(current)) - /* interrupted - return 0 to finish sync */ - q->sync_event_put = 0; - if (! q->sync_event_put || q->sync_time >= time) - return 0; - return 1; + return 0; }
/*
On Tue, Mar 1, 2016 at 4:31 PM, Takashi Iwai tiwai@suse.de wrote:
On Tue, 01 Mar 2016 16:04:43 +0100, Dmitry Vyukov wrote:
On Tue, Mar 1, 2016 at 4:01 PM, Dmitry Vyukov dvyukov@google.com wrote:
On Tue, Mar 1, 2016 at 3:44 PM, Takashi Iwai tiwai@suse.de wrote:
On Tue, 01 Mar 2016 13:33:27 +0100, Dmitry Vyukov wrote:
Hello,
The following program creates an unkillable process:
.....
The hang stack is:
[<ffffffff85309f77>] snd_seq_oss_writeq_sync+0x327/0x790 sound/core/seq/oss/seq_oss_writeq.c:121
This is wait_event_interruptible_timeout(q->sync_sleep, ! q->sync_event_put, HZ);
and this should return zero if (signal_pending(current)) /* interrupted - return 0 to finish sync */ q->sync_event_put = 0; if (! q->sync_event_put || q->sync_time >= time) return 0; return 1;
[<ffffffff852fa353>] snd_seq_oss_drain_write+0x113/0x160
... and this loop should break: while (snd_seq_oss_writeq_sync(dp->writeq)) ;
So, I see no obvious error in the code, so far.
I'm running your test program now with 8 parallel runs, but I couldn't reproduce it. Any other specifics?
Hummm.. for me this process hangs every time, even if I just run it once from console. I've now retested in on clean commit fc77dbd34c5c99bce46d40a2491937c3bcbd10af (without KASAN/KCOV and with release gcc) and also got the same hang. I can only think of a different config. I've attached mine, please try with it.
Are signals delivered if we are already in process of dying? When I kill -9 this process it does not react, so presumably wait is not unblocked...
Good point.
But above all, it doesn't make much sense to loop this sync call. When wait_event*() returns, it should go out. So, the patch like below should be good enough and fix your issue, too.
The patch fixes the hang for me. There is a second delay at exit, but otherwise the process exits fine.
Tested-by: Dmitry Vyukov dvyukov@google.com
Thanks for quick fix!
diff --git a/sound/core/seq/oss/seq_oss_writeq.c b/sound/core/seq/oss/seq_oss_writeq.c index 1f6788a18444..4014a5469d1a 100644 --- a/sound/core/seq/oss/seq_oss_writeq.c +++ b/sound/core/seq/oss/seq_oss_writeq.c @@ -119,12 +119,7 @@ snd_seq_oss_writeq_sync(struct seq_oss_writeq *q) }
wait_event_interruptible_timeout(q->sync_sleep, ! q->sync_event_put, HZ);
if (signal_pending(current))
/* interrupted - return 0 to finish sync */
q->sync_event_put = 0;
if (! q->sync_event_put || q->sync_time >= time)
return 0;
return 1;
return 0;
}
/*
On Tue, 01 Mar 2016 16:45:22 +0100, Dmitry Vyukov wrote:
On Tue, Mar 1, 2016 at 4:31 PM, Takashi Iwai tiwai@suse.de wrote:
On Tue, 01 Mar 2016 16:04:43 +0100, Dmitry Vyukov wrote:
On Tue, Mar 1, 2016 at 4:01 PM, Dmitry Vyukov dvyukov@google.com wrote:
On Tue, Mar 1, 2016 at 3:44 PM, Takashi Iwai tiwai@suse.de wrote:
On Tue, 01 Mar 2016 13:33:27 +0100, Dmitry Vyukov wrote:
Hello,
The following program creates an unkillable process:
.....
The hang stack is:
[<ffffffff85309f77>] snd_seq_oss_writeq_sync+0x327/0x790 sound/core/seq/oss/seq_oss_writeq.c:121
This is wait_event_interruptible_timeout(q->sync_sleep, ! q->sync_event_put, HZ);
and this should return zero if (signal_pending(current)) /* interrupted - return 0 to finish sync */ q->sync_event_put = 0; if (! q->sync_event_put || q->sync_time >= time) return 0; return 1;
[<ffffffff852fa353>] snd_seq_oss_drain_write+0x113/0x160
... and this loop should break: while (snd_seq_oss_writeq_sync(dp->writeq)) ;
So, I see no obvious error in the code, so far.
I'm running your test program now with 8 parallel runs, but I couldn't reproduce it. Any other specifics?
Hummm.. for me this process hangs every time, even if I just run it once from console. I've now retested in on clean commit fc77dbd34c5c99bce46d40a2491937c3bcbd10af (without KASAN/KCOV and with release gcc) and also got the same hang. I can only think of a different config. I've attached mine, please try with it.
Are signals delivered if we are already in process of dying? When I kill -9 this process it does not react, so presumably wait is not unblocked...
Good point.
But above all, it doesn't make much sense to loop this sync call. When wait_event*() returns, it should go out. So, the patch like below should be good enough and fix your issue, too.
The patch fixes the hang for me. There is a second delay at exit, but otherwise the process exits fine.
Tested-by: Dmitry Vyukov dvyukov@google.com
Thanks for quick fix!
OK, I got the same result finally on my VM, too. I had to disable INPUT_PCSPKR that conflicts with SND_PCSP.
I reconsidered about this problem again, and concluded that the currently implemented drain behavior is simply superfluous. So, the fix is just to remove all these relevant calls. The patch is attached below. Try this one instead of the previous one.
thanks,
Takashi
-- 8< -- From: Takashi Iwai tiwai@suse.de Subject: [PATCH] ALSA: seq: oss: Don't drain at closing a client
The OSS sequencer client tries to drain the pending events at releasing. Unfortunately, as spotted by syzkaller fuzzer, this may lead to an unkillable process state when the event has been queued at the far future. Since the process being released can't be signaled any longer, it remains and waits for the echo-back event in that far future.
Back to history, the draining feature was implemented at the time we misinterpreted POSIX definition for blocking file operation. Actually, such a behavior is superfluous at release, and we should just release the device as is instead of keeping it up forever.
This patch just removes the draining call that may block the release for too long time unexpectedly.
BugLink: http://lkml.kernel.org/r/CACT4Y+Y4kD-aBGj37rf-xBw9bH3GMU6P+MYg4W1e-s-paVD2pg... Reported-by: Dmitry Vyukov dvyukov@google.com Cc: stable@vger.kernel.org Signed-off-by: Takashi Iwai tiwai@suse.de --- sound/core/seq/oss/seq_oss.c | 2 -- sound/core/seq/oss/seq_oss_device.h | 1 - sound/core/seq/oss/seq_oss_init.c | 16 ---------------- 3 files changed, 19 deletions(-)
diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c index 8db156b207f1..8cdf489df80e 100644 --- a/sound/core/seq/oss/seq_oss.c +++ b/sound/core/seq/oss/seq_oss.c @@ -149,8 +149,6 @@ odev_release(struct inode *inode, struct file *file) if ((dp = file->private_data) == NULL) return 0;
- snd_seq_oss_drain_write(dp); - mutex_lock(®ister_mutex); snd_seq_oss_release(dp); mutex_unlock(®ister_mutex); diff --git a/sound/core/seq/oss/seq_oss_device.h b/sound/core/seq/oss/seq_oss_device.h index b43924325249..d7b4d016b547 100644 --- a/sound/core/seq/oss/seq_oss_device.h +++ b/sound/core/seq/oss/seq_oss_device.h @@ -127,7 +127,6 @@ int snd_seq_oss_write(struct seq_oss_devinfo *dp, const char __user *buf, int co unsigned int snd_seq_oss_poll(struct seq_oss_devinfo *dp, struct file *file, poll_table * wait);
void snd_seq_oss_reset(struct seq_oss_devinfo *dp); -void snd_seq_oss_drain_write(struct seq_oss_devinfo *dp);
/* */ void snd_seq_oss_process_queue(struct seq_oss_devinfo *dp, abstime_t time); diff --git a/sound/core/seq/oss/seq_oss_init.c b/sound/core/seq/oss/seq_oss_init.c index 6779e82b46dd..92c96a95a903 100644 --- a/sound/core/seq/oss/seq_oss_init.c +++ b/sound/core/seq/oss/seq_oss_init.c @@ -436,22 +436,6 @@ snd_seq_oss_release(struct seq_oss_devinfo *dp)
/* - * Wait until the queue is empty (if we don't have nonblock) - */ -void -snd_seq_oss_drain_write(struct seq_oss_devinfo *dp) -{ - if (! dp->timer->running) - return; - if (is_write_mode(dp->file_mode) && !is_nonblock_mode(dp->file_mode) && - dp->writeq) { - while (snd_seq_oss_writeq_sync(dp->writeq)) - ; - } -} - - -/* * reset sequencer devices */ void
On Tue, Mar 1, 2016 at 6:43 PM, Takashi Iwai tiwai@suse.de wrote:
On Tue, 01 Mar 2016 16:45:22 +0100, Dmitry Vyukov wrote:
On Tue, Mar 1, 2016 at 4:31 PM, Takashi Iwai tiwai@suse.de wrote:
On Tue, 01 Mar 2016 16:04:43 +0100, Dmitry Vyukov wrote:
On Tue, Mar 1, 2016 at 4:01 PM, Dmitry Vyukov dvyukov@google.com wrote:
On Tue, Mar 1, 2016 at 3:44 PM, Takashi Iwai tiwai@suse.de wrote:
On Tue, 01 Mar 2016 13:33:27 +0100, Dmitry Vyukov wrote: > > Hello, > > The following program creates an unkillable process: ..... > The hang stack is: > > [<ffffffff85309f77>] snd_seq_oss_writeq_sync+0x327/0x790 > sound/core/seq/oss/seq_oss_writeq.c:121
This is wait_event_interruptible_timeout(q->sync_sleep, ! q->sync_event_put, HZ);
and this should return zero if (signal_pending(current)) /* interrupted - return 0 to finish sync */ q->sync_event_put = 0; if (! q->sync_event_put || q->sync_time >= time) return 0; return 1;
> [<ffffffff852fa353>] snd_seq_oss_drain_write+0x113/0x160
... and this loop should break: while (snd_seq_oss_writeq_sync(dp->writeq)) ;
So, I see no obvious error in the code, so far.
I'm running your test program now with 8 parallel runs, but I couldn't reproduce it. Any other specifics?
Hummm.. for me this process hangs every time, even if I just run it once from console. I've now retested in on clean commit fc77dbd34c5c99bce46d40a2491937c3bcbd10af (without KASAN/KCOV and with release gcc) and also got the same hang. I can only think of a different config. I've attached mine, please try with it.
Are signals delivered if we are already in process of dying? When I kill -9 this process it does not react, so presumably wait is not unblocked...
Good point.
But above all, it doesn't make much sense to loop this sync call. When wait_event*() returns, it should go out. So, the patch like below should be good enough and fix your issue, too.
The patch fixes the hang for me. There is a second delay at exit, but otherwise the process exits fine.
Tested-by: Dmitry Vyukov dvyukov@google.com
Thanks for quick fix!
OK, I got the same result finally on my VM, too. I had to disable INPUT_PCSPKR that conflicts with SND_PCSP.
I reconsidered about this problem again, and concluded that the currently implemented drain behavior is simply superfluous. So, the fix is just to remove all these relevant calls. The patch is attached below. Try this one instead of the previous one.
Replaced the previous fix with this one.
-- 8< -- From: Takashi Iwai tiwai@suse.de Subject: [PATCH] ALSA: seq: oss: Don't drain at closing a client
The OSS sequencer client tries to drain the pending events at releasing. Unfortunately, as spotted by syzkaller fuzzer, this may lead to an unkillable process state when the event has been queued at the far future. Since the process being released can't be signaled any longer, it remains and waits for the echo-back event in that far future.
Back to history, the draining feature was implemented at the time we misinterpreted POSIX definition for blocking file operation. Actually, such a behavior is superfluous at release, and we should just release the device as is instead of keeping it up forever.
This patch just removes the draining call that may block the release for too long time unexpectedly.
BugLink: http://lkml.kernel.org/r/CACT4Y+Y4kD-aBGj37rf-xBw9bH3GMU6P+MYg4W1e-s-paVD2pg... Reported-by: Dmitry Vyukov dvyukov@google.com Cc: stable@vger.kernel.org Signed-off-by: Takashi Iwai tiwai@suse.de
sound/core/seq/oss/seq_oss.c | 2 -- sound/core/seq/oss/seq_oss_device.h | 1 - sound/core/seq/oss/seq_oss_init.c | 16 ---------------- 3 files changed, 19 deletions(-)
diff --git a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c index 8db156b207f1..8cdf489df80e 100644 --- a/sound/core/seq/oss/seq_oss.c +++ b/sound/core/seq/oss/seq_oss.c @@ -149,8 +149,6 @@ odev_release(struct inode *inode, struct file *file) if ((dp = file->private_data) == NULL) return 0;
snd_seq_oss_drain_write(dp);
mutex_lock(®ister_mutex); snd_seq_oss_release(dp); mutex_unlock(®ister_mutex);
diff --git a/sound/core/seq/oss/seq_oss_device.h b/sound/core/seq/oss/seq_oss_device.h index b43924325249..d7b4d016b547 100644 --- a/sound/core/seq/oss/seq_oss_device.h +++ b/sound/core/seq/oss/seq_oss_device.h @@ -127,7 +127,6 @@ int snd_seq_oss_write(struct seq_oss_devinfo *dp, const char __user *buf, int co unsigned int snd_seq_oss_poll(struct seq_oss_devinfo *dp, struct file *file, poll_table * wait);
void snd_seq_oss_reset(struct seq_oss_devinfo *dp); -void snd_seq_oss_drain_write(struct seq_oss_devinfo *dp);
/* */ void snd_seq_oss_process_queue(struct seq_oss_devinfo *dp, abstime_t time); diff --git a/sound/core/seq/oss/seq_oss_init.c b/sound/core/seq/oss/seq_oss_init.c index 6779e82b46dd..92c96a95a903 100644 --- a/sound/core/seq/oss/seq_oss_init.c +++ b/sound/core/seq/oss/seq_oss_init.c @@ -436,22 +436,6 @@ snd_seq_oss_release(struct seq_oss_devinfo *dp)
/*
- Wait until the queue is empty (if we don't have nonblock)
- */
-void -snd_seq_oss_drain_write(struct seq_oss_devinfo *dp) -{
if (! dp->timer->running)
return;
if (is_write_mode(dp->file_mode) && !is_nonblock_mode(dp->file_mode) &&
dp->writeq) {
while (snd_seq_oss_writeq_sync(dp->writeq))
;
}
-}
-/*
- reset sequencer devices
*/ void -- 2.7.2
participants (2)
-
Dmitry Vyukov
-
Takashi Iwai