And make safe_fork_full() takes fds to be assigned to stdio.
int safe_fork_full(
const char *name,
+ const int stdio_fds[3],
const int except_fds[],
size_t n_except_fds,
ForkFlags flags,
}
}
+ if (flags & FORK_REARRANGE_STDIO) {
+ if (stdio_fds) {
+ r = rearrange_stdio(stdio_fds[0], stdio_fds[1], stdio_fds[2]);
+ if (r < 0) {
+ log_full_errno(prio, r, "Failed to rearrange stdio fds: %m");
+ _exit(EXIT_FAILURE);
+ }
+ } else {
+ r = make_null_stdio();
+ if (r < 0) {
+ log_full_errno(prio, r, "Failed to connect stdin/stdout to /dev/null: %m");
+ _exit(EXIT_FAILURE);
+ }
+ }
+ } else if (flags & FORK_STDOUT_TO_STDERR) {
+ if (dup2(STDERR_FILENO, STDOUT_FILENO) < 0) {
+ log_full_errno(prio, errno, "Failed to connect stdout to stderr: %m");
+ _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();
log_set_open_when_needed(false);
}
- if (flags & FORK_NULL_STDIO) {
- r = make_null_stdio();
- if (r < 0) {
- log_full_errno(prio, r, "Failed to connect stdin/stdout to /dev/null: %m");
- _exit(EXIT_FAILURE);
- }
-
- } else if (flags & FORK_STDOUT_TO_STDERR) {
- if (dup2(STDERR_FILENO, STDOUT_FILENO) < 0) {
- log_full_errno(prio, errno, "Failed to connect stdout to stderr: %m");
- _exit(EXIT_FAILURE);
- }
- }
-
if (flags & FORK_RLIMIT_NOFILE_SAFE) {
r = rlimit_nofile_safe();
if (r < 0) {
* process. This ensures that we are fully a member of the destination namespace, with pidns an all, so that
* /proc/self/fd works correctly. */
- r = safe_fork_full(outer_name, except_fds, n_except_fds, (flags|FORK_DEATHSIG) & ~(FORK_REOPEN_LOG|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE), ret_pid);
+ r = safe_fork_full(outer_name,
+ NULL,
+ except_fds, n_except_fds,
+ (flags|FORK_DEATHSIG) & ~(FORK_REOPEN_LOG|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE), ret_pid);
if (r < 0)
return r;
if (r == 0) {
}
/* We mask a few flags here that either make no sense for the grandchild, or that we don't have to do again */
- r = safe_fork_full(inner_name, except_fds, n_except_fds, flags & ~(FORK_WAIT|FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_NULL_STDIO), &pid);
+ r = safe_fork_full(inner_name,
+ NULL,
+ except_fds, n_except_fds,
+ flags & ~(FORK_WAIT|FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_REARRANGE_STDIO), &pid);
if (r < 0)
_exit(EXIT_FAILURE);
if (r == 0) {
FORK_CLOSE_ALL_FDS = 1 << 1, /* Close all open file descriptors in the child, except for 0,1,2 */
FORK_DEATHSIG = 1 << 2, /* Set PR_DEATHSIG in the child to SIGTERM */
FORK_DEATHSIG_SIGINT = 1 << 3, /* Set PR_DEATHSIG in the child to SIGINT */
- FORK_NULL_STDIO = 1 << 4, /* Connect 0,1,2 to /dev/null */
+ FORK_REARRANGE_STDIO = 1 << 4, /* Connect 0,1,2 to specified fds or /dev/null */
FORK_REOPEN_LOG = 1 << 5, /* Reopen log connection */
FORK_LOG = 1 << 6, /* Log above LOG_DEBUG log level about failures */
FORK_WAIT = 1 << 7, /* Wait until child exited */
FORK_CLOEXEC_OFF = 1 << 15, /* In the child: turn off O_CLOEXEC on all fds in except_fds[] */
} ForkFlags;
-int safe_fork_full(const char *name, const int except_fds[], size_t n_except_fds, ForkFlags flags, pid_t *ret_pid);
+int safe_fork_full(
+ const char *name,
+ const int stdio_fds[3],
+ 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);
+ return safe_fork_full(name, NULL, NULL, 0, flags, ret_pid);
}
int namespace_fork(const char *outer_name, const char *inner_name, const int except_fds[], size_t n_except_fds, ForkFlags flags, int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd, pid_t *ret_pid);
return -errno;
r = safe_fork_full("(sd-homework)",
+ NULL,
(int[]) { stdin_fd, stdout_fd }, 2,
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG|FORK_LOG|FORK_REOPEN_LOG, &pid);
if (r < 0)
if (r < 0)
return -errno;
- r = safe_fork_full("(sd-busexec)", s+1, 1, FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_RLIMIT_NOFILE_SAFE, &b->busexec_pid);
+ r = safe_fork_full("(sd-busexec)",
+ NULL,
+ s+1, 1,
+ FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_RLIMIT_NOFILE_SAFE, &b->busexec_pid);
if (r < 0) {
safe_close_pair(s);
return r;
assert(w->child == 0);
assert(!w->child_event_source);
- r = safe_fork("(sd-bright)", FORK_DEATHSIG|FORK_NULL_STDIO|FORK_CLOSE_ALL_FDS|FORK_LOG|FORK_REOPEN_LOG, &w->child);
+ r = safe_fork("(sd-bright)", FORK_DEATHSIG|FORK_REARRANGE_STDIO|FORK_CLOSE_ALL_FDS|FORK_LOG|FORK_REOPEN_LOG, &w->child);
if (r < 0)
return r;
if (r == 0) {
fd_tls = fd[1];
}
- r = safe_fork_full("(test-resolved-stream-tls-openssl)", (int[]) { fd_server, fd_tls }, 2,
- FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG|FORK_LOG|FORK_REOPEN_LOG, &openssl_pid);
+ r = safe_fork_full("(test-resolved-stream-tls-openssl)",
+ NULL,
+ (int[]) { fd_server, fd_tls }, 2,
+ FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG|FORK_LOG|FORK_REOPEN_LOG, &openssl_pid);
assert_se(r >= 0);
if (r == 0) {
/* Child */
r = safe_fork_full(
"(fsck)",
+ NULL,
&node_fd, 1, /* Leave the node fd open */
- FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_RLIMIT_NOFILE_SAFE|FORK_DEATHSIG|FORK_NULL_STDIO|FORK_CLOEXEC_OFF,
+ FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_RLIMIT_NOFILE_SAFE|FORK_DEATHSIG|FORK_REARRANGE_STDIO|FORK_CLOEXEC_OFF,
&pid);
if (r < 0)
return log_debug_errno(r, "Failed to fork off fsck: %m");
* system call or interacting with the system in any way, besides reading from
* the file descriptor and writing into these four pipes. */
r = safe_fork_full("(sd-parse-elf)",
+ NULL,
(int[]){ fd, error_pipe[1], return_pipe[1], json_pipe[1] },
4,
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_NEW_MOUNTNS|FORK_MOUNTNS_SLAVE|FORK_NEW_USERNS|FORK_WAIT|FORK_REOPEN_LOG,
/* Spawns a temporary TTY agent, making sure it goes away when we go away */
r = safe_fork_full(name,
+ NULL,
except,
n_except,
FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG|FORK_RLIMIT_NOFILE_SAFE,
} else
args[1] = desc;
- r = safe_fork("(man)", FORK_RESET_SIGNALS|FORK_DEATHSIG|(null_stdio ? FORK_NULL_STDIO : 0)|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid);
+ r = safe_fork("(man)", FORK_RESET_SIGNALS|FORK_DEATHSIG|(null_stdio ? FORK_REARRANGE_STDIO : 0)|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid);
if (r < 0)
return r;
if (r == 0) {
/* Due to the possibility of a remount operation hanging, we fork a child process and set a
* timeout. If the timeout lapses, the assumption is that the particular remount failed. */
- r = safe_fork_full("(sd-remount)", pfd, ELEMENTSOF(pfd), FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_LOG|FORK_REOPEN_LOG, &pid);
+ r = safe_fork_full("(sd-remount)",
+ NULL,
+ pfd, ELEMENTSOF(pfd),
+ FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_LOG|FORK_REOPEN_LOG, &pid);
if (r < 0)
return r;
if (r == 0) {
/* Due to the possibility of a umount operation hanging, we fork a child process and set a
* timeout. If the timeout lapses, the assumption is that the particular umount failed. */
- r = safe_fork_full("(sd-umount)", pfd, ELEMENTSOF(pfd), FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_LOG|FORK_REOPEN_LOG, &pid);
+ r = safe_fork_full("(sd-umount)",
+ NULL,
+ pfd, ELEMENTSOF(pfd),
+ FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_LOG|FORK_REOPEN_LOG, &pid);
if (r < 0)
return r;
if (r == 0) {
BLOCK_SIGNALS(SIGCHLD);
- r = safe_fork("(test-child)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG|FORK_NULL_STDIO|FORK_REOPEN_LOG, &pid);
+ r = safe_fork("(test-child)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG|FORK_REARRANGE_STDIO|FORK_REOPEN_LOG, &pid);
assert_se(r >= 0);
if (r == 0) {