On 07/21, Roland McGrath wrote:
>
> > For example, utrace_control(UTRACE_STOP)->utrace_do_stop() finds
> > the child inside utrace_report_jctl() path in TASK_STOPPED state,
>
> Where?  utrace_report_jctl is called with the siglock held, and resets
> to TASK_RUNNING before it unlocks.
>
> > sets utrace->stopped and returns true. After that utrace_report_jctl()
> > clears ->stopped and another engine's ->report_jctl does mutex_lock()
> > and sets ->state == TASK_INTERRUPTIBLE.
>
> TASK_STOPPED should never be seen (by someone holding the siglock, like
> utrace_do_stop does) until after all ->report_jctl hooks have finished.

Well yes, this particular scenario is not possible, but...


OK, please forget about this for the moment. Why utrace_report_jctl()
and utrace_get_signal() have to clear ->stopped ? Because unlike
utrace_stop(), do_signal_stop() does not do finish_utrace_stop(). This
means that utrace_report_jctl() and utrace_get_signal() might be called
with ->stopped == true, ->stopped can be set by UTRACE_STOP/UTRACE_DETACH
while we were stopped _before_.

(btw, I think the comment in utrace_report_jctl() above "->stopped = 0"
 is confusing, it looks as if we are trying to prevent the race with
 utrace_do_stop() which was called after the caller sets TASK_STOPPED).


Now return to the problem. It is even simpler (and worse) than I thought.
Let's suppose the tracee is TASK_STOPPED, and the tracer does
ptrace_check_attach(). utrace_control(UTRACE_STOP) sets ->stopped = true.
But, the tracee is still TASK_STOPPED, not TASK_TRACED, SIGCONT can wake
it up ?

This means ptrace_check_attach() can succeed but the tracee can even return
to the user-space after that, no? There is no guarantee utrace_get_signal()
will call finish_resume_report(). For example, if there are no pending
signals, we just clear ->stopped and return after dequeue_signal().


Oh, I hope I missed something.

Oleg.

Reply via email to