tree-wide: introduce new safe_fork() helper and port everything over
authorLennart Poettering <lennart@poettering.net>
Fri, 22 Dec 2017 12:08:14 +0000 (13:08 +0100)
committerLennart Poettering <lennart@poettering.net>
Mon, 25 Dec 2017 10:48:21 +0000 (11:48 +0100)
This adds a new safe_fork() wrapper around fork() and makes use of it
everywhere. The new wrapper does a couple of things we previously did
manually and separately in a safer, more correct and automatic way:

1. Optionally resets signal handlers/mask in the child

2. Sets a name on all processes we fork off right after forking off (and
   the patch assigns useful names for all processes we fork off now,
   following a systematic naming scheme: always enclosed in () – in order
   to indicate that these are not proper, exec()ed processes, but only
   forked off children, and if the process is long-running with only our
   own code, without execve()'ing something else, it gets am "sd-" prefix.)

3. Optionally closes all file descriptors in the child

4. Optionally sets a PR_SET_DEATHSIG to SIGTERM in the child, in a safe
   way so that the parent dying before this happens being handled
   safely.

5. Optionally reopens the logs

6. Optionally connects stdin/stdout/stderr to /dev/null

7. Debug logs about the forked off processes.

42 files changed:
src/activate/activate.c
src/basic/async.c
src/basic/calendarspec.c
src/basic/exec-util.c
src/basic/process-util.c
src/basic/process-util.h
src/basic/terminal-util.c
src/basic/time-util.c
src/basic/util.c
src/core/execute.c
src/core/shutdown.c
src/core/socket.c
src/core/umount.c
src/core/unit.c
src/core/unit.h
src/coredump/coredumpctl.c
src/delta/delta.c
src/fsck/fsck.c
src/import/import-common.c
src/import/importd.c
src/import/pull-common.c
src/journal-remote/journal-remote.c
src/libsystemd/sd-bus/bus-container.c
src/libsystemd/sd-bus/bus-socket.c
src/login/inhibit.c
src/machine/image-dbus.c
src/machine/machine-dbus.c
src/machine/machined-dbus.c
src/nspawn/nspawn-setuid.c
src/nspawn/nspawn-stub-pid1.c
src/partition/makefs.c
src/quotacheck/quotacheck.c
src/remount-fs/remount-fs.c
src/shared/logs-show.c
src/shared/machine-pool.c
src/shared/pager.c
src/sulogin-shell/sulogin-shell.c
src/systemctl/systemctl.c
src/test/test-process-util.c
src/tty-ask-password-agent/tty-ask-password-agent.c
src/udev/udev-event.c
src/vconsole/vconsole-setup.c

index 83807ef..67067a8 100644 (file)
@@ -267,38 +267,23 @@ static int exec_process(const char* name, char **argv, char **env, int start_fd,
 
 static int fork_and_exec_process(const char* child, char** argv, char **env, int fd) {
         _cleanup_free_ char *joined = NULL;
-        pid_t parent_pid, child_pid;
+        pid_t child_pid;
+        int r;
 
         joined = strv_join(argv, " ");
         if (!joined)
                 return log_oom();
 
-        parent_pid = getpid_cached();
-
-        child_pid = fork();
-        if (child_pid < 0)
-                return log_error_errno(errno, "Failed to fork: %m");
-
-        /* In the child */
-        if (child_pid == 0) {
-
-                (void) reset_all_signal_handlers();
-                (void) reset_signal_mask();
-
-                /* Make sure the child goes away when the parent dies */
-                if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
-                        _exit(EXIT_FAILURE);
-
-                /* Check whether our parent died before we were able
-                 * to set the death signal */
-                if (getppid() != parent_pid)
-                        _exit(EXIT_SUCCESS);
-
+        r = safe_fork("(activate)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child_pid);
+        if (r < 0)
+                return log_error_errno(r, "Failed to fork: %m");
+        if (r == 0) {
+                /* In the child */
                 exec_process(child, argv, env, fd, 1);
                 _exit(EXIT_FAILURE);
         }
 
-        log_info("Spawned %s (%s) as PID %d", child, joined, child_pid);
+        log_info("Spawned %s (%s) as PID " PID_FMT ".", child, joined, child_pid);
         return 0;
 }
 
index c510cbd..21e05d9 100644 (file)
@@ -61,29 +61,18 @@ finish:
 }
 
 int asynchronous_sync(void) {
-        pid_t pid;
+        int r;
 
         /* This forks off an invocation of fork() as a child process, in order to initiate synchronization to
          * disk. Note that we implement this as helper process rather than thread as we don't want the sync() to hang our
          * original process ever, and a thread would do that as the process can't exit with threads hanging in blocking
          * syscalls. */
 
-        log_debug("Spawning new process for sync");
-
-        pid = fork();
-        if (pid < 0)
-                return -errno;
-
-        if (pid == 0) {
+        r = safe_fork("(sd-sync)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS, NULL);
+        if (r < 0)
+                return r;
+        if (r == 0) {
                 /* Child process */
-
-                (void) rename_process("(sd-sync)");
-
-                (void) reset_all_signal_handlers();
-                (void) reset_signal_mask();
-
-                (void) close_all_fds(NULL, 0);
-
                 (void) sync();
                 _exit(EXIT_SUCCESS);
         }
index e6add0c..dbd7fb1 100644 (file)
@@ -1348,9 +1348,8 @@ typedef struct SpecNextResult {
 } SpecNextResult;
 
 int calendar_spec_next_usec(const CalendarSpec *spec, usec_t usec, usec_t *next) {
+        SpecNextResult *shared, tmp;
         pid_t pid;
-        SpecNextResult *shared;
-        SpecNextResult tmp;
         int r;
 
         if (isempty(spec->timezone))
@@ -1360,15 +1359,12 @@ int calendar_spec_next_usec(const CalendarSpec *spec, usec_t usec, usec_t *next)
         if (shared == MAP_FAILED)
                 return negative_errno();
 
-        pid = fork();
-
-        if (pid == -1) {
-                int fork_errno = errno;
+        r = safe_fork("(sd-calendar)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG, &pid);
+        if (r < 0) {
                 (void) munmap(shared, sizeof *shared);
-                return -fork_errno;
+                return r;
         }
-
-        if (pid == 0) {
+        if (r == 0) {
                 if (setenv("TZ", spec->timezone, 1) != 0) {
                         shared->return_value = negative_errno();
                         _exit(EXIT_FAILURE);
index 82ccbdf..afad636 100644 (file)
@@ -48,20 +48,19 @@ assert_cc(EAGAIN == EWOULDBLOCK);
 static int do_spawn(const char *path, char *argv[], int stdout_fd, pid_t *pid) {
 
         pid_t _pid;
+        int r;
 
         if (null_or_empty_path(path)) {
                 log_debug("%s is empty (a mask).", path);
                 return 0;
         }
 
-        _pid = fork();
-        if (_pid < 0)
-                return log_error_errno(errno, "Failed to fork: %m");
-        if (_pid == 0) {
+        r = safe_fork("(direxec)", FORK_DEATHSIG, &_pid);
+        if (r < 0)
+                return log_error_errno(r, "Failed to fork: %m");
+        if (r == 0) {
                 char *_argv[2];
 
-                assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
-
                 if (stdout_fd >= 0) {
                         /* If the fd happens to be in the right place, go along with that */
                         if (stdout_fd != STDOUT_FILENO &&
@@ -107,11 +106,6 @@ static int do_execute(
          * If callbacks is nonnull, execution is serial. Otherwise, we default to parallel.
          */
 
-        (void) reset_all_signal_handlers();
-        (void) reset_signal_mask();
-
-        assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
-
         r = conf_files_list_strv(&paths, NULL, NULL, CONF_FILES_EXECUTABLE, (const char* const*) directories);
         if (r < 0)
                 return r;
@@ -222,11 +216,10 @@ int execute_directories(
          * them to finish. Optionally a timeout is applied. If a file with the same name
          * exists in more than one directory, the earliest one wins. */
 
-        executor_pid = fork();
-        if (executor_pid < 0)
-                return log_error_errno(errno, "Failed to fork: %m");
-
-        if (executor_pid == 0) {
+        r = safe_fork("(sd-executor)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &executor_pid);
+        if (r < 0)
+                return log_error_errno(r, "Failed to fork: %m");
+        if (r == 0) {
                 r = do_execute(dirs, timeout, callbacks, callback_args, fd, argv);
                 _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
         }
index 17c94f4..01c73cf 100644 (file)
@@ -56,6 +56,7 @@
 #include "stat-util.h"
 #include "string-table.h"
 #include "string-util.h"
+#include "terminal-util.h"
 #include "user-util.h"
 #include "util.h"
 
@@ -1134,6 +1135,142 @@ int must_be_root(void) {
         return -EPERM;
 }
 
+int safe_fork_full(
+                const char *name,
+                const int except_fds[],
+                size_t n_except_fds,
+                ForkFlags flags,
+                pid_t *ret_pid) {
+
+        pid_t original_pid, pid;
+        sigset_t saved_ss;
+        bool block_signals;
+        int r;
+
+        /* A wrapper around fork(), that does a couple of important initializations in addition to mere forking. Always
+         * returns the child's PID in *ret_pid. Returns == 0 in the child, and > 0 in the parent. */
+
+        original_pid = getpid_cached();
+
+        block_signals = flags & (FORK_RESET_SIGNALS|FORK_DEATHSIG);
+
+        if (block_signals) {
+                sigset_t ss;
+
+                /* We temporarily block all signals, so that the new child has them blocked initially. This way, we can be sure
+                 * that SIGTERMs are not lost we might send to the child. */
+                if (sigfillset(&ss) < 0)
+                        return log_debug_errno(errno, "Failed to reset signal set: %m");
+
+                if (sigprocmask(SIG_SETMASK, &ss, &saved_ss) < 0)
+                        return log_debug_errno(errno, "Failed to reset signal mask: %m");
+        }
+
+        pid = fork();
+        if (pid < 0) {
+                r = -errno;
+
+                if (block_signals) /* undo what we did above */
+                        (void) sigprocmask(SIG_SETMASK, &saved_ss, NULL);
+
+                return log_debug_errno(r, "Failed to fork: %m");
+        }
+        if (pid > 0) {
+                /* We are in the parent process */
+
+                if (block_signals) /* undo what we did above */
+                        (void) sigprocmask(SIG_SETMASK, &saved_ss, NULL);
+
+                log_debug("Sucessfully forked off '%s' as PID " PID_FMT ".", strna(name), pid);
+
+                if (ret_pid)
+                        *ret_pid = pid;
+
+                return 1;
+        }
+
+        /* We are in the child process */
+
+        if (flags & FORK_REOPEN_LOG) {
+                /* Close the logs if requested, before we log anything. And make sure we reopen it if needed. */
+                log_close();
+                log_set_open_when_needed(true);
+        }
+
+        if (name) {
+                r = rename_process(name);
+                if (r < 0)
+                        log_debug_errno(r, "Failed to rename process, ignoring: %m");
+        }
+
+        if (flags & FORK_DEATHSIG)
+                if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0) {
+                        log_debug_errno(errno, "Failed to set death signal: %m");
+                        _exit(EXIT_FAILURE);
+                }
+
+        if (flags & FORK_RESET_SIGNALS) {
+                r = reset_all_signal_handlers();
+                if (r < 0) {
+                        log_debug_errno(r, "Failed to reset signal handlers: %m");
+                        _exit(EXIT_FAILURE);
+                }
+
+                /* This implicitly undoes the signal mask stuff we did before the fork()ing above */
+                r = reset_signal_mask();
+                if (r < 0) {
+                        log_debug_errno(r, "Failed to reset signal mask: %m");
+                        _exit(EXIT_FAILURE);
+                }
+        } else if (block_signals) { /* undo what we did above */
+                if (sigprocmask(SIG_SETMASK, &saved_ss, NULL) < 0) {
+                        log_debug_errno(errno, "Failed to restore signal mask: %m");
+                        _exit(EXIT_FAILURE);
+                }
+        }
+
+        if (flags & FORK_DEATHSIG) {
+                /* Let's see if the parent PID is still the one we started from? If not, then the parent
+                 * already died by the time we set PR_SET_PDEATHSIG, hence let's emulate the effect */
+
+                if (getppid() != original_pid) {
+                        log_debug("Parent died early, raising SIGTERM.");
+                        (void) raise(SIGTERM);
+                        _exit(EXIT_FAILURE);
+                }
+        }
+
+        if (flags & FORK_CLOSE_ALL_FDS) {
+                /* Close the logs here in case it got reopened above, as close_all_fds() would close them for us */
+                log_close();
+
+                r = close_all_fds(except_fds, n_except_fds);
+                if (r < 0) {
+                        log_debug_errno(r, "Failed to close all file descriptors: %m");
+                        _exit(EXIT_FAILURE);
+                }
+        }
+
+        /* When we were asked to reopen the logs, do so again now */
+        if (flags & FORK_REOPEN_LOG) {
+                log_open();
+                log_set_open_when_needed(false);
+        }
+
+        if (flags & FORK_NULL_STDIO) {
+                r = make_null_stdio();
+                if (r < 0) {
+                        log_debug_errno(r, "Failed to connect stdin/stdout to /dev/null: %m");
+                        _exit(EXIT_FAILURE);
+                }
+        }
+
+        if (ret_pid)
+                *ret_pid = getpid_cached();
+
+        return 0;
+}
+
 static const char *const ioprio_class_table[] = {
         [IOPRIO_CLASS_NONE] = "none",
         [IOPRIO_CLASS_RT] = "realtime",
index 1b7e692..0ab1eec 100644 (file)
@@ -142,3 +142,17 @@ int ioprio_parse_priority(const char *s, int *ret);
 pid_t getpid_cached(void);
 
 int must_be_root(void);
+
+typedef enum ForkFlags {
+        FORK_RESET_SIGNALS = 1U << 0,
+        FORK_CLOSE_ALL_FDS = 1U << 1,
+        FORK_DEATHSIG      = 1U << 2,
+        FORK_NULL_STDIO    = 1U << 3,
+        FORK_REOPEN_LOG    = 1U << 4,
+} ForkFlags;
+
+int safe_fork_full(const char *name, const int except_fds[], size_t n_except_fds, ForkFlags flags, pid_t *ret_pid);
+
+static inline int safe_fork(const char *name, ForkFlags flags, pid_t *ret_pid) {
+        return safe_fork_full(name, NULL, 0, flags, ret_pid);
+}
index 6051daf..d15fa38 100644 (file)
@@ -1106,11 +1106,10 @@ int openpt_in_namespace(pid_t pid, int flags) {
         if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
                 return -errno;
 
-        child = fork();
-        if (child < 0)
-                return -errno;
-
-        if (child == 0) {
+        r = safe_fork("(sd-openpt)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child);
+        if (r < 0)
+                return r;
+        if (r == 0) {
                 int master;
 
                 pair[0] = safe_close(pair[0]);
@@ -1157,11 +1156,10 @@ int open_terminal_in_namespace(pid_t pid, const char *name, int mode) {
         if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
                 return -errno;
 
-        child = fork();
-        if (child < 0)
-                return -errno;
-
-        if (child == 0) {
+        r = safe_fork("(sd-terminal)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child);
+        if (r < 0)
+                return r;
+        if (r == 0) {
                 int master;
 
                 pair[0] = safe_close(pair[0]);
index d56576d..95358f8 100644 (file)
@@ -886,8 +886,8 @@ typedef struct ParseTimestampResult {
 int parse_timestamp(const char *t, usec_t *usec) {
         char *last_space, *tz = NULL;
         ParseTimestampResult *shared, tmp;
-        int r;
         pid_t pid;
+        int r;
 
         last_space = strrchr(t, ' ');
         if (last_space != NULL && timezone_is_valid(last_space + 1))
@@ -900,15 +900,12 @@ int parse_timestamp(const char *t, usec_t *usec) {
         if (shared == MAP_FAILED)
                 return negative_errno();
 
-        pid = fork();
-
-        if (pid == -1) {
-                int fork_errno = errno;
+        r = safe_fork("(sd-timestamp)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG, &pid);
+        if (r < 0) {
                 (void) munmap(shared, sizeof *shared);
-                return -fork_errno;
+                return r;
         }
-
-        if (pid == 0) {
+        if (r == 0) {
                 bool with_tz = true;
 
                 if (setenv("TZ", tz, 1) != 0) {
index 8f9f2b9..8e43187 100644 (file)
@@ -186,11 +186,11 @@ int prot_from_flags(int flags) {
 
 int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *path, ...) {
         bool stdout_is_tty, stderr_is_tty;
-        pid_t parent_pid, agent_pid;
-        sigset_t ss, saved_ss;
+        pid_t agent_pid;
         unsigned n, i;
         va_list ap;
         char **l;
+        int r;
 
         assert(pid);
         assert(path);
@@ -198,45 +198,13 @@ int fork_agent(pid_t *pid, const int except[], unsigned n_except, const char *pa
         /* Spawns a temporary TTY agent, making sure it goes away when
          * we go away */
 
-        parent_pid = getpid_cached();
-
-        /* First we temporarily block all signals, so that the new
-         * child has them blocked initially. This way, we can be sure
-         * that SIGTERMs are not lost we might send to the agent. */
-        assert_se(sigfillset(&ss) >= 0);
-        assert_se(sigprocmask(SIG_SETMASK, &ss, &saved_ss) >= 0);
-
-        agent_pid = fork();
-        if (agent_pid < 0) {
-                assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0);
-                return -errno;
-        }
-
-        if (agent_pid != 0) {
-                assert_se(sigprocmask(SIG_SETMASK, &saved_ss, NULL) >= 0);
-                *pid = agent_pid;
+        r = safe_fork_full("(sd-agent)", except, n_except, FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS, &agent_pid);
+        if (r < 0)
+                return r;
+        if (r > 0)
                 return 0;
-        }
 
-        /* In the child:
-         *
-         * Make sure the agent goes away when the parent dies */
-        if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
-                _exit(EXIT_FAILURE);
-
-        /* Make sure we actually can kill the agent, if we need to, in
-         * case somebody invoked us from a shell script that trapped
-         * SIGTERM or so... */
-        (void) reset_all_signal_handlers();
-        (void) reset_signal_mask();
-
-        /* Check whether our parent died before we were able
-         * to set the death signal and unblock the signals */
-        if (getppid() != parent_pid)
-                _exit(EXIT_SUCCESS);
-
-        /* Don't leak fds to the agent */
-        close_all_fds(except, n_except);
+        /* In the child: */
 
         stdout_is_tty = isatty(STDOUT_FILENO);
         stderr_is_tty = isatty(STDERR_FILENO);
index aa9120b..3f3d732 100644 (file)
@@ -1207,27 +1207,19 @@ static int setup_pam(
 
         parent_pid = getpid_cached();
 
-        pam_pid = fork();
-        if (pam_pid < 0) {
-                r = -errno;
+        r = safe_fork("(sd-pam)", 0, &pam_pid);
+        if (r < 0)
                 goto fail;
-        }
-
-        if (pam_pid == 0) {
+        if (r == 0) {
                 int sig, ret = EXIT_PAM;
 
                 /* The child's job is to reset the PAM session on
                  * termination */
                 barrier_set_role(&barrier, BARRIER_CHILD);
 
-                /* This string must fit in 10 chars (i.e. the length
-                 * of "/sbin/init"), to look pretty in /bin/ps */
-                rename_process("(sd-pam)");
-
-                /* Make sure we don't keep open the passed fds in this
-                child. We assume that otherwise only those fds are
-                open here that have been opened by PAM. */
-                close_many(fds, n_fds);
+                /* Make sure we don't keep open the passed fds in this child. We assume that otherwise only those fds
+                 * are open here that have been opened by PAM. */
+                (void) close_many(fds, n_fds);
 
                 /* Drop privileges - we don't need any to pam_close_session
                  * and this will make PR_SET_PDEATHSIG work in most cases.
@@ -1879,11 +1871,10 @@ static int setup_private_users(uid_t uid, gid_t gid) {
         if (pipe2(errno_pipe, O_CLOEXEC) < 0)
                 return -errno;
 
-        pid = fork();
-        if (pid < 0)
-                return -errno;
-
-        if (pid == 0) {
+        r = safe_fork("(sd-userns)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
+        if (r < 0)
+                return r;
+        if (r == 0) {
                 _cleanup_close_ int fd = -1;
                 const char *a;
                 pid_t ppid;
index aca89d1..9ef4e77 100644 (file)
@@ -221,13 +221,12 @@ static void sync_with_progress(void) {
         /* Due to the possiblity of the sync operation hanging, we fork
          * a child process and monitor the progress. If the timeout
          * lapses, the assumption is that that particular sync stalled. */
-        pid = fork();
-        if (pid < 0) {
-                log_error_errno(errno, "Failed to fork: %m");
+        r = safe_fork("(sd-sync)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS, &pid);
+        if (r < 0) {
+                log_error_errno(r, "Failed to fork: %m");
                 return;
         }
-
-        if (pid == 0) {
+        if (r == 0) {
                 /* Start the sync operation here in the child */
                 sync();
                 _exit(EXIT_SUCCESS);
@@ -492,10 +491,10 @@ int main(int argc, char *argv[]) {
 
                         log_info("Rebooting with kexec.");
 
-                        pid = fork();
-                        if (pid < 0)
-                                log_error_errno(errno, "Failed to fork: %m");
-                        else if (pid == 0) {
+                        r = safe_fork("(sd-kexec)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS, &pid);
+                        if (r < 0)
+                                log_error_errno(r, "Failed to fork: %m");
+                        if (r == 0) {
 
                                 const char * const args[] = {
                                         KEXEC, "-e", NULL
@@ -505,8 +504,9 @@ int main(int argc, char *argv[]) {
 
                                 execv(args[0], (char * const *) args);
                                 _exit(EXIT_FAILURE);
-                        } else
-                                wait_for_terminate_and_warn("kexec", pid, true);
+                        }
+
+                        (void) wait_for_terminate_and_warn("kexec", pid, true);
                 }
 
                 cmd = RB_AUTOBOOT;
index d2c4694..8e796e9 100644 (file)
@@ -1527,7 +1527,7 @@ static int socket_address_listen_in_cgroup(
         if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, pair) < 0)
                 return log_unit_error_errno(UNIT(s), errno, "Failed to create communication channel: %m");
 
-        r = unit_fork_helper_process(UNIT(s), &pid);
+        r = unit_fork_helper_process(UNIT(s), "(sd-listen)", &pid);
         if (r < 0)
                 return log_unit_error_errno(UNIT(s), r, "Failed to fork off listener stub process: %m");
         if (r == 0) {
@@ -1944,7 +1944,7 @@ static int socket_chown(Socket *s, pid_t *_pid) {
         /* We have to resolve the user names out-of-process, hence
          * let's fork here. It's messy, but well, what can we do? */
 
-        r = unit_fork_helper_process(UNIT(s), &pid);
+        r = unit_fork_helper_process(UNIT(s), "(sd-chown)", &pid);
         if (r < 0)
                 return r;
         if (r == 0) {
@@ -2871,7 +2871,7 @@ static int socket_accept_in_cgroup(Socket *s, SocketPort *p, int fd) {
         if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, pair) < 0)
                 return log_unit_error_errno(UNIT(s), errno, "Failed to create communication channel: %m");
 
-        r = unit_fork_helper_process(UNIT(s), &pid);
+        r = unit_fork_helper_process(UNIT(s), "(sd-accept)", &pid);
         if (r < 0)
                 return log_unit_error_errno(UNIT(s), r, "Failed to fork off accept stub process: %m");
         if (r == 0) {
index 7f8ddb9..d8ccdfd 100644 (file)
@@ -388,11 +388,10 @@ static int remount_with_timeout(MountPoint *m, char *options, int *n_failed) {
          * fork a child process and set a timeout. If the timeout
          * lapses, the assumption is that that particular remount
          * failed. */
-        pid = fork();
-        if (pid < 0)
-                return log_error_errno(errno, "Failed to fork: %m");
-
-        if (pid == 0) {
+        r = safe_fork("(sd-remount)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS, &pid);
+        if (r < 0)
+                return log_error_errno(r, "Failed to fork: %m");
+        if (r == 0) {
                 log_info("Remounting '%s' read-only in with options '%s'.", m->path, options);
 
                 /* Start the mount operation here in the child */
@@ -423,11 +422,10 @@ static int umount_with_timeout(MountPoint *m, bool *changed) {
          * fork a child process and set a timeout. If the timeout
          * lapses, the assumption is that that particular umount
          * failed. */
-        pid = fork();
-        if (pid < 0)
-                return log_error_errno(errno, "Failed to fork: %m");
-
-        if (pid == 0) {
+        r = safe_fork("(sd-umount)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS, &pid);
+        if (r < 0)
+                return log_error_errno(r, "Failed to fork: %m");
+        if (r == 0) {
                 log_info("Unmounting '%s'.", m->path);
 
                 /* Start the mount operation here in the child Using MNT_FORCE
index 7af8425..652587e 100644 (file)
@@ -21,6 +21,7 @@
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/prctl.h>
 #include <sys/stat.h>
 #include <unistd.h>
 
@@ -4968,8 +4969,7 @@ void unit_set_exec_params(Unit *u, ExecParameters *p) {
         SET_FLAG(p->flags, EXEC_CGROUP_DELEGATE, UNIT_CGROUP_BOOL(u, delegate));
 }
 
-int unit_fork_helper_process(Unit *u, pid_t *ret) {
-        pid_t pid;
+int unit_fork_helper_process(Unit *u, const char *name, pid_t *ret) {
         int r;
 
         assert(u);
@@ -4980,32 +4980,24 @@ int unit_fork_helper_process(Unit *u, pid_t *ret) {
 
         (void) unit_realize_cgroup(u);
 
-        pid = fork();
-        if (pid < 0)
-                return -errno;
-
-        if (pid == 0) {
+        r = safe_fork(name, FORK_REOPEN_LOG, ret);
+        if (r != 0)
+                return r;
 
-                (void) default_signals(SIGNALS_CRASH_HANDLER, SIGNALS_IGNORE, -1);
-                (void) ignore_signals(SIGPIPE, -1);
+        (void) default_signals(SIGNALS_CRASH_HANDLER, SIGNALS_IGNORE, -1);
+        (void) ignore_signals(SIGPIPE, -1);
 
-                log_close();
-                log_open();
+        (void) prctl(PR_SET_PDEATHSIG, SIGTERM);
 
-                if (u->cgroup_path) {
-                        r = cg_attach_everywhere(u->manager->cgroup_supported, u->cgroup_path, 0, NULL, NULL);
-                        if (r < 0) {
-                                log_unit_error_errno(u, r, "Failed to join unit cgroup %s: %m", u->cgroup_path);
-                                _exit(EXIT_CGROUP);
-                        }
+        if (u->cgroup_path) {
+                r = cg_attach_everywhere(u->manager->cgroup_supported, u->cgroup_path, 0, NULL, NULL);
+                if (r < 0) {
+                        log_unit_error_errno(u, r, "Failed to join unit cgroup %s: %m", u->cgroup_path);
+                        _exit(EXIT_CGROUP);
                 }
-
-                *ret = getpid_cached();
-                return 0;
         }
 
-        *ret = pid;
-        return 1;
+        return 0;
 }
 
 static void unit_update_dependency_mask(Unit *u, UnitDependency d, Unit *other, UnitDependencyInfo di) {
index fdd8231..80585ac 100644 (file)
@@ -782,7 +782,7 @@ bool unit_shall_confirm_spawn(Unit *u);
 
 void unit_set_exec_params(Unit *s, ExecParameters *p);
 
-int unit_fork_helper_process(Unit *u, pid_t *ret);
+int unit_fork_helper_process(Unit *u, const char *name, pid_t *ret);
 
 void unit_remove_dependencies(Unit *u, UnitDependencyMask mask);
 
index 2fd5adc..5013758 100644 (file)
@@ -928,17 +928,13 @@ static int run_gdb(sd_journal *j) {
         /* Don't interfere with gdb and its handling of SIGINT. */
         (void) ignore_signals(SIGINT, -1);
 
-        pid = fork();
-        if (pid < 0) {
-                r = log_error_errno(errno, "Failed to fork(): %m");
+        r = safe_fork("(gdb)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS, &pid);
+        if (r < 0) {
+                log_error_errno(r, "Failed to fork(): %m");
                 goto finish;
         }
-        if (pid == 0) {
-                (void) reset_all_signal_handlers();
-                (void) reset_signal_mask();
-
+        if (r == 0) {
                 execlp("gdb", "gdb", exe, path, NULL);
-
                 log_error_errno(errno, "Failed to invoke gdb: %m");
                 _exit(1);
         }
index d286881..8ebfbf4 100644 (file)
@@ -161,8 +161,8 @@ static int notify_override_unchanged(const char *f) {
 
 static int found_override(const char *top, const char *bottom) {
         _cleanup_free_ char *dest = NULL;
-        int k;
         pid_t pid;
+        int r;
 
         assert(top);
         assert(bottom);
@@ -170,31 +170,26 @@ static int found_override(const char *top, const char *bottom) {
         if (null_or_empty_path(top) > 0)
                 return notify_override_masked(top, bottom);
 
-        k = readlink_malloc(top, &dest);
-        if (k >= 0) {
+        r = readlink_malloc(top, &dest);
+        if (r >= 0) {
                 if (equivalent(dest, bottom) > 0)
                         return notify_override_equivalent(top, bottom);
                 else
                         return notify_override_redirected(top, bottom);
         }
 
-        k = notify_override_overridden(top, bottom);
+        r = notify_override_overridden(top, bottom);
         if (!arg_diff)
-                return k;
+                return r;
 
         putchar('\n');
 
         fflush(stdout);
 
-        pid = fork();
-        if (pid < 0)
-                return log_error_errno(errno, "Failed to fork off diff: %m");
-        else if (pid == 0) {
-
-                (void) reset_all_signal_handlers();
-                (void) reset_signal_mask();
-                assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
-
+        r = safe_fork("(diff)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS, &pid);
+        if (r < 0)
+                return log_error_errno(pid, "Failed to fork off diff: %m");
+        if (r == 0) {
                 execlp("diff", "diff", "-us", "--", bottom, top, NULL);
                 log_error_errno(errno, "Failed to execute diff: %m");
                 _exit(EXIT_FAILURE);
@@ -203,7 +198,7 @@ static int found_override(const char *top, const char *bottom) {
         wait_for_terminate_and_warn("diff", pid, false);
         putchar('\n');
 
-        return k;
+        return r;
 }
 
 static int enumerate_dir_d(
index 0091e38..818d581 100644 (file)
@@ -392,12 +392,12 @@ int main(int argc, char *argv[]) {
                 }
         }
 
-        pid = fork();
-        if (pid < 0) {
-                r = log_error_errno(errno, "fork(): %m");
+        r = safe_fork("(fsck)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
+        if (r < 0) {
+                log_error_errno(r, "fork(): %m");
                 goto finish;
         }
-        if (pid == 0) {
+        if (r == 0) {
                 char dash_c[STRLEN("-C") + DECIMAL_STR_MAX(int) + 1];
                 int progress_socket = -1;
                 const char *cmdline[9];
@@ -405,10 +405,6 @@ int main(int argc, char *argv[]) {
 
                 /* Child */
 
-                (void) reset_all_signal_handlers();
-                (void) reset_signal_mask();
-                assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
-
                 /* Close the reading side of the progress pipe */
                 progress_pipe[0] = safe_close(progress_pipe[0]);
 
index 2f989a1..1efbda9 100644 (file)
@@ -82,11 +82,10 @@ int import_fork_tar_x(const char *path, pid_t *ret) {
         if (pipe2(pipefd, O_CLOEXEC) < 0)
                 return log_error_errno(errno, "Failed to create pipe for tar: %m");
 
-        pid = fork();
-        if (pid < 0)
-                return log_error_errno(errno, "Failed to fork off tar: %m");
-
-        if (pid == 0) {
+        r = safe_fork("(tar)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
+        if (r < 0)
+                return log_error_errno(r, "Failed to fork off tar: %m");
+        if (r == 0) {
                 int null_fd;
                 uint64_t retain =
                         (1ULL << CAP_CHOWN) |
@@ -98,10 +97,6 @@ int import_fork_tar_x(const char *path, pid_t *ret) {
 
                 /* Child */
 
-                (void) reset_all_signal_handlers();
-                (void) reset_signal_mask();
-                assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
-
                 pipefd[1] = safe_close(pipefd[1]);
 
                 r = move_fd(pipefd[0], STDIN_FILENO, false);
@@ -156,20 +151,15 @@ int import_fork_tar_c(const char *path, pid_t *ret) {
         if (pipe2(pipefd, O_CLOEXEC) < 0)
                 return log_error_errno(errno, "Failed to create pipe for tar: %m");
 
-        pid = fork();
-        if (pid < 0)
-                return log_error_errno(errno, "Failed to fork off tar: %m");
-
-        if (pid == 0) {
+        r = safe_fork("(tar)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
+        if (r < 0)
+                return log_error_errno(r, "Failed to fork off tar: %m");
+        if (r == 0) {
                 int null_fd;
                 uint64_t retain = (1ULL << CAP_DAC_OVERRIDE);
 
                 /* Child */
 
-                (void) reset_all_signal_handlers();
-                (void) reset_signal_mask();
-                assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
-
                 pipefd[0] = safe_close(pipefd[0]);
 
                 r = move_fd(pipefd[1], STDOUT_FILENO, false);
index 9c7694c..21af09f 100644 (file)
@@ -371,10 +371,10 @@ static int transfer_start(Transfer *t) {
         if (pipe2(pipefd, O_CLOEXEC) < 0)
                 return -errno;
 
-        t->pid = fork();
-        if (t->pid < 0)
-                return -errno;
-        if (t->pid == 0) {
+        r = safe_fork("(sd-transfer)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &t->pid);
+        if (r < 0)
+                return r;
+        if (r == 0) {
                 const char *cmd[] = {
                         NULL, /* systemd-import, systemd-export or systemd-pull */
                         NULL, /* tar, raw  */
@@ -393,10 +393,6 @@ static int transfer_start(Transfer *t) {
 
                 /* Child */
 
-                (void) reset_all_signal_handlers();
-                (void) reset_signal_mask();
-                assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
-
                 pipefd[0] = safe_close(pipefd[0]);
 
                 if (dup2(pipefd[1], STDERR_FILENO) != STDERR_FILENO) {
index c2a3a6a..6acd264 100644 (file)
@@ -463,10 +463,10 @@ int pull_verify(PullJob *main_job,
 
         gpg_home_created = true;
 
-        pid = fork();
-        if (pid < 0)
-                return log_error_errno(errno, "Failed to fork off gpg: %m");
-        if (pid == 0) {
+        r = safe_fork("(gpg)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
+        if (r < 0)
+                return log_error_errno(r, "Failed to fork off gpg: %m");
+        if (r == 0) {
                 const char *cmd[] = {
                         "gpg",
                         "--no-options",
@@ -487,10 +487,6 @@ int pull_verify(PullJob *main_job,
 
                 /* Child */
 
-                (void) reset_all_signal_handlers();
-                (void) reset_signal_mask();
-                assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
-
                 gpg_pipe[1] = safe_close(gpg_pipe[1]);
 
                 r = move_fd(gpg_pipe[0], STDIN_FILENO, false);
index e44989e..3241649 100644 (file)
@@ -81,27 +81,20 @@ static bool arg_trust_all = false;
  **********************************************************************/
 
 static int spawn_child(const char* child, char** argv) {
-        int fd[2];
-        pid_t parent_pid, child_pid;
-        int r;
+        pid_t child_pid;
+        int fd[2], r;
 
         if (pipe(fd) < 0)
                 return log_error_errno(errno, "Failed to create pager pipe: %m");
 
-        parent_pid = getpid_cached();
-
-        child_pid = fork();
-        if (child_pid < 0) {
-                r = log_error_errno(errno, "Failed to fork: %m");
+        r = safe_fork("(remote)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child_pid);
+        if (r < 0) {
                 safe_close_pair(fd);
-                return r;
+                return log_error_errno(r, "Failed to fork: %m");
         }
 
         /* In the child */
-        if (child_pid == 0) {
-
-                (void) reset_all_signal_handlers();
-                (void) reset_signal_mask();
+        if (r == 0) {
 
                 r = dup2(fd[1], STDOUT_FILENO);
                 if (r < 0) {
@@ -111,15 +104,6 @@ static int spawn_child(const char* child, char** argv) {
 
                 safe_close_pair(fd);
 
-                /* Make sure the child goes away when the parent dies */
-                if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
-                        _exit(EXIT_FAILURE);
-
-                /* Check whether our parent died before we were able
-                 * to set the death signal */
-                if (getppid() != parent_pid)
-                        _exit(EXIT_SUCCESS);
-
                 execvp(child, argv);
                 log_error_errno(errno, "Failed to exec child %s: %m", child);
                 _exit(EXIT_FAILURE);
index 8f6d348..a1242c5 100644 (file)
@@ -62,11 +62,10 @@ int bus_container_connect_socket(sd_bus *b) {
         if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
                 return -errno;
 
-        child = fork();
-        if (child < 0)
-                return -errno;
-
-        if (child == 0) {
+        r = safe_fork("(sd-buscntr)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child);
+        if (r < 0)
+                return r;
+        if (r == 0) {
                 pid_t grandchild;
 
                 pair[0] = safe_close(pair[0]);
@@ -82,11 +81,10 @@ int bus_container_connect_socket(sd_bus *b) {
                  * comes from a process from within the container, and
                  * not outside of it */
 
-                grandchild = fork();
-                if (grandchild < 0)
+                r = safe_fork("(sd-buscntr2)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &grandchild);
+                if (r < 0)
                         _exit(EXIT_FAILURE);
-
-                if (grandchild == 0) {
+                if (r == 0) {
 
                         r = connect(b->input_fd, &b->sockaddr.sa, b->sockaddr_size);
                         if (r < 0) {
index d72cb61..013bdb0 100644 (file)
@@ -715,19 +715,14 @@ int bus_socket_exec(sd_bus *b) {
         if (r < 0)
                 return -errno;
 
-        pid = fork();
-        if (pid < 0) {
+        r = safe_fork_full("(sd-busexec)", s+1, 1, FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS, &pid);
+        if (r < 0) {
                 safe_close_pair(s);
-                return -errno;
+                return r;
         }
-        if (pid == 0) {
+        if (r == 0) {
                 /* Child */
 
-                (void) reset_all_signal_handlers();
-                (void) reset_signal_mask();
-
-                close_all_fds(s+1, 1);
-
                 assert_se(dup3(s[1], STDIN_FILENO, 0) == STDIN_FILENO);
                 assert_se(dup3(s[1], STDOUT_FILENO, 0) == STDOUT_FILENO);
 
index 7b9e3f0..9117a70 100644 (file)
@@ -266,20 +266,13 @@ int main(int argc, char *argv[]) {
                         return EXIT_FAILURE;
                 }
 
-                pid = fork();
-                if (pid < 0) {
-                        log_error_errno(errno, "Failed to fork: %m");
+                r = safe_fork("(inhibit)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS, &pid);
+                if (r < 0) {
+                        log_error_errno(r, "Failed to fork: %m");
                         return EXIT_FAILURE;
                 }
-
-                if (pid == 0) {
+                if (r == 0) {
                         /* Child */
-
-                        (void) reset_all_signal_handlers();
-                        (void) reset_signal_mask();
-
-                        close_all_fds(NULL, 0);
-
                         execvp(argv[optind], argv + optind);
                         log_error_errno(errno, "Failed to execute %s: %m", argv[optind]);
                         _exit(EXIT_FAILURE);
index 10d1b06..8ba1380 100644 (file)
@@ -75,10 +75,10 @@ int bus_image_method_remove(
         if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
                 return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
 
-        child = fork();
-        if (child < 0)
-                return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
-        if (child == 0) {
+        r = safe_fork("(sd-imgrm)", FORK_RESET_SIGNALS, &child);
+        if (r < 0)
+                return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
+        if (r == 0) {
                 errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
 
                 r = image_remove(image);
@@ -187,10 +187,10 @@ int bus_image_method_clone(
         if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
                 return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
 
-        child = fork();
-        if (child < 0)
-                return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
-        if (child == 0) {
+        r = safe_fork("(imgclone)", FORK_RESET_SIGNALS, &child);
+        if (r < 0)
+                return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
+        if (r == 0) {
                 errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
 
                 r = image_clone(image, new_name, read_only);
index 2d3d285..68e0b7e 100644 (file)
@@ -250,11 +250,10 @@ int bus_machine_method_get_addresses(sd_bus_message *message, void *userdata, sd
                 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
                         return -errno;
 
-                child = fork();
-                if (child < 0)
-                        return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
-
-                if (child == 0) {
+                r = safe_fork("(sd-addr)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child);
+                if (r < 0)
+                        return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
+                if (r == 0) {
                         _cleanup_free_ struct local_address *addresses = NULL;
                         struct local_address *a;
                         int i, n;
@@ -390,11 +389,10 @@ int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, s
                 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
                         return -errno;
 
-                child = fork();
-                if (child < 0)
-                        return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
-
-                if (child == 0) {
+                r = safe_fork("(sd-osrel)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child);
+                if (r < 0)
+                        return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
+                if (r == 0) {
                         int fd = -1;
 
                         pair[0] = safe_close(pair[0]);
@@ -997,13 +995,12 @@ int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bu
                 goto finish;
         }
 
-        child = fork();
-        if (child < 0) {
-                r = sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
+        r = safe_fork("(sd-bindmnt)", FORK_RESET_SIGNALS, &child);
+        if (r < 0) {
+                sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
                 goto finish;
         }
-
-        if (child == 0) {
+        if (r == 0) {
                 const char *mount_inside;
                 int mntfd;
                 const char *q;
@@ -1172,11 +1169,10 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro
         if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
                 return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
 
-        child = fork();
-        if (child < 0)
-                return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
-
-        if (child == 0) {
+        r = safe_fork("(sd-copy)", FORK_RESET_SIGNALS, &child);
+        if (r < 0)
+                return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
+        if (r == 0) {
                 int containerfd;
                 const char *q;
                 int mntfd;
@@ -1282,11 +1278,10 @@ int bus_machine_method_open_root_directory(sd_bus_message *message, void *userda
                 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
                         return -errno;
 
-                child = fork();
-                if (child < 0)
-                        return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
-
-                if (child == 0) {
+                r = safe_fork("(sd-openroot)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child);
+                if (r < 0)
+                        return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
+                if (r == 0) {
                         _cleanup_close_ int dfd = -1;
 
                         pair[0] = safe_close(pair[0]);
index 330d6b3..c5e59c4 100644 (file)
@@ -1078,11 +1078,10 @@ static int method_clean_pool(sd_bus_message *message, void *userdata, sd_bus_err
                 return -errno;
 
         /* This might be a slow operation, run it asynchronously in a background process */
-        child = fork();
-        if (child < 0)
-                return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
-
-        if (child == 0) {
+        r = safe_fork("(sd-clean)", FORK_RESET_SIGNALS, &child);
+        if (r < 0)
+                return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
+        if (r == 0) {
                 _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
                 bool success = true;
                 Image *image;
index 31f5dd3..3d9e23e 100644 (file)
@@ -33,7 +33,7 @@
 #include "util.h"
 
 static int spawn_getent(const char *database, const char *key, pid_t *rpid) {
-        int pipe_fds[2];
+        int pipe_fds[2], r;
         pid_t pid;
 
         assert(database);
@@ -43,10 +43,10 @@ static int spawn_getent(const char *database, const char *key, pid_t *rpid) {
         if (pipe2(pipe_fds, O_CLOEXEC) < 0)
                 return log_error_errno(errno, "Failed to allocate pipe: %m");
 
-        pid = fork();
-        if (pid < 0)
-                return log_error_errno(errno, "Failed to fork getent child: %m");
-        else if (pid == 0) {
+        r = safe_fork("(getent)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
+        if (r < 0)
+                return log_error_errno(r, "Failed to fork getent child: %m");
+        if (r == 0) {
                 int nullfd;
                 char *empty_env = NULL;
 
@@ -71,8 +71,6 @@ static int spawn_getent(const char *database, const char *key, pid_t *rpid) {
                 if (nullfd > 2)
                         safe_close(nullfd);
 
-                (void) reset_all_signal_handlers();
-                (void) reset_signal_mask();
                 close_all_fds(NULL, 0);
 
                 execle("/usr/bin/getent", "getent", database, key, NULL, &empty_env);
index bb87eb1..58f4636 100644 (file)
@@ -93,7 +93,7 @@ int stub_pid1(sd_id128_t uuid) {
         sd_id128_to_string(uuid, new_environment + sizeof(new_environment) - SD_ID128_STRING_MAX);
         reset_environ(new_environment, sizeof(new_environment));
 
-        rename_process("STUBINIT");
+        (void) rename_process("(sd-stubinit)");
 
         assert_se(sigemptyset(&waitmask) >= 0);
         assert_se(sigset_add_many(&waitmask,
index e5e1252..872cf0d 100644 (file)
@@ -34,6 +34,7 @@
 static int makefs(const char *type, const char *device) {
         const char *mkfs;
         pid_t pid;
+        int r;
 
         if (streq(type, "swap"))
                 mkfs = "/sbin/mkswap";
@@ -42,19 +43,14 @@ static int makefs(const char *type, const char *device) {
         if (access(mkfs, X_OK) != 0)
                 return log_error_errno(errno, "%s is not executable: %m", mkfs);
 
-        pid = fork();
-        if (pid < 0)
-                return log_error_errno(errno, "fork(): %m");
-
-        if (pid == 0) {
+        r = safe_fork("(fsck)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
+        if (r < 0)
+                return log_error_errno(r, "fork(): %m");
+        if (r == 0) {
                 const char *cmdline[3] = { mkfs, device, NULL };
 
                 /* Child */
 
-                (void) reset_all_signal_handlers();
-                (void) reset_signal_mask();
-                assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
-
                 execv(cmdline[0], (char**) cmdline);
                 _exit(EXIT_FAILURE);
         }
index ec5be21..b5636e6 100644 (file)
@@ -106,19 +106,15 @@ int main(int argc, char *argv[]) {
                         return EXIT_SUCCESS;
         }
 
-        pid = fork();
-        if (pid < 0) {
-                r = log_error_errno(errno, "fork(): %m");
+        r = safe_fork("(quotacheck)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
+        if (r < 0) {
+                log_error_errno(r, "fork(): %m");
                 goto finish;
         }
-        if (pid == 0) {
+        if (r == 0) {
 
                 /* Child */
 
-                (void) reset_all_signal_handlers();
-                (void) reset_signal_mask();
-                assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
-
                 execv(cmdline[0], (char**) cmdline);
                 _exit(1); /* Operational error */
         }
index 2d7cf72..1f0397c 100644 (file)
@@ -87,19 +87,14 @@ int main(int argc, char *argv[]) {
 
                 log_debug("Remounting %s", me->mnt_dir);
 
-                pid = fork();
-                if (pid < 0) {
-                        r = log_error_errno(errno, "Failed to fork: %m");
+                r = safe_fork("(remount)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
+                if (r < 0) {
+                        log_error_errno(r, "Failed to fork: %m");
                         goto finish;
                 }
-
-                if (pid == 0) {
+                if (r == 0) {
                         /* Child */
 
-                        (void) reset_all_signal_handlers();
-                        (void) reset_signal_mask();
-                        (void) prctl(PR_SET_PDEATHSIG, SIGTERM);
-
                         execv(MOUNT_PATH, STRV_MAKE(MOUNT_PATH, me->mnt_dir, "-o", "remount"));
 
                         log_error_errno(errno, "Failed to execute " MOUNT_PATH ": %m");
index af7f8f3..ffb921e 100644 (file)
@@ -1278,11 +1278,10 @@ static int get_boot_id_for_machine(const char *machine, sd_id128_t *boot_id) {
         if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
                 return -errno;
 
-        child = fork();
-        if (child < 0)
-                return -errno;
-
-        if (child == 0) {
+        r = safe_fork("(sd-bootid)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &child);
+        if (r < 0)
+                return r;
+        if (r == 0) {
                 int fd;
 
                 pair[0] = safe_close(pair[0]);
index e7d19b1..fb8a6e2 100644 (file)
@@ -123,20 +123,15 @@ static int setup_machine_raw(uint64_t size, sd_bus_error *error) {
                 goto fail;
         }
 
-        pid = fork();
-        if (pid < 0) {
-                r = sd_bus_error_set_errnof(error, errno, "Failed to fork mkfs.btrfs: %m");
+        r = safe_fork("(mkfs)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
+        if (r < 0) {
+                sd_bus_error_set_errnof(error, r, "Failed to fork mkfs.btrfs: %m");
                 goto fail;
         }
-
-        if (pid == 0) {
+        if (r == 0) {
 
                 /* Child */
 
-                (void) reset_all_signal_handlers();
-                (void) reset_signal_mask();
-                assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
-
                 fd = safe_close(fd);
 
                 execlp("mkfs.btrfs", "-Lvar-lib-machines", tmp, NULL);
index 3999727..17e0121 100644 (file)
@@ -62,7 +62,7 @@ static bool stderr_redirected = false;
 int pager_open(bool no_pager, bool jump_to_end) {
         _cleanup_close_pair_ int fd[2] = { -1, -1 };
         const char *pager;
-        pid_t parent_pid;
+        int r;
 
         if (no_pager)
                 return 0;
@@ -89,18 +89,13 @@ int pager_open(bool no_pager, bool jump_to_end) {
         if (pipe2(fd, O_CLOEXEC) < 0)
                 return log_error_errno(errno, "Failed to create pager pipe: %m");
 
-        parent_pid = getpid_cached();
-
-        pager_pid = fork();
-        if (pager_pid < 0)
-                return log_error_errno(errno, "Failed to fork pager: %m");
-
-        /* In the child start the pager */
-        if (pager_pid == 0) {
+        r = safe_fork("(pager)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pager_pid);
+        if (r < 0)
+                return log_error_errno(r, "Failed to fork pager: %m");
+        if (r == 0) {
                 const char* less_opts, *less_charset;
 
-                (void) reset_all_signal_handlers();
-                (void) reset_signal_mask();
+                /* In the child start the pager */
 
                 (void) dup2(fd[0], STDIN_FILENO);
                 safe_close_pair(fd);
@@ -124,15 +119,6 @@ int pager_open(bool no_pager, bool jump_to_end) {
                     setenv("LESSCHARSET", less_charset, 1) < 0)
                         _exit(EXIT_FAILURE);
 
-                /* Make sure the pager goes away when the parent dies */
-                if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
-                        _exit(EXIT_FAILURE);
-
-                /* Check whether our parent died before we were able
-                 * to set the death signal */
-                if (getppid() != parent_pid)
-                        _exit(EXIT_SUCCESS);
-
                 if (pager) {
                         execlp(pager, pager, NULL);
                         execl("/bin/sh", "sh", "-c", pager, NULL);
@@ -222,24 +208,11 @@ int show_man_page(const char *desc, bool null_stdio) {
         } else
                 args[1] = desc;
 
-        pid = fork();
-        if (pid < 0)
-                return log_error_errno(errno, "Failed to fork: %m");
-
-        if (pid == 0) {
+        r = safe_fork("(man)", FORK_RESET_SIGNALS|FORK_DEATHSIG|(null_stdio ? FORK_NULL_STDIO : 0), &pid);
+        if (r < 0)
+                return log_error_errno(r, "Failed to fork: %m");
+        if (r == 0) {
                 /* Child */
-
-                (void) reset_all_signal_handlers();
-                (void) reset_signal_mask();
-
-                if (null_stdio) {
-                        r = make_null_stdio();
-                        if (r < 0) {
-                                log_error_errno(r, "Failed to kill stdio: %m");
-                                _exit(EXIT_FAILURE);
-                        }
-                }
-
                 execvp(args[0], (char**) args);
                 log_error_errno(errno, "Failed to execute man: %m");
                 _exit(EXIT_FAILURE);
index 70659df..a6e0e04 100644 (file)
@@ -81,18 +81,13 @@ static int start_default_target(sd_bus *bus) {
 
 static int fork_wait(const char* const cmdline[]) {
         pid_t pid;
+        int r;
 
-        pid = fork();
-        if (pid < 0)
-                return log_error_errno(errno, "fork(): %m");
-        if (pid == 0) {
-
+        r = safe_fork("(sulogin)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
+        if (r < 0)
+                return log_error_errno(r, "fork(): %m");
+        if (r == 0) {
                 /* Child */
-
-                (void) reset_all_signal_handlers();
-                (void) reset_signal_mask();
-                assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
-
                 execv(cmdline[0], (char**) cmdline);
                 log_error_errno(errno, "Failed to execute %s: %m", cmdline[0]);
                 _exit(EXIT_FAILURE); /* Operational error */
index 45e2750..61ce1d0 100644 (file)
@@ -3539,10 +3539,10 @@ static int load_kexec_kernel(void) {
         if (arg_dry_run)
                 return 0;
 
-        pid = fork();
-        if (pid < 0)
-                return log_error_errno(errno, "Failed to fork: %m");
-        else if (pid == 0) {
+        r = safe_fork("(kexec)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
+        if (r < 0)
+                return log_error_errno(r, "Failed to fork: %m");
+        if (r == 0) {
 
                 const char* const args[] = {
                         KEXEC,
@@ -3552,15 +3552,11 @@ static int load_kexec_kernel(void) {
                         NULL };
 
                 /* Child */
-
-                (void) reset_all_signal_handlers();
-                (void) reset_signal_mask();
-                assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
-
                 execv(args[0], (char * const *) args);
                 _exit(EXIT_FAILURE);
-        } else
-                return wait_for_terminate_and_warn("kexec", pid, true);
+        }
+
+        return wait_for_terminate_and_warn("kexec", pid, true);
 }
 
 static int set_exit_code(uint8_t code) {
@@ -6123,15 +6119,11 @@ static int enable_sysv_units(const char *verb, char **args) {
                 if (!arg_quiet)
                         log_info("Executing: %s", l);
 
-                pid = fork();
-                if (pid < 0)
-                        return log_error_errno(errno, "Failed to fork: %m");
-                else if (pid == 0) {
+                j = safe_fork("(sysv)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
+                if (j < 0)
+                        return log_error_errno(j, "Failed to fork: %m");
+                if (j == 0) {
                         /* Child */
-
-                        (void) reset_all_signal_handlers();
-                        (void) reset_signal_mask();
-
                         execv(argv[0], (char**) argv);
                         log_error_errno(errno, "Failed to execute %s: %m", argv[0]);
                         _exit(EXIT_FAILURE);
@@ -7000,20 +6992,16 @@ static int run_editor(char **paths) {
 
         assert(paths);
 
-        pid = fork();
-        if (pid < 0)
-                return log_error_errno(errno, "Failed to fork: %m");
-
-        if (pid == 0) {
+        r = safe_fork("(editor)", FORK_RESET_SIGNALS|FORK_DEATHSIG, &pid);
+        if (r < 0)
+                return log_error_errno(r, "Failed to fork: %m");
+        if (r == 0) {
                 const char **args;
                 char *editor, **editor_args = NULL;
                 char **tmp_path, **original_path, *p;
                 unsigned n_editor_args = 0, i = 1;
                 size_t argc;
 
-                (void) reset_all_signal_handlers();
-                (void) reset_signal_mask();
-
                 argc = strv_length(paths)/2 + 1;
 
                 /* SYSTEMD_EDITOR takes precedence over EDITOR which takes precedence over VISUAL
index a38f917..2e262dd 100644 (file)
@@ -38,6 +38,7 @@
 #include "macro.h"
 #include "parse-util.h"
 #include "process-util.h"
+#include "signal-util.h"
 #include "stdio-util.h"
 #include "string-util.h"
 #include "terminal-util.h"
@@ -497,6 +498,28 @@ static void test_getpid_measure(void) {
         log_info("getpid_cached(): %llu/s\n", (unsigned long long) (MEASURE_ITERATIONS*USEC_PER_SEC/q));
 }
 
+static void test_safe_fork(void) {
+        siginfo_t status;
+        pid_t pid;
+        int r;
+
+        BLOCK_SIGNALS(SIGCHLD);
+
+        r = safe_fork("(test-child)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG|FORK_NULL_STDIO|FORK_REOPEN_LOG, &pid);
+        assert_se(r >= 0);
+
+        if (r == 0) {
+                /* child */
+                usleep(100 * USEC_PER_MSEC);
+
+                _exit(88);
+        }
+
+        assert_se(wait_for_terminate(pid, &status) >= 0);
+        assert_se(status.si_code == CLD_EXITED);
+        assert_se(status.si_status == 88);
+}
+
 int main(int argc, char *argv[]) {
 
         log_set_max_level(LOG_DEBUG);
@@ -523,6 +546,7 @@ int main(int argc, char *argv[]) {
         test_rename_process();
         test_getpid_cached();
         test_getpid_measure();
+        test_safe_fork();
 
         return 0;
 }
index 1553655..8edd891 100644 (file)
@@ -693,11 +693,13 @@ static int parse_argv(int argc, char *argv[]) {
  * If one of the tasks does handle a password, the remaining tasks
  * will be terminated.
  */
-static int ask_on_this_console(const char *tty, pid_t *pid, int argc, char *argv[]) {
+static int ask_on_this_console(const char *tty, pid_t *ret_pid, int argc, char *argv[]) {
         struct sigaction sig = {
                 .sa_handler = nop_signal_handler,
                 .sa_flags = SA_NOCLDSTOP | SA_RESTART,
         };
+        pid_t pid;
+        int r;
 
         assert_se(sigprocmask_many(SIG_UNBLOCK, NULL, SIGHUP, SIGCHLD, -1) >= 0);
 
@@ -707,18 +709,14 @@ static int ask_on_this_console(const char *tty, pid_t *pid, int argc, char *argv
         sig.sa_handler = SIG_DFL;
         assert_se(sigaction(SIGHUP, &sig, NULL) >= 0);
 
-        *pid = fork();
-        if (*pid < 0)
-                return log_error_errno(errno, "Failed to fork process: %m");
-
-        if (*pid == 0) {
+        r = safe_fork("(sd-passwd)", FORK_RESET_SIGNALS, &pid);
+        if (r < 0)
+                return log_error_errno(r, "Failed to fork process: %m");
+        if (r == 0) {
                 int ac;
 
                 assert_se(prctl(PR_SET_PDEATHSIG, SIGHUP) >= 0);
 
-                reset_signal_mask();
-                reset_all_signal_handlers();
-
                 for (ac = 0; ac < argc; ac++) {
                         if (streq(argv[ac], "--console")) {
                                 argv[ac] = strjoina("--console=", tty);
@@ -731,6 +729,8 @@ static int ask_on_this_console(const char *tty, pid_t *pid, int argc, char *argv
                 execv(SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH, argv);
                 _exit(EXIT_FAILURE);
         }
+
+        *ret_pid = pid;
         return 0;
 }
 
index 8f7c28f..8506e67 100644 (file)
@@ -774,10 +774,12 @@ int udev_event_spawn(struct udev_event *event,
                 }
         }
 
-        pid = fork();
-        switch(pid) {
-        case 0:
-        {
+        err = safe_fork("(spawn)", FORK_RESET_SIGNALS, &pid);
+        if (err < 0) {
+                log_error_errno(err, "fork of '%s' failed: %m", cmd);
+                goto out;
+        }
+        if (err == 0) {
                 char arg[UTIL_PATH_SIZE];
                 char *argv[128];
                 char program[UTIL_PATH_SIZE];
@@ -802,23 +804,18 @@ int udev_event_spawn(struct udev_event *event,
 
                 _exit(2);
         }
-        case -1:
-                log_error_errno(errno, "fork of '%s' failed: %m", cmd);
-                err = -1;
-                goto out;
-        default:
-                /* parent closed child's ends of pipes */
-                outpipe[WRITE_END] = safe_close(outpipe[WRITE_END]);
-                errpipe[WRITE_END] = safe_close(errpipe[WRITE_END]);
 
-                spawn_read(event,
-                           timeout_usec,
-                           cmd,
-                           outpipe[READ_END], errpipe[READ_END],
-                           result, ressize);
+        /* parent closed child's ends of pipes */
+        outpipe[WRITE_END] = safe_close(outpipe[WRITE_END]);
+        errpipe[WRITE_END] = safe_close(errpipe[WRITE_END]);
 
-                err = spawn_wait(event, timeout_usec, timeout_warn_usec, cmd, pid, accept_failure);
-        }
+        spawn_read(event,
+                   timeout_usec,
+                   cmd,
+                   outpipe[READ_END], errpipe[READ_END],
+                   result, ressize);
+
+        err = spawn_wait(event, timeout_usec, timeout_warn_usec, cmd, pid, accept_failure);
 
 out:
         if (outpipe[READ_END] >= 0)
index e19a163..fdc7c5f 100644 (file)
@@ -133,6 +133,7 @@ static int keyboard_load_and_wait(const char *vc, const char *map, const char *m
         const char *args[8];
         unsigned i = 0;
         pid_t pid;
+        int r;
 
         /* An empty map means kernel map */
         if (isempty(map))
@@ -152,14 +153,10 @@ static int keyboard_load_and_wait(const char *vc, const char *map, const char *m
         log_debug("Executing \"%s\"...",
                   strnull((cmd = strv_join((char**) args, " "))));
 
-        pid = fork();
-        if (pid < 0)
-                return log_error_errno(errno, "Failed to fork: %m");
-        else if (pid == 0) {
-
-                (void) reset_all_signal_handlers();
-                (void) reset_signal_mask();
-
+        r = safe_fork("(loadkeys)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS, &pid);
+        if (r < 0)
+                return log_error_errno(r, "Failed to fork: %m");
+        if (r == 0) {
                 execv(args[0], (char **) args);
                 _exit(EXIT_FAILURE);
         }
@@ -172,6 +169,7 @@ static int font_load_and_wait(const char *vc, const char *font, const char *map,
         const char *args[9];
         unsigned i = 0;
         pid_t pid;
+        int r;
 
         /* Any part can be set independently */
         if (isempty(font) && isempty(map) && isempty(unimap))
@@ -195,14 +193,10 @@ static int font_load_and_wait(const char *vc, const char *font, const char *map,
         log_debug("Executing \"%s\"...",
                   strnull((cmd = strv_join((char**) args, " "))));
 
-        pid = fork();
-        if (pid < 0)
-                return log_error_errno(errno, "Failed to fork: %m");
-        else if (pid == 0) {
-
-                (void) reset_all_signal_handlers();
-                (void) reset_signal_mask();
-
+        r = safe_fork("(setfont)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS, &pid);
+        if (r < 0)
+                return log_error_errno(r, "Failed to fork: %m");
+        if (r == 0) {
                 execv(args[0], (char **) args);
                 _exit(EXIT_FAILURE);
         }