sd-bus: Make sure we can connect to user machines as well (#40698)

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.
This commit is contained in:
Daan De Meyer
2026-02-17 19:13:40 +01:00
committed by GitHub
9 changed files with 204 additions and 160 deletions
+87 -39
View File
@@ -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 */
}
@@ -216,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. */
@@ -275,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)
@@ -361,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;
+1
View 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);
+1 -43
View File
@@ -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;
-2
View File
@@ -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);
}