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
