]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-bus: Don't fork unnecessarily to connect to container 40698/head
authorDaan De Meyer <daan@amutable.com>
Mon, 16 Feb 2026 12:14:58 +0000 (13:14 +0100)
committerDaan De Meyer <daan@amutable.com>
Tue, 17 Feb 2026 16:52:20 +0000 (17:52 +0100)
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.

src/basic/namespace-util.c
src/basic/namespace-util.h
src/libsystemd/sd-bus/bus-container.c

index 93b9ed1f3888681d0a359041d1b1c0153e18936a..f156bfdf2499401e96d258f72fadff95d0911aa9 100644 (file)
@@ -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;
 
index 32e64fa9e6801490bc7dbcbc0136018b2811b375..cd2ea786927c3cc1ca30430570025fa626a8cf04 100644 (file)
@@ -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);
 
index 66cb0ab0c7a1c1d26644ec1135d0a65fe21fbc6d..475e855462d407d1603d0c31170af38f0a3db06f 100644 (file)
@@ -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);
 }