sigqueue_free: fix the race with collect_signal()

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>
Cc: <stable@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by Oleg Nesterov and committed by Linus Torvalds 60187d27 99db67bc

+9 -10
+9 -10
kernel/signal.c
··· 1300 1300 void sigqueue_free(struct sigqueue *q) 1301 1301 { 1302 1302 unsigned long flags; 1303 + spinlock_t *lock = &current->sighand->siglock; 1304 + 1303 1305 BUG_ON(!(q->flags & SIGQUEUE_PREALLOC)); 1304 1306 /* 1305 1307 * If the signal is still pending remove it from the 1306 - * pending queue. 1308 + * pending queue. We must hold ->siglock while testing 1309 + * q->list to serialize with collect_signal(). 1307 1310 */ 1308 - if (unlikely(!list_empty(&q->list))) { 1309 - spinlock_t *lock = &current->sighand->siglock; 1310 - read_lock(&tasklist_lock); 1311 - spin_lock_irqsave(lock, flags); 1312 - if (!list_empty(&q->list)) 1313 - list_del_init(&q->list); 1314 - spin_unlock_irqrestore(lock, flags); 1315 - read_unlock(&tasklist_lock); 1316 - } 1311 + spin_lock_irqsave(lock, flags); 1312 + if (!list_empty(&q->list)) 1313 + list_del_init(&q->list); 1314 + spin_unlock_irqrestore(lock, flags); 1315 + 1317 1316 q->flags &= ~SIGQUEUE_PREALLOC; 1318 1317 __sigqueue_free(q); 1319 1318 }