Forgot to mention...

I didn't test this patch and it is in fact buggy, we should
set sig = context->siginfo->si_signo when !valid_signal(sig).

This is just RFC to know what do you think.

On 10/06, Oleg Nesterov wrote:
>
> 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))

Reply via email to