On Thu, 30 Jan 2020, Marc Espie wrote:
> So, basically, if we start arbitrary commands, then
> the classic loop 
>     /* Wait for the child to exit.  */
>     while (waitpid(cpid, &status, 0) == -1 && errno == EINTR)
>           continue;
> 
> is not quite enough.
> 
> See the small note in manpages (not only us, but everyone):
>      WIFSTOPPED(status)
>              True if the process has not terminated, but has stopped and can
>              be restarted.  This macro can be true only if the wait call
>              specified the WUNTRACED option or if the child process is being
>              traced (see ptrace(2)).
> 
> this means that somebody could run a command that forks, and then its child
> (our grand-child) could use ptrace on its parent, and then we would get
> a notification with WIFSTOPPED (assuming the current kernel bug is fixed).

No, what you describe would not cause waitpid(2) to return in the 'make' 
process: when ptrace(PT_ATTACH) is used, then target is effectively 
reparented to the tracing process such that the tracing process is the one 
which sees the wait() status changes, including the "stopped for tracing" 
state.  Only when it is detached (and thus either continued or killed!) 
will the make process see any wait statuses; at that point they will be 
normal wait statuses.


The case you describe _can_ happen if make's direct child simply calls 
ptrace(PT_TRACE_ME) and then takes a signal or execs, but a process doing 
that without providing a tracer process as well is simply buggy and 
misdesigned.


(The kernel bug is that wait calls in the "original but not currently the 
parent" process do not act like the traced process is still there and 
running: the fact that the child has been attached to and is being stopped 
and started by its tracer should be completely invisible to the original 
parent.)


Philip Guenther

Reply via email to