On 10/06, Jan Kratochvil wrote: > > On Tue, 06 Oct 2009 15:10:10 +0200, Oleg Nesterov wrote: > > Once again. Suppose that the tracer does ptrace(PTRACE_DETACH, SIGXXX). > > Currently, if the next thacer attaches right after this detach it has no > > way to intercept SIGXXX, it will be never reported via ptrace_signal(). >^ > No matter if it gets reported to the new tracer still SIGXXX should never get > lost.
OK, great. Roland, do you agree? If yes, perhaps we can avoid ptrace_utrace_detached_ops logic? At least for the first version which can be sent to lkml. If the tracer does ptrace(DETACH, SIGNR) - just send this signal, that is all. If the tracer exits (valid_signal() == F), send the already reported signal. Otherwise, if the tracee didn't report a signal - do nothing. What do you think? --- kernel/ptrace.c | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) --- PU/kernel/ptrace.c~71_PARTLY_FIX_DETACH 2009-10-06 02:25:02.000000000 +0200 +++ PU/kernel/ptrace.c 2009-10-06 18:12:12.000000000 +0200 @@ -82,6 +82,33 @@ static struct utrace_engine *ptrace_look &ptrace_utrace_ops, NULL); } +static void detach_signal(struct task_struct *tracee, + struct ptrace_context *context, int sig) +{ + siginfo_t *info = NULL; + + switch (get_stop_code(context)) { + case PTRACE_EVENT_SYSCALL_ENTRY: + case PTRACE_EVENT_SYSCALL_EXIT: + if (valid_signal(sig)) + info = SEND_SIG_PRIV; + break; + + case PTRACE_EVENT_SIGNAL: + if (valid_signal(sig) && sig != context->signr) + info = SEND_SIG_NOINFO; + else + info = context->siginfo; + break; + } + + // XXX: if info == context->siginfo we can race with SIGKILL, + // but afaics this is harmless ? send_sig_info() uses *info + // under ->siglock, the worst case SIGKILL will be sent twice. + if (info) + send_sig_info(sig, info, tracee); +} + static void ptrace_detach_task(struct task_struct *child, int sig) { struct utrace_engine *engine = ptrace_lookup_engine(child); @@ -90,6 +117,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); @@ -668,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))