On 10/07, Roland McGrath wrote:
>
> > +static int ptrace_rw_siginfo(struct task_struct *tracee,
> > +                           struct ptrace_context *context,
> > +                           siginfo_t *info, bool write)
> > +{
> > +   unsigned long flags;
> > +   siginfo_t *context_info;
> > +   int err = -ESRCH;
> > +
> > +   if (!lock_task_sighand(tracee, &flags))
> > +           return err;
> > +   /*
> > +    * Make sure the compiler reads ->siginfo only once, if we race
> > +    * with SIGKILL ->siginfo can be cleared under us. But the memory
> > +    * it points to can't go away, and since we hold ->siglock we can't
> > +    * race with get_signal_to_deliver() pathes clobber this memory.
>
> s/pathes clobber/paths that clobber/

Thanks,

> > +    * See also the comment in ptrace_report_signal().
> > +    */
> > +   context_info = ACCESS_ONCE(context->siginfo);
> > +   if (context_info) {
> > +           if (write)
> > +                   *context_info = *info;
> > +           else
> > +                   *info = *context_info;
> > +           err = 0;
> > +   }
> > +   unlock_task_sighand(tracee, &flags);
>
> Couldn't we instead do:
>
>       context_info = ACCESS_ONCE(context->siginfo);
>       if (context_info) {
>               *info = *context_info;
>               smp_rmb();
>               if (ACCESS_ONCE(context->siginfo))
>                       err = 0;

I don't think this can work. context->siginfo can be cleared and then
set again in between. If we race with SIGKILL, utrace_get_signal()
can dequeue another signal != SIGKILL and start the reporting loop.

I thought about

        *info = *context_info;
        rmb();
        if (fatal_ignal_pending(tracee))
                return -ERR;

But I think it is better to do theses cleanups after V1. See also
my reply to next reviews.

Oleg.

Reply via email to