diff options
author | Oleg Nesterov <oleg@tv-sign.ru> | 2008-02-05 01:27:23 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2008-02-05 12:44:07 -0500 |
commit | 198466b41d11dd062fb26ee0376080458d7bfcaf (patch) | |
tree | ccf725c9a05e13b983e4480fd218280d5e58b47e /kernel/signal.c | |
parent | bdff746a3915f109bd13730b6847e33e17e91ed3 (diff) |
__group_complete_signal(): fix coredump with group stop race
When __group_complete_signal() sees sig_kernel_coredump() signal, it starts
the group stop, but sets ->group_exit_task = t in a hope that "t" will
actually dequeue this signal and invoke do_coredump(). However, by the
time "t" enters get_signal_to_deliver() it is possible that the signal was
blocked/ignored or we have another pending !SIG_KERNEL_COREDUMP_MASK signal
which will be dequeued first. This means the task could be stopped but not
killed.
Remove this code from __group_complete_signal(). Note also this patch
removes the bogus signal_wake_up(t, 1). This thread can't be
STOPPED/TRACED, note the corresponding check in wants_signal().
Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
Cc: Davide Libenzi <davidel@xmailserver.org>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Robin Holt <holt@sgi.com>
Cc: Roland McGrath <roland@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/signal.c')
-rw-r--r-- | kernel/signal.c | 30 |
1 files changed, 0 insertions, 30 deletions
diff --git a/kernel/signal.c b/kernel/signal.c index 4333b6dbb424..ea90c34e9348 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
@@ -911,27 +911,6 @@ __group_complete_signal(int sig, struct task_struct *p) | |||
911 | } while_each_thread(p, t); | 911 | } while_each_thread(p, t); |
912 | return; | 912 | return; |
913 | } | 913 | } |
914 | |||
915 | /* | ||
916 | * There will be a core dump. We make all threads other | ||
917 | * than the chosen one go into a group stop so that nothing | ||
918 | * happens until it gets scheduled, takes the signal off | ||
919 | * the shared queue, and does the core dump. This is a | ||
920 | * little more complicated than strictly necessary, but it | ||
921 | * keeps the signal state that winds up in the core dump | ||
922 | * unchanged from the death state, e.g. which thread had | ||
923 | * the core-dump signal unblocked. | ||
924 | */ | ||
925 | rm_from_queue(SIG_KERNEL_STOP_MASK, &t->pending); | ||
926 | rm_from_queue(SIG_KERNEL_STOP_MASK, &p->signal->shared_pending); | ||
927 | p->signal->group_stop_count = 0; | ||
928 | p->signal->group_exit_task = t; | ||
929 | p = t; | ||
930 | do { | ||
931 | p->signal->group_stop_count++; | ||
932 | signal_wake_up(t, t == p); | ||
933 | } while_each_thread(p, t); | ||
934 | return; | ||
935 | } | 914 | } |
936 | 915 | ||
937 | /* | 916 | /* |
@@ -1762,15 +1741,6 @@ static int handle_group_stop(void) | |||
1762 | { | 1741 | { |
1763 | int stop_count; | 1742 | int stop_count; |
1764 | 1743 | ||
1765 | if (current->signal->group_exit_task == current) { | ||
1766 | /* | ||
1767 | * Group stop is so we can do a core dump, | ||
1768 | * We are the initiating thread, so get on with it. | ||
1769 | */ | ||
1770 | current->signal->group_exit_task = NULL; | ||
1771 | return 0; | ||
1772 | } | ||
1773 | |||
1774 | if (current->signal->flags & SIGNAL_GROUP_EXIT) | 1744 | if (current->signal->flags & SIGNAL_GROUP_EXIT) |
1775 | /* | 1745 | /* |
1776 | * Group stop is so another thread can do a core dump, | 1746 | * Group stop is so another thread can do a core dump, |