From: Lennart Poettering Date: Mon, 12 Nov 2018 22:37:13 +0000 (+0100) Subject: core: add namespace_fork() helper, that forks, joins a set of namespaces and forks... X-Git-Tag: archive/raspbian/239-13+rpi1^2~23 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=33a0da745ecd5f8ed1a59a7487dd372f7c8063d7;p=systemd.git core: add namespace_fork() helper, that forks, joins a set of namespaces and forks again This helper is useful to ensure pidns/userns joining is properly executed (as that requires a fork after the setns()). This is particularly important when it comes to /proc/self/ access or SCM_CREDENTIALS, but is generally the safer mode of operation. (cherry picked from commit 27096982798e4f4d1498f9ce75c317b8d3376125) Gbp-Pq: Name core-add-namespace_fork-helper-that-forks-joins-a-set-of-.patch --- diff --git a/src/basic/process-util.c b/src/basic/process-util.c index 0a4f917c..2e64a21e 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -1390,6 +1390,60 @@ int safe_fork_full( return 0; } +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) { + + int r; + + /* This is much like safe_fork(), but forks twice, and joins the specified namespaces in the middle + * 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); + if (r < 0) + return r; + if (r == 0) { + pid_t pid; + + /* Child */ + + r = namespace_enter(pidns_fd, mntns_fd, netns_fd, userns_fd, root_fd); + if (r < 0) { + log_full_errno(FLAGS_SET(flags, FORK_LOG) ? LOG_ERR : LOG_DEBUG, r, "Failed to join namespace: %m"); + _exit(EXIT_FAILURE); + } + + /* 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); + if (r < 0) + _exit(EXIT_FAILURE); + if (r == 0) { + /* Child */ + if (ret_pid) + *ret_pid = pid; + return 0; + } + + r = wait_for_terminate_and_check(inner_name, pid, FLAGS_SET(flags, FORK_LOG) ? WAIT_LOG : 0); + if (r < 0) + _exit(EXIT_FAILURE); + + _exit(r); + } + + return 1; +} + int fork_agent(const char *name, const int except[], size_t n_except, pid_t *ret_pid, const char *path, ...) { bool stdout_is_tty, stderr_is_tty; size_t n, i; diff --git a/src/basic/process-util.h b/src/basic/process-util.h index a5bb072b..2cd96c09 100644 --- a/src/basic/process-util.h +++ b/src/basic/process-util.h @@ -166,6 +166,8 @@ static inline int safe_fork(const char *name, ForkFlags flags, pid_t *ret_pid) { return safe_fork_full(name, 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); + int fork_agent(const char *name, const int except[], size_t n_except, pid_t *pid, const char *path, ...); int set_oom_score_adjust(int value);