libbb: use _exit, not exit, in bb_daemonize_or_rexec()
authorDenys Vlasenko <vda.linux@googlemail.com>
Fri, 4 Aug 2017 21:04:17 +0000 (23:04 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Fri, 4 Aug 2017 21:04:17 +0000 (23:04 +0200)
By the time we reach exit in parent, child already exited or execed.
We should not re-run libc cleanup code.

While at it, introduce bb_daemon_helper() and add a few comments.

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
console-tools/openvt.c
debianutils/start_stop_daemon.c
include/libbb.h
libbb/vfork_daemon_rexec.c
loginutils/login.c
printutils/lpd.c

index f3db283675b18c977cc5b4711292a256fc8f2b1e..423122fe9e1ecf152122f551b839f82efa8e004f 100644 (file)
@@ -99,7 +99,7 @@ static int find_free_vtno(void)
        /*xfunc_error_retval = 3; - do we need compat? */
        if (ioctl(fd, VT_OPENQRY, &vtno) != 0 || vtno <= 0)
                bb_perror_msg_and_die("can't find open VT");
-// Not really needed, grep for DAEMON_ONLY_SANITIZE
+// Not really needed, grep for DAEMON_CLOSE_EXTRA_FDS
 //     if (fd > 2)
 //             close(fd);
        return vtno;
@@ -155,7 +155,7 @@ int openvt_main(int argc UNUSED_PARAM, char **argv)
        /* Grab new VT */
        sprintf(vtname, VC_FORMAT, vtno);
        /* (Try to) clean up stray open fds above fd 2 */
-       bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS | DAEMON_ONLY_SANITIZE, NULL);
+       bb_daemon_helper(DAEMON_CLOSE_EXTRA_FDS);
        close(STDIN_FILENO);
        /*setsid(); - BAD IDEA: after we exit, child is SIGHUPed... */
        xopen(vtname, O_RDWR);
index 9d60b2c7f18f5edaf055ab45c43aa3c86a42c75b..07c104baad230e41b3fba7b67285d65887baa20f 100644 (file)
@@ -516,6 +516,11 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv)
                /* DAEMON_DEVNULL_STDIO is superfluous -
                 * it's always done by bb_daemonize() */
 #else
+               /* Daemons usually call bb_daemonize_or_rexec(), but SSD can do
+                * without: SSD is not itself a daemon, it _execs_ a daemon.
+                * The usual NOMMU problem of "child can't run indefinitely,
+                * it must exec" does not bite us: we exec anyway.
+                */
                pid_t pid = xvfork();
                if (pid != 0) {
                        /* parent */
@@ -525,12 +530,8 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv)
                }
                /* Child */
                setsid(); /* detach from controlling tty */
-               /* Redirect stdio to /dev/null, close extra FDs.
-                * We do not actually daemonize because of DAEMON_ONLY_SANITIZE */
-               bb_daemonize_or_rexec(DAEMON_DEVNULL_STDIO
-                       + DAEMON_CLOSE_EXTRA_FDS
-                       + DAEMON_ONLY_SANITIZE,
-                       NULL /* argv, unused */ );
+               /* Redirect stdio to /dev/null, close extra FDs */
+               bb_daemon_helper(DAEMON_DEVNULL_STDIO + DAEMON_CLOSE_EXTRA_FDS);
 #endif
        }
        if (opt & OPT_MAKEPID) {
index bb27c59a15f84a2426a8afa8c06a582a27d3c22b..6a2a2d640f8e8ec8f292a135824d61dc4f848891 100644 (file)
@@ -1169,6 +1169,7 @@ enum {
 #endif
 void bb_daemonize_or_rexec(int flags, char **argv) FAST_FUNC;
 void bb_sanitize_stdio(void) FAST_FUNC;
+#define bb_daemon_helper(arg) bb_daemonize_or_rexec((arg) | DAEMON_ONLY_SANITIZE, NULL)
 /* Clear dangerous stuff, set PATH. Return 1 if was run by different user. */
 int sanitize_env_if_suid(void) FAST_FUNC;
 
index 98512bb000480727e7c2cfd7c1fd61a82a521ad3..f84e678b5fd5e4e9bb46eddc56aa4bcfb8e7c01b 100644 (file)
@@ -209,6 +209,9 @@ pid_t FAST_FUNC fork_or_rexec(char **argv)
        /* Maybe we are already re-execed and come here again? */
        if (re_execed)
                return 0;
+
+       /* fflush_all(); ? - so far all callers had no buffered output to flush */
+
        pid = xvfork();
        if (pid) /* parent */
                return pid;
@@ -245,8 +248,11 @@ void FAST_FUNC bb_daemonize_or_rexec(int flags, char **argv)
                fd = dup(fd); /* have 0,1,2 open at least to /dev/null */
 
        if (!(flags & DAEMON_ONLY_SANITIZE)) {
+
+               /* fflush_all(); - add it in fork_or_rexec() if necessary */
+
                if (fork_or_rexec(argv))
-                       exit(EXIT_SUCCESS); /* parent */
+                       _exit(EXIT_SUCCESS); /* parent */
                /* if daemonizing, detach from stdio & ctty */
                setsid();
                dup2(fd, 0);
@@ -258,7 +264,7 @@ void FAST_FUNC bb_daemonize_or_rexec(int flags, char **argv)
                         * Prevent this: stop being a session leader.
                         */
                        if (fork_or_rexec(argv))
-                               exit(EXIT_SUCCESS); /* parent */
+                               _exit(EXIT_SUCCESS); /* parent */
                }
        }
        while (fd > 2) {
index 381468d8115c30b07f155de915e8cd8ad5907651..fcdb9592c13f1a16f602e6ab177b582aeba67684 100644 (file)
@@ -350,8 +350,8 @@ int login_main(int argc UNUSED_PARAM, char **argv)
        /* Mandatory paranoia for suid applet:
         * ensure that fd# 0,1,2 are opened (at least to /dev/null)
         * and any extra open fd's are closed.
-        * (The name of the function is misleading. Not daemonizing here.) */
-       bb_daemonize_or_rexec(DAEMON_ONLY_SANITIZE | DAEMON_CLOSE_EXTRA_FDS, NULL);
+        */
+       bb_daemon_helper(DAEMON_CLOSE_EXTRA_FDS);
 
        username[0] = '\0';
        opt = getopt32(argv, "f:h:p", &opt_user, &opt_host);
index 3fdba5d2bb923d0d82b022abbf71fd006ba04544..662d3a22467b3e0c470baad9592fdf64a999147f 100644 (file)
@@ -198,9 +198,8 @@ int lpd_main(int argc UNUSED_PARAM, char *argv[])
                                q = p; // next line
                        }
                        // helper should not talk over network.
-                       // this call reopens stdio fds to "/dev/null"
-                       // (no daemonization is done)
-                       bb_daemonize_or_rexec(DAEMON_DEVNULL_STDIO | DAEMON_ONLY_SANITIZE, NULL);
+                       // this call reopens stdio fds to "/dev/null".
+                       bb_daemon_helper(DAEMON_DEVNULL_STDIO);
                        BB_EXECVP_or_die(argv);
                }