start-stop-daemon: use vfork to avoid races
While running `rc-service start docker` on Gentoo, I found that the command does not start the service 90% of the time, with an enigmatic 'service crashed' message. The root cause of this is apparently rc-service spawning a pty, running start-stop-daemon inside that pty, and exitting, before start-stop-daemon child process calls setsid(), which results in the child process being killed with SIGHUP (SI_KERNEL). Theoretically this bug was present ever since the file was created in5af58b4514
("Rewrite the core parts in C. We now provide...") (or even before that), but it should have been only a minor issue before45bd125dcc
("Use a pty for prefixed output instead of pipes for..."). Not sure why nobody has had the issue so far (it has been present for almost 15 years). As here setsid() is the last call before execve(), the most natural locking mechanism is vfork(), as it gives back control to parent process only after execve() or process termination. So this way the bug can be fixed by adding a single letter. :-) Another way to ensure this would be using an O_CLOEXEC file descriptor or some custom lock, which would need to be released not before setsid(). Fixes:5af58b4514
("Rewrite the core parts in C. We now provide...") Fixes #532.
This commit is contained in:
parent
95dc83bfbc
commit
9e5ce59a21
@ -864,8 +864,8 @@ int main(int argc, char **argv)
|
|||||||
if (background)
|
if (background)
|
||||||
signal_setup(SIGCHLD, handle_signal);
|
signal_setup(SIGCHLD, handle_signal);
|
||||||
|
|
||||||
if ((pid = fork()) == -1)
|
if ((pid = vfork()) == -1)
|
||||||
eerrorx("%s: fork: %s", applet, strerror(errno));
|
eerrorx("%s: vfork: %s", applet, strerror(errno));
|
||||||
|
|
||||||
/* Child process - lets go! */
|
/* Child process - lets go! */
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
|
Loading…
Reference in New Issue
Block a user