Introduce detach_signal(sig) helper. It is called by ptrace_detach_task() instead of removed ptrace_do_detach()->send_sig().
!valid_signal(sig) means that the tracer exits and detaches implicitly. If sig == 0 - nothing to do, just detach and return. If the tracee reported the signal, it will be cancelled. If sig != 0, the tracee should process the reported signal. Currently we call send_sig_info(). Also, handle PTRACE_EVENT_SYSCALL_XXX case. --- kernel/ptrace.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) --- PU/kernel/ptrace.c~74_DETACH_SIGNAL 2009-10-09 16:48:40.000000000 +0200 +++ PU/kernel/ptrace.c 2009-10-09 16:49:32.000000000 +0200 @@ -87,6 +87,25 @@ static struct utrace_engine *ptrace_look &ptrace_utrace_ops, NULL); } +static void detach_signal(struct task_struct *tracee, + struct ptrace_context *context, int sig) +{ + switch (get_stop_event(context)) { + case PTRACE_EVENT_SYSCALL_ENTRY: + case PTRACE_EVENT_SYSCALL_EXIT: + if (valid_signal(sig)) + send_sig_info(sig, SEND_SIG_PRIV, tracee); + break; + + case PTRACE_EVENT_SIGNAL: + if (!valid_signal(sig)) + sig = context->signr; + if (sig) + send_sig_info(sig, SEND_SIG_PRIV, tracee); + break; + } +} + static void ptrace_detach_task(struct task_struct *child, int sig) { struct utrace_engine *engine = ptrace_lookup_engine(child); @@ -95,6 +114,9 @@ static void ptrace_detach_task(struct ta if (unlikely(IS_ERR(engine))) return; + if (sig) + detach_signal(child, ptrace_context(engine), sig); + ret = utrace_control(child, engine, UTRACE_DETACH); WARN_ON(ret && ret != -EINPROGRESS && ret != -ESRCH && ret != -EALREADY); @@ -676,12 +698,8 @@ static void ptrace_do_detach(struct task */ detach = tracee->ptrace != 0; release = false; - if (likely(detach)) { - // XXX: temporary hack - if (data && valid_signal(data)) - send_sig(data, tracee, 1); + if (likely(detach)) release = __ptrace_detach(current, tracee); - } write_unlock_irq(&tasklist_lock); if (unlikely(release))