sound: uninterruptible hang in snd_seq_oss_writeq_sync

88 views
Skip to first unread message

Dmitry Vyukov

unread,
Mar 1, 2016, 7:33:47 AM3/1/16
to Jaroslav Kysela, Takashi Iwai, alsa-...@alsa-project.org, LKML, Alexander Potapenko, Kostya Serebryany, Sasha Levin, syzkaller
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).

Takashi Iwai

unread,
Mar 1, 2016, 9:45:00 AM3/1/16
to Dmitry Vyukov, alsa-...@alsa-project.org, Jaroslav Kysela, LKML, Alexander Potapenko, Kostya Serebryany, syzkaller, Sasha Levin
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

Dmitry Vyukov

unread,
Mar 1, 2016, 10:01:34 AM3/1/16
to Takashi Iwai, alsa-...@alsa-project.org, Jaroslav Kysela, LKML, Alexander Potapenko, Kostya Serebryany, syzkaller, Sasha Levin

Dmitry Vyukov

unread,
Mar 1, 2016, 10:05:04 AM3/1/16
to Takashi Iwai, alsa-...@alsa-project.org, Jaroslav Kysela, LKML, Alexander Potapenko, Kostya Serebryany, syzkaller, Sasha Levin
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...
.config

Takashi Iwai

unread,
Mar 1, 2016, 10:31:11 AM3/1/16
to Dmitry Vyukov, alsa-...@alsa-project.org, Jaroslav Kysela, LKML, Alexander Potapenko, Kostya Serebryany, syzkaller, Sasha Levin
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;
}

/*

Dmitry Vyukov

unread,
Mar 1, 2016, 10:45:42 AM3/1/16
to Takashi Iwai, alsa-...@alsa-project.org, Jaroslav Kysela, LKML, Alexander Potapenko, Kostya Serebryany, syzkaller, Sasha Levin
The patch fixes the hang for me. There is a second delay at exit, but
otherwise the process exits fine.

Tested-by: Dmitry Vyukov <dvy...@google.com>

Thanks for quick fix!

Takashi Iwai

unread,
Mar 1, 2016, 12:43:41 PM3/1/16
to Dmitry Vyukov, alsa-...@alsa-project.org, Jaroslav Kysela, LKML, Alexander Potapenko, Kostya Serebryany, syzkaller, Sasha Levin
On Tue, 01 Mar 2016 16:45:22 +0100,
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 <ti...@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-xBw9...@mail.gmail.com
Reported-by: Dmitry Vyukov <dvy...@google.com>
Cc: <sta...@vger.kernel.org>
Signed-off-by: Takashi Iwai <ti...@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(&register_mutex);
snd_seq_oss_release(dp);
mutex_unlock(&register_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

Dmitry Vyukov

unread,
Mar 2, 2016, 4:26:50 AM3/2/16
to Takashi Iwai, alsa-...@alsa-project.org, Jaroslav Kysela, LKML, Alexander Potapenko, Kostya Serebryany, syzkaller, Sasha Levin
Replaced the previous fix with this one.
Reply all
Reply to author
Forward
0 new messages