History

ptrace: ensure JOBCTL_STOP_SIGMASK is not zero after detach

This is the temporary simple fix for 3.2, we need more changes in this area. 1. do_signal_stop() assumes that the running untraced thread in the stopped thread group is not possible. This was our goal but it is not yet achieved: a stopped-but-resumed tracee can clone the running thread which can initiate another group-stop. Remove WARN_ON_ONCE(!current->ptrace). 2. A new thread always starts with ->jobctl = 0. If it is auto-attached and this group is stopped, __ptrace_unlink() sets JOBCTL_STOP_PENDING but JOBCTL_STOP_SIGMASK part is zero, this triggers WANR_ON(!signr) in do_jobctl_trap() if another debugger attaches. Change __ptrace_unlink() to set the artificial SIGSTOP for report. Alternatively we could change ptrace_init_task() to copy signr from current, but this means we can copy it for no reason and hide the possible similar problems.

Oleg Nesterov committed 14 years ago

Commit 8a889511 parent 50b8d252 files · +12 −3Browse files

Unified · Split

2 files
  1. kernel/ptrace.c +12 −1
  2. kernel/signal.c +0 −2
kernel/ptrace.c+12−1
@@ -96,9 +96,20 @@ void __ptrace_unlink(struct task_struct *child) · 95 unmodified lines
9696 */
9797 if (!(child->flags & PF_EXITING) &&
9898 (child->signal->flags & SIGNAL_STOP_STOPPED ||
99− child->signal->group_stop_count))
99+ child->signal->group_stop_count)) {
100100 child->jobctl |= JOBCTL_STOP_PENDING;
101101
102+ /*
103+ * This is only possible if this thread was cloned by the
104+ * traced task running in the stopped group, set the signal
105+ * for the future reports.
106+ * FIXME: we should change ptrace_init_task() to handle this
107+ * case.
108+ */
109+ if (!(child->jobctl & JOBCTL_STOP_SIGMASK))
110+ child->jobctl |= SIGSTOP;
111+ }
112+
102113 /*
103114 * If transition to TASK_STOPPED is pending or in TASK_TRACED, kick
104115 * @child in the butt. Note that @resume should be used iff @child
kernel/signal.c+0−2
@@ -1994,8 +1994,6 @@ static bool do_signal_stop(int signr) · 1993 unmodified lines
19941994 */
19951995 if (!(sig->flags & SIGNAL_STOP_STOPPED))
19961996 sig->group_exit_code = signr;
1997− else
1998− WARN_ON_ONCE(!current->ptrace);
19991997
20001998 sig->group_stop_count = 0;
20011999