diff options
author | Oleg Nesterov <oleg@redhat.com> | 2011-09-26 19:06:32 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-11-11 09:36:23 -0800 |
commit | 43742b14ffbe87453e96f4411389445fc707df57 (patch) | |
tree | 42e98afb73a408e2cf9b3525648657f8c7612d2c /kernel/signal.c | |
parent | eb4b2df8f20d4479eceeb9bc51695caaa7bcd229 (diff) |
ptrace: don't clear GROUP_STOP_SIGMASK on double-stop
[This does not correspond to any specific patch in the upstream tree as it was
fixed accidentally by rewriting the code in the 3.1 release]
https://bugzilla.redhat.com/show_bug.cgi?id=740121
1. Luke Macken triggered WARN_ON(!(group_stop & GROUP_STOP_SIGMASK))
in do_signal_stop().
This is because do_signal_stop() clears GROUP_STOP_SIGMASK part
unconditionally but doesn't update it if task_is_stopped().
2. Looking at this problem I noticed that WARN_ON_ONCE(!ptrace) is
not right, a stopped-but-resumed tracee can clone the untraced
thread in the SIGNAL_STOP_STOPPED group, the new thread can start
another group-stop.
Remove this warning, we need more fixes to make it true.
Reported-by: Luke Macken <lmacken@redhat.com>
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'kernel/signal.c')
-rw-r--r-- | kernel/signal.c | 4 |
1 files changed, 1 insertions, 3 deletions
diff --git a/kernel/signal.c b/kernel/signal.c index 415d85d6f6c..43fee1cf50d 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -1894,21 +1894,19 @@ static int do_signal_stop(int signr) */ if (!(sig->flags & SIGNAL_STOP_STOPPED)) sig->group_exit_code = signr; - else - WARN_ON_ONCE(!task_ptrace(current)); current->group_stop &= ~GROUP_STOP_SIGMASK; current->group_stop |= signr | gstop; sig->group_stop_count = 1; for (t = next_thread(current); t != current; t = next_thread(t)) { - t->group_stop &= ~GROUP_STOP_SIGMASK; /* * Setting state to TASK_STOPPED for a group * stop is always done with the siglock held, * so this check has no races. */ if (!(t->flags & PF_EXITING) && !task_is_stopped(t)) { + t->group_stop &= ~GROUP_STOP_SIGMASK; t->group_stop |= signr | gstop; sig->group_stop_count++; signal_wake_up(t, 0); |