]> err.no Git - linux-2.6/commitdiff
[PATCH] fix de_thread() vs do_coredump() deadlock
authorOleg Nesterov <oleg@tv-sign.ru>
Sun, 30 Oct 2005 23:02:54 +0000 (15:02 -0800)
committerLinus Torvalds <torvalds@g5.osdl.org>
Mon, 31 Oct 2005 01:37:25 +0000 (17:37 -0800)
de_thread() sends SIGKILL to all sub-threads and waits them to die in 'D'
state.  It is possible that one of the threads already dequeued coredump
signal.  When de_thread() unlocks ->sighand->lock that thread can enter
do_coredump()->coredump_wait() and cause a deadlock.

Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
Cc: Roland McGrath <roland@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
fs/exec.c

index 6d9521636aaa22100c436b11cc88edc5984d19d2..10d493fea7ce6a9e4de05ff01facdf162bb9dd8b 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1460,11 +1460,21 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
                current->fsuid = 0;     /* Dump root private */
        }
        mm->dumpable = 0;
-       init_completion(&mm->core_done);
+
+       retval = -EAGAIN;
        spin_lock_irq(&current->sighand->siglock);
-       current->signal->flags = SIGNAL_GROUP_EXIT;
-       current->signal->group_exit_code = exit_code;
+       if (!(current->signal->flags & SIGNAL_GROUP_EXIT)) {
+               current->signal->flags = SIGNAL_GROUP_EXIT;
+               current->signal->group_exit_code = exit_code;
+               retval = 0;
+       }
        spin_unlock_irq(&current->sighand->siglock);
+       if (retval) {
+               up_write(&mm->mmap_sem);
+               goto fail;
+       }
+
+       init_completion(&mm->core_done);
        coredump_wait(mm);
 
        /*