diff --git a/src/basic/namespace-util.c b/src/basic/namespace-util.c index 93b9ed1f38..f156bfdf24 100644 --- a/src/basic/namespace-util.c +++ b/src/basic/namespace-util.c @@ -373,6 +373,42 @@ int is_our_namespace(int fd, NamespaceType type) { return fd_inode_same(fd, our_ns); } +int are_our_namespaces(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd) { + int r; + + if (pidns_fd >= 0) { + r = is_our_namespace(pidns_fd, NAMESPACE_PID); + if (r <= 0) + return r; + } + + if (mntns_fd >= 0) { + r = is_our_namespace(mntns_fd, NAMESPACE_MOUNT); + if (r <= 0) + return r; + } + + if (netns_fd >= 0) { + r = is_our_namespace(netns_fd, NAMESPACE_NET); + if (r <= 0) + return r; + } + + if (userns_fd >= 0) { + r = is_our_namespace(userns_fd, NAMESPACE_USER); + if (r <= 0) + return r; + } + + if (root_fd >= 0) { + r = dir_fd_is_root(root_fd); + if (r <= 0) + return r; + } + + return true; +} + int namespace_is_init(NamespaceType type) { int r; diff --git a/src/basic/namespace-util.h b/src/basic/namespace-util.h index 32e64fa9e6..cd2ea78692 100644 --- a/src/basic/namespace-util.h +++ b/src/basic/namespace-util.h @@ -50,6 +50,7 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int int fd_is_namespace(int fd, NamespaceType type); int is_our_namespace(int fd, NamespaceType type); +int are_our_namespaces(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd); int namespace_is_init(NamespaceType type); diff --git a/src/libsystemd/sd-bus/bus-container.c b/src/libsystemd/sd-bus/bus-container.c index 66cb0ab0c7..475e855462 100644 --- a/src/libsystemd/sd-bus/bus-container.c +++ b/src/libsystemd/sd-bus/bus-container.c @@ -6,6 +6,7 @@ #include "bus-internal.h" #include "bus-socket.h" #include "env-file.h" +#include "errno-util.h" #include "fd-util.h" #include "format-util.h" #include "hostname-util.h" @@ -14,7 +15,6 @@ #include "parse-util.h" #include "path-lookup.h" #include "path-util.h" -#include "pidref.h" #include "process-util.h" #include "string-util.h" @@ -67,12 +67,37 @@ int container_get_leader(RuntimeScope scope, const char *machine, pid_t *ret) { return 0; } +static int bus_container_connect_namespace(sd_bus *b, int pidnsfd, int mntnsfd, int usernsfd, int rootfd) { + _cleanup_close_pair_ int errno_pipe_fd[2] = EBADF_PAIR; + int r; + + if (pipe2(errno_pipe_fd, O_CLOEXEC) < 0) + return log_debug_errno(errno, "Failed to create pipe: %m"); + + r = namespace_fork("(sd-buscntrns)", "(sd-buscntr)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGKILL|FORK_WAIT, + pidnsfd, mntnsfd, /* netns_fd= */ -EBADF, usernsfd, rootfd, /* ret= */ NULL); + if (r == -EPROTO) { + errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]); + + int k = read_errno(errno_pipe_fd[0]); + if (k < 0 && k != -EIO) + return k; + } + if (r < 0) + return log_debug_errno(r, "Failed to create namespace for (sd-buscntr): %m"); + if (r == 0) { + errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]); + + r = RET_NERRNO(connect(b->input_fd, &b->sockaddr.sa, b->sockaddr_size)); + report_errno_and_exit(errno_pipe_fd[1], r); + } + + return 0; +} + int bus_container_connect_socket(sd_bus *b) { _cleanup_close_ int pidnsfd = -EBADF, mntnsfd = -EBADF, usernsfd = -EBADF, rootfd = -EBADF; - _cleanup_(pidref_done) PidRef child = PIDREF_NULL; - _cleanup_close_pair_ int pair[2] = EBADF_PAIR; - int r, error_buf = 0; - ssize_t n; + int r; assert(b); assert(b->input_fd < 0); @@ -106,56 +131,17 @@ int bus_container_connect_socket(sd_bus *b) { bus_socket_setup(b); - if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, pair) < 0) - return log_debug_errno(errno, "Failed to create a socket pair: %m"); - - r = namespace_fork("(sd-buscntrns)", "(sd-buscntr)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGKILL, - pidnsfd, mntnsfd, -1, usernsfd, rootfd, &child); + r = are_our_namespaces(pidnsfd, mntnsfd, /* netns_fd= */ -EBADF, usernsfd, rootfd); if (r < 0) - return log_debug_errno(r, "Failed to create namespace for (sd-buscntr): %m"); - if (r == 0) { - pair[0] = safe_close(pair[0]); - - r = connect(b->input_fd, &b->sockaddr.sa, b->sockaddr_size); - if (r < 0) { - /* Try to send error up */ - error_buf = errno; - (void) write(pair[1], &error_buf, sizeof(error_buf)); - _exit(EXIT_FAILURE); - } - - _exit(EXIT_SUCCESS); - } - - pair[1] = safe_close(pair[1]); - - r = pidref_wait_for_terminate_and_check("(sd-buscntrns)", &child, 0); + return log_debug_errno(r, "Failed to check if already in PID "PID_FMT" namespaces: %m", b->nspid); + if (r > 0) + r = RET_NERRNO(connect(b->input_fd, &b->sockaddr.sa, b->sockaddr_size)); + else + r = bus_container_connect_namespace(b, pidnsfd, mntnsfd, usernsfd, rootfd); + if (r == -EINPROGRESS) + return 1; if (r < 0) - return r; - bool nonzero_exit_status = r != EXIT_SUCCESS; - - n = read(pair[0], &error_buf, sizeof(error_buf)); - if (n < 0) - return log_debug_errno(errno, "Failed to read error status from (sd-buscntr): %m"); - - if (n > 0) { - if (n != sizeof(error_buf)) - return log_debug_errno(SYNTHETIC_ERRNO(EIO), - "Read error status of unexpected length %zd from (sd-buscntr).", n); - - if (error_buf < 0) - return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), - "Got unexpected error status from (sd-buscntr)."); - - if (error_buf == EINPROGRESS) - return 1; - - if (error_buf > 0) - return log_debug_errno(error_buf, "(sd-buscntr) failed to connect to D-Bus socket: %m"); - } - - if (nonzero_exit_status) - return -EPROTO; + return log_debug_errno(r, "Failed to connect to D-Bus socket in namespaces of PID "PID_FMT": %m", b->nspid); return bus_socket_start_auth(b); }