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.
This commit is contained in:
parent
8724defeae
commit
2709698279
|
@ -1409,6 +1409,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;
|
||||
|
|
|
@ -159,6 +159,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, ...) _sentinel_;
|
||||
|
||||
int set_oom_score_adjust(int value);
|
||||
|
|
Loading…
Reference in a new issue