From f6bcd125dbf89cfb61516d29b5d45f2e3edce468 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Mon, 16 Feb 2026 22:12:34 +0100 Subject: [PATCH 1/6] nspawn: Join network namespace with setns() We don't have /proc mounted which means namespace_enter() won't work on older kernels, so use setns() instead. --- src/nspawn/nspawn.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 1c0ab6e712..296b12bb90 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -4368,15 +4368,8 @@ static int outer_child( /* The inner child has all namespaces that are requested, so that we all are owned by the * user if user namespaces are turned on. */ - if (arg_network_namespace_path) { - r = namespace_enter(/* pidns_fd= */ -EBADF, - /* mntns_fd= */ -EBADF, - netns_fd, - /* userns_fd= */ -EBADF, - /* root_fd= */ -EBADF); - if (r < 0) - return log_error_errno(r, "Failed to join network namespace: %m"); - } + if (arg_network_namespace_path && setns(netns_fd, CLONE_NEWNET) < 0) + return log_error_errno(errno, "Failed to join network namespace: %m"); if (arg_userns_mode == USER_NAMESPACE_MANAGED) { /* In managed usernamespace operation, sysfs + procfs are special, we'll have to From 5045a28ae11a0fbe720864c8bcae4bb79b2a57aa Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Tue, 17 Feb 2026 15:38:01 +0100 Subject: [PATCH 2/6] coredump: Use error log level in coredump_send_to_container() --- src/coredump/coredump-send.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/coredump/coredump-send.c b/src/coredump/coredump-send.c index 12c781d05a..0174be69a4 100644 --- a/src/coredump/coredump-send.c +++ b/src/coredump/coredump-send.c @@ -241,7 +241,7 @@ int coredump_send_to_container(CoredumpContext *context) { _cleanup_(pidref_done) PidRef leader_pid = PIDREF_NULL; r = namespace_get_leader(&context->pidref, NAMESPACE_PID, &leader_pid); if (r < 0) - return log_debug_errno(r, "Failed to get namespace leader: %m"); + return log_error_errno(r, "Failed to get namespace leader: %m"); r = can_forward_coredump(&context->pidref, &leader_pid); if (r <= 0) @@ -258,33 +258,33 @@ int coredump_send_to_container(CoredumpContext *context) { r = RET_NERRNO(socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, pair)); if (r < 0) - return log_debug_errno(r, "Failed to create socket pair: %m"); + return log_error_errno(r, "Failed to create socket pair: %m"); r = setsockopt_int(pair[1], SOL_SOCKET, SO_PASSCRED, true); if (r < 0) - return log_debug_errno(r, "Failed to set SO_PASSCRED: %m"); + return log_error_errno(r, "Failed to set SO_PASSCRED: %m"); r = pidref_namespace_open(&leader_pid, &pidnsfd, &mntnsfd, &netnsfd, &usernsfd, &rootfd); if (r < 0) - return log_debug_errno(r, "Failed to open namespaces of PID " PID_FMT ": %m", leader_pid.pid); + return log_error_errno(r, "Failed to open namespaces of PID " PID_FMT ": %m", leader_pid.pid); r = namespace_fork("(sd-coredumpns)", "(sd-coredump)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM, pidnsfd, mntnsfd, netnsfd, usernsfd, rootfd, &child); if (r < 0) - return log_debug_errno(r, "Failed to fork into namespaces of PID " PID_FMT ": %m", leader_pid.pid); + return log_error_errno(r, "Failed to fork into namespaces of PID " PID_FMT ": %m", leader_pid.pid); if (r == 0) { pair[0] = safe_close(pair[0]); r = access_nofollow("/run/systemd/coredump", W_OK); if (r < 0) { - log_debug_errno(r, "Cannot find coredump socket, exiting: %m"); + log_error_errno(r, "Cannot find coredump socket, exiting: %m"); _exit(EXIT_FAILURE); } r = receive_ucred(pair[1], &ucred); if (r < 0) { - log_debug_errno(r, "Failed to receive ucred and fd: %m"); + log_error_errno(r, "Failed to receive ucred and fd: %m"); _exit(EXIT_FAILURE); } @@ -309,7 +309,7 @@ int coredump_send_to_container(CoredumpContext *context) { r = coredump_send(context); if (r < 0) { - log_debug_errno(r, "Failed to send iovec to coredump socket: %m"); + log_error_errno(r, "Failed to send iovec to coredump socket: %m"); _exit(EXIT_FAILURE); } @@ -324,13 +324,13 @@ int coredump_send_to_container(CoredumpContext *context) { * container. The kernel will perform the translation for us. */ r = send_ucred(pair[0], &ucred); if (r < 0) - return log_debug_errno(r, "Failed to send metadata to container: %m"); + return log_error_errno(r, "Failed to send metadata to container: %m"); - r = pidref_wait_for_terminate_and_check("(sd-coredumpns)", &child, 0); + r = pidref_wait_for_terminate_and_check("(sd-coredumpns)", &child, WAIT_LOG); if (r < 0) - return log_debug_errno(r, "Failed to wait for child to terminate: %m"); + return r; if (r != EXIT_SUCCESS) - return log_debug_errno(SYNTHETIC_ERRNO(EPROTO), "Failed to process coredump in container."); + return -EPROTO; return 1; /* sent */ } From 3791710f445fdebf661edc7889432770bee09f61 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Tue, 17 Feb 2026 15:35:30 +0100 Subject: [PATCH 3/6] namespace-util: Add extra debug logging --- src/basic/namespace-util.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/basic/namespace-util.c b/src/basic/namespace-util.c index 6a73eed913..4ba84a27ea 100644 --- a/src/basic/namespace-util.c +++ b/src/basic/namespace-util.c @@ -68,6 +68,11 @@ static int pidref_namespace_open_by_type_internal(const PidRef *pidref, Namespac if (pidref->fd >= 0) { r = pidfd_get_namespace(pidref->fd, namespace_info[type].pidfd_get_ns_ioctl_cmd); + if (r == -ENOPKG) + return log_debug_errno( + r, + "Cannot open %s namespace for PID "PID_FMT" as the namespace type is not supported by the kernel", + namespace_info[type].proc_name, pidref->pid); if (!ERRNO_IS_NEG_NOT_SUPPORTED(r)) return r; } @@ -83,10 +88,17 @@ static int pidref_namespace_open_by_type_internal(const PidRef *pidref, Namespac if (nsfd == -ENOENT) { r = proc_mounted(); if (r == 0) - return -ENOSYS; /* /proc/ is not available or not set up properly, we're most likely - in some chroot environment. */ + /* /proc/ is not available or not set up properly, we're most likely in some chroot environment. */ + return log_debug_errno( + SYNTHETIC_ERRNO(ENOSYS), + "Cannot open %s namespace for PID "PID_FMT" as /proc is not mounted", + namespace_info[type].proc_name, pidref->pid); if (r > 0) - return -ENOPKG; /* If /proc/ is definitely around then this means the namespace type is not supported */ + /* If /proc/ is definitely around then this means the namespace type is not supported */ + return log_debug_errno( + SYNTHETIC_ERRNO(ENOPKG), + "Cannot open %s namespace for PID "PID_FMT" via /proc as the namespace type is not supported by the kernel", + namespace_info[type].proc_name, pidref->pid); /* can't determine? then propagate original error */ } From 8d1183539711f653ffe569cdbc15efddb515f8c4 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Tue, 17 Feb 2026 15:36:00 +0100 Subject: [PATCH 4/6] namespace-util: Do is_our_namespace() checks first in namespace_enter() These checks may rely on /proc on older kernels which we could lose access to by joining namespaces so let's do all the checks first and then join namespaces. --- src/basic/namespace-util.c | 72 +++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/src/basic/namespace-util.c b/src/basic/namespace-util.c index 4ba84a27ea..93b9ed1f38 100644 --- a/src/basic/namespace-util.c +++ b/src/basic/namespace-util.c @@ -228,33 +228,39 @@ int namespace_open( return pidref_namespace_open(&pidref, ret_pidns_fd, ret_mntns_fd, ret_netns_fd, ret_userns_fd, ret_root_fd); } -static int namespace_enter_one_idempotent(int nsfd, NamespaceType type) { - int r; - - /* Join a namespace, but only if we're not part of it already. This is important if we don't necessarily - * own the namespace in question, as kernel would unconditionally return EPERM otherwise. */ - - assert(nsfd >= 0); - assert(type >= 0 && type < _NAMESPACE_TYPE_MAX); - - r = is_our_namespace(nsfd, type); - if (r < 0) - return r; - if (r > 0) - return 0; - - if (setns(nsfd, namespace_info[type].clone_flag) < 0) - return -errno; - - return 1; -} - int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd) { int r; /* Block dlopen() now, to avoid us inadvertently loading shared library from another namespace */ block_dlopen(); + /* Join namespaces, but only if we're not part of them already. This is important if we don't + * necessarily own the namespace in question, as kernel would unconditionally return EPERM otherwise. */ + + if (pidns_fd >= 0) { + r = is_our_namespace(pidns_fd, NAMESPACE_PID); + if (r < 0) + return r; + if (r > 0) + pidns_fd = -EBADF; + } + + if (mntns_fd >= 0) { + r = is_our_namespace(mntns_fd, NAMESPACE_MOUNT); + if (r < 0) + return r; + if (r > 0) + mntns_fd = -EBADF; + } + + if (netns_fd >= 0) { + r = is_our_namespace(netns_fd, NAMESPACE_NET); + if (r < 0) + return r; + if (r > 0) + netns_fd = -EBADF; + } + if (userns_fd >= 0) { /* Can't setns to your own userns, since then you could escalate from non-root to root in * your own namespace, so check if namespaces are equal before attempting to enter. */ @@ -287,23 +293,17 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int return -errno; } - if (pidns_fd >= 0) { - r = namespace_enter_one_idempotent(pidns_fd, NAMESPACE_PID); - if (r < 0) - return r; - } + if (pidns_fd >= 0) + if (setns(pidns_fd, CLONE_NEWPID) < 0) + return -errno; - if (mntns_fd >= 0) { - r = namespace_enter_one_idempotent(mntns_fd, NAMESPACE_MOUNT); - if (r < 0) - return r; - } + if (mntns_fd >= 0) + if (setns(mntns_fd, CLONE_NEWNS) < 0) + return -errno; - if (netns_fd >= 0) { - r = namespace_enter_one_idempotent(netns_fd, NAMESPACE_NET); - if (r < 0) - return r; - } + if (netns_fd >= 0) + if (setns(netns_fd, CLONE_NEWNET) < 0) + return -errno; if (userns_fd >= 0 && have_cap_sys_admin) if (setns(userns_fd, CLONE_NEWUSER) < 0) From a12c5bf4f5a01eb7cc62cf987e5f4451c07b4fd0 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Mon, 16 Feb 2026 11:27:21 +0100 Subject: [PATCH 5/6] sd-bus: Make sure we can connect to user machines as well Don't unconditionally look into /run/systemd/machines. If we're a connected to a session bus, look at the machines for the current user instead. --- src/basic/process-util.c | 44 +------------------- src/basic/process-util.h | 2 - src/libsystemd/sd-bus/bus-container.c | 58 ++++++++++++++++++++++++++- src/libsystemd/sd-bus/bus-container.h | 2 + src/libsystemd/sd-id128/id128-util.c | 4 +- 5 files changed, 63 insertions(+), 47 deletions(-) diff --git a/src/basic/process-util.c b/src/basic/process-util.c index 9d77e96b1a..3f2c2d3b23 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -25,13 +25,11 @@ #include "cgroup-util.h" #include "dirent-util.h" #include "dlfcn-util.h" -#include "env-file.h" #include "errno-util.h" #include "escape.h" #include "fd-util.h" #include "fileio.h" #include "fs-util.h" -#include "hostname-util.h" #include "io-util.h" #include "iovec-util.h" #include "locale-util.h" @@ -53,6 +51,7 @@ #include "stdio-util.h" #include "string-table.h" #include "string-util.h" +#include "strv.h" #include "time-util.h" #include "user-util.h" @@ -349,47 +348,6 @@ int pidref_get_cmdline_strv(const PidRef *pid, ProcessCmdlineFlags flags, char * return 0; } -int container_get_leader(const char *machine, pid_t *pid) { - _cleanup_free_ char *s = NULL, *class = NULL; - const char *p; - pid_t leader; - int r; - - assert(machine); - assert(pid); - - if (streq(machine, ".host")) { - *pid = 1; - return 0; - } - - if (!hostname_is_valid(machine, 0)) - return -EINVAL; - - p = strjoina("/run/systemd/machines/", machine); - r = parse_env_file(NULL, p, - "LEADER", &s, - "CLASS", &class); - if (r == -ENOENT) - return -EHOSTDOWN; - if (r < 0) - return r; - if (!s) - return -EIO; - - if (!streq_ptr(class, "container")) - return -EIO; - - r = parse_pid(s, &leader); - if (r < 0) - return r; - if (leader <= 1) - return -EIO; - - *pid = leader; - return 0; -} - int pid_is_kernel_thread(pid_t pid) { int r; diff --git a/src/basic/process-util.h b/src/basic/process-util.h index b3f6120053..9d16055d5e 100644 --- a/src/basic/process-util.h +++ b/src/basic/process-util.h @@ -54,8 +54,6 @@ int pid_get_start_time(pid_t pid, usec_t *ret); int pidref_get_start_time(const PidRef *pid, usec_t *ret); int get_process_umask(pid_t pid, mode_t *ret); -int container_get_leader(const char *machine, pid_t *pid); - static inline bool SIGINFO_CODE_IS_DEAD(int code) { return IN_SET(code, CLD_EXITED, CLD_KILLED, CLD_DUMPED); } diff --git a/src/libsystemd/sd-bus/bus-container.c b/src/libsystemd/sd-bus/bus-container.c index 3bbcbb81c6..66cb0ab0c7 100644 --- a/src/libsystemd/sd-bus/bus-container.c +++ b/src/libsystemd/sd-bus/bus-container.c @@ -5,14 +5,68 @@ #include "bus-container.h" #include "bus-internal.h" #include "bus-socket.h" +#include "env-file.h" #include "fd-util.h" #include "format-util.h" +#include "hostname-util.h" #include "log.h" #include "namespace-util.h" +#include "parse-util.h" +#include "path-lookup.h" +#include "path-util.h" #include "pidref.h" #include "process-util.h" #include "string-util.h" +int container_get_leader(RuntimeScope scope, const char *machine, pid_t *ret) { + _cleanup_free_ char *p = NULL, *s = NULL, *class = NULL; + pid_t leader; + int r; + + assert(machine); + assert(ret); + + if (streq(machine, ".host")) { + if (scope == RUNTIME_SCOPE_USER) + return -EHOSTDOWN; + + *ret = 1; + return 0; + } + + if (!hostname_is_valid(machine, 0)) + return -EINVAL; + + r = runtime_directory_generic(scope, "systemd/machines", &p); + if (r < 0) + return r; + + if (!path_extend(&p, machine)) + return -ENOMEM; + + r = parse_env_file(NULL, p, + "LEADER", &s, + "CLASS", &class); + if (r == -ENOENT) + return -EHOSTDOWN; + if (r < 0) + return r; + if (!s) + return -ESRCH; + + if (!streq_ptr(class, "container")) + return -EMEDIUMTYPE; + + r = parse_pid(s, &leader); + if (r < 0) + return r; + if (leader <= 1) + return -EBADMSG; + + *ret = leader; + 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; @@ -29,7 +83,9 @@ int bus_container_connect_socket(sd_bus *b) { log_debug("sd-bus: connecting bus%s%s to machine %s...", b->description ? " " : "", strempty(b->description), b->machine); - r = container_get_leader(b->machine, &b->nspid); + r = container_get_leader(RUNTIME_SCOPE_USER, b->machine, &b->nspid); + if (IN_SET(r, -EHOSTDOWN, -ENXIO)) + r = container_get_leader(RUNTIME_SCOPE_SYSTEM, b->machine, &b->nspid); if (r < 0) return r; } else diff --git a/src/libsystemd/sd-bus/bus-container.h b/src/libsystemd/sd-bus/bus-container.h index 2e933bd9a7..f6ede2ecd6 100644 --- a/src/libsystemd/sd-bus/bus-container.h +++ b/src/libsystemd/sd-bus/bus-container.h @@ -3,4 +3,6 @@ #include "sd-forward.h" +int container_get_leader(RuntimeScope scope, const char *machine, pid_t *ret); + int bus_container_connect_socket(sd_bus *b); diff --git a/src/libsystemd/sd-id128/id128-util.c b/src/libsystemd/sd-id128/id128-util.c index 0cae92b728..9d406a45d1 100644 --- a/src/libsystemd/sd-id128/id128-util.c +++ b/src/libsystemd/sd-id128/id128-util.c @@ -5,6 +5,7 @@ #include #include +#include "bus-container.h" #include "fd-util.h" #include "fs-util.h" #include "hash-funcs.h" @@ -13,6 +14,7 @@ #include "namespace-util.h" #include "pidref.h" #include "process-util.h" +#include "runtime-scope.h" #include "sha256.h" #include "siphash24.h" #include "string-util.h" @@ -287,7 +289,7 @@ int id128_get_boot_for_machine(const char *machine, sd_id128_t *ret) { if (isempty(machine)) return sd_id128_get_boot(ret); - r = container_get_leader(machine, &pid); + r = container_get_leader(RUNTIME_SCOPE_SYSTEM, machine, &pid); if (r < 0) return r; From 6119252f5a66fa881fe01b8300d468023f294261 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Mon, 16 Feb 2026 13:14:58 +0100 Subject: [PATCH 6/6] 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. --- src/basic/namespace-util.c | 36 +++++++++++ src/basic/namespace-util.h | 1 + src/libsystemd/sd-bus/bus-container.c | 92 ++++++++++++--------------- 3 files changed, 76 insertions(+), 53 deletions(-) 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); }