Edit: waitpid is also similarly broken and unfixable for a lot of the same reasons as signals, pidfds and waitid(P_PIDFD, ...) should be replacing most uses of that as well.
Edit: waitpid is also similarly broken and unfixable for a lot of the same reasons as signals, pidfds and waitid(P_PIDFD, ...) should be replacing most uses of that as well.
Unfortunately, it seems like this idea was rejected during the introduction of pidfd.
Edit: note that pidfds holding same-uid processes have no effect (that process already belongs to your uid), and multiple processes holding a single foreign process only count once (that single foreign process is counted toward your NPROC, since it will stick around for pidfd even if its user kills it).
However if opening a handle based on pid you may want to double-check that the handle matches your expectation before using it, since that would be prone to the same race.
Once the service forks then it becomes a problem. If you use cgroups it can be solved separately with the cgroup freezer, but there are still some open issues with this in systemd: https://github.com/systemd/systemd/issues/13101
https://lwn.net/Articles/773459/
https://lwn.net/Articles/784831/
In essence it's a classic TOCTTOU.
Under normal operation (pid returned from fork, waitpid used in one spot until the child exits, no odd sigchild shenanigans), I don't think waitpid() has any races.
Am I missing anything?
If you need to multiplex a wait for multiple processes, it's safer to use epoll with several pidfds. But you still eventually may need to call waitid(-1, ...) to reap any forked processes, and there really is no good way around that.