[PATCH] sigqueue_free: fix the race with collect_signal()
authorOleg Nesterov <oleg@tv-sign.ru>
Fri, 31 Aug 2007 06:56:35 +0000 (23:56 -0700)
committerWilly Tarreau <w@1wt.eu>
Wed, 17 Oct 2007 19:30:29 +0000 (21:30 +0200)
commit4b6f210cb63eeceb5ea009ecd7a69c88d9e1b7c3
treee00265a67d7067c3f08b77122e03c894b9e9a46b
parent56a35d830d0aa88e8843d567f91374d86108162c
[PATCH] sigqueue_free: fix the race with collect_signal()

commit 60187d2708caa870f0825d753df1612ea688eb9e in mainline.

Spotted by taoyue <yue.tao@windriver.com> and Jeremy Katz <jeremy.katz@windriver.com>.

collect_signal: sigqueue_free:

list_del_init(&first->list);
if (!list_empty(&q->list)) {
// not taken
}
q->flags &= ~SIGQUEUE_PREALLOC;

__sigqueue_free(first); __sigqueue_free(q);

Now, __sigqueue_free() is called twice on the same "struct sigqueue" with the
obviously bad implications.

In particular, this double free breaks the array_cache->avail logic, so the
same sigqueue could be "allocated" twice, and the bug can manifest itself via
the "impossible" BUG_ON(!SIGQUEUE_PREALLOC) in sigqueue_free/send_sigqueue.

Hopefully this can explain these mysterious bug-reports, see

http://marc.info/?t=118766926500003
http://marc.info/?t=118466273000005

Alexey Dobriyan reports this patch makes the difference for the testcase, but
nobody has an access to the application which opened the problems originally.

Also, this patch removes tasklist lock/unlock, ->siglock is enough.

Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
Cc: taoyue <yue.tao@windriver.com>
Cc: Jeremy Katz <jeremy.katz@windriver.com>
Cc: Sukadev Bhattiprolu <sukadev@us.ibm.com>
Cc: Alexey Dobriyan <adobriyan@sw.ru>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Roland McGrath <roland@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
kernel/signal.c