From: Daan De Meyer Date: Mon, 16 Feb 2026 12:14:58 +0000 (+0100) Subject: sd-bus: Don't fork unnecessarily to connect to container X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6119252f5a66fa881fe01b8300d468023f294261;p=thirdparty%2Fsystemd.git sd-bus: Don't fork unnecessarily to connect to container Let's check if we're already in the right namespaces and call connect() directly if that's the case. This can easily happen when the machine is specified as .host or so. --- diff --git a/src/basic/namespace-util.c b/src/basic/namespace-util.c index 93b9ed1f388..f156bfdf249 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 32e64fa9e68..cd2ea786927 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 66cb0ab0c7a..475e855462d 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); }