From: Lennart Poettering Date: Tue, 7 Jan 2025 08:54:15 +0000 (+0100) Subject: namespace-util: port namespace_get_leader() to PidRef X-Git-Tag: v258-rc1~1634^2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=refs%2Fpull%2F35895%2Fhead;p=thirdparty%2Fsystemd.git namespace-util: port namespace_get_leader() to PidRef --- diff --git a/src/basic/namespace-util.c b/src/basic/namespace-util.c index c7b1bcca2d3..da6ef374938 100644 --- a/src/basic/namespace-util.c +++ b/src/basic/namespace-util.c @@ -351,31 +351,46 @@ int pidref_in_same_namespace(PidRef *pid1, PidRef *pid2, NamespaceType type) { return fd_inode_same(ns1, ns2); } -int namespace_get_leader(pid_t pid, NamespaceType type, pid_t *ret) { +int namespace_get_leader(PidRef *pidref, NamespaceType type, PidRef *ret) { int r; - assert(pid >= 0); + /* Note: we don't bother with pidref_is_set()/pidref_is_remote() here, as the first call we do, + * pidref_get_ppid_as_pidref() calls those anyway */ + assert(type >= 0 && type < _NAMESPACE_TYPE_MAX); assert(ret); + _cleanup_(pidref_done) PidRef current = PIDREF_NULL; + PidRef *c = pidref; + for (;;) { - pid_t ppid; + _cleanup_(pidref_done) PidRef parent = PIDREF_NULL; - r = pid_get_ppid(pid, &ppid); + r = pidref_get_ppid_as_pidref(c, &parent); if (r < 0) return r; - r = in_same_namespace(pid, ppid, type); + r = pidref_in_same_namespace(c, &parent, type); if (r < 0) return r; if (r == 0) { /* If the parent and the child are not in the same namespace, then the child is * the leader we are looking for. */ - *ret = pid; + + if (pidref_is_set(¤t)) + *ret = TAKE_PIDREF(current); + else { + r = pidref_copy(c, ret); + if (r < 0) + return r; + } + return 0; } - pid = ppid; + pidref_done(¤t); + current = TAKE_PIDREF(parent); + c = ¤t; } } diff --git a/src/basic/namespace-util.h b/src/basic/namespace-util.h index d1ac4f6ed40..ea2488a4320 100644 --- a/src/basic/namespace-util.h +++ b/src/basic/namespace-util.h @@ -62,7 +62,7 @@ static inline int in_same_namespace(pid_t pid1, pid_t pid2, NamespaceType type) type); } -int namespace_get_leader(pid_t pid, NamespaceType type, pid_t *ret); +int namespace_get_leader(PidRef *pidref, NamespaceType type, PidRef *ret); int detach_mount_namespace(void); int detach_mount_namespace_harder(uid_t target_uid, gid_t target_gid); diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c index 9210d30688d..55d075fdf36 100644 --- a/src/coredump/coredump.c +++ b/src/coredump/coredump.c @@ -757,31 +757,34 @@ static int compose_open_fds(pid_t pid, char **ret) { * container parent (the pid's process isn't 'containerized'). * Returns a negative number on errors. */ -static int get_process_container_parent_cmdline(pid_t pid, char** cmdline) { - pid_t container_pid; +static int get_process_container_parent_cmdline(PidRef *pid, char** ret_cmdline) { const char *proc_root_path; struct stat root_stat, proc_root_stat; int r; + assert(pidref_is_set(pid)); + assert(!pidref_is_remote(pid)); + /* To compare inodes of / and /proc/[pid]/root */ if (stat("/", &root_stat) < 0) return -errno; - proc_root_path = procfs_file_alloca(pid, "root"); + proc_root_path = procfs_file_alloca(pid->pid, "root"); if (stat(proc_root_path, &proc_root_stat) < 0) return -errno; /* The process uses system root. */ if (stat_inode_same(&proc_root_stat, &root_stat)) { - *cmdline = NULL; + *ret_cmdline = NULL; return 0; } + _cleanup_(pidref_done) PidRef container_pid = PIDREF_NULL; r = namespace_get_leader(pid, NAMESPACE_MOUNT, &container_pid); if (r < 0) return r; - r = pid_get_cmdline(container_pid, SIZE_MAX, PROCESS_CMDLINE_QUOTE_POSIX, cmdline); + r = pidref_get_cmdline(&container_pid, SIZE_MAX, PROCESS_CMDLINE_QUOTE_POSIX, ret_cmdline); if (r < 0) return r; @@ -1451,7 +1454,7 @@ static int gather_pid_metadata_from_procfs(struct iovec_wrapper *iovw, Context * /* If the process' root is "/", then there is a chance it has * mounted own root and hence being containerized. */ - if (proc_self_root_is_slash && get_process_container_parent_cmdline(pid, &t) > 0) + if (proc_self_root_is_slash && get_process_container_parent_cmdline(&context->pidref, &t) > 0) (void) iovw_put_string_field_free(iovw, "COREDUMP_CONTAINER_CMDLINE=", t); } @@ -1518,11 +1521,14 @@ static int receive_ucred(int transport_fd, struct ucred *ret_ucred) { return 0; } -static int can_forward_coredump(pid_t pid) { +static int can_forward_coredump(const PidRef *pid) { _cleanup_free_ char *cgroup = NULL, *path = NULL, *unit = NULL; int r; - r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &cgroup); + assert(pidref_is_set(pid)); + assert(!pidref_is_remote(pid)); + + r = cg_pidref_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &cgroup); if (r < 0) return r; @@ -1551,7 +1557,7 @@ static int can_forward_coredump(pid_t pid) { static int forward_coredump_to_container(Context *context) { _cleanup_close_ int pidnsfd = -EBADF, mntnsfd = -EBADF, netnsfd = -EBADF, usernsfd = -EBADF, rootfd = -EBADF; _cleanup_close_pair_ int pair[2] = EBADF_PAIR; - pid_t leader_pid, child; + pid_t child; struct ucred ucred = { .pid = context->pidref.pid, .uid = context->uid, @@ -1561,11 +1567,12 @@ static int forward_coredump_to_container(Context *context) { assert(context); - r = namespace_get_leader(context->pidref.pid, NAMESPACE_PID, &leader_pid); + _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"); - r = can_forward_coredump(leader_pid); + r = can_forward_coredump(&leader_pid); if (r < 0) return log_debug_errno(r, "Failed to check if coredump can be forwarded: %m"); if (r == 0) @@ -1580,15 +1587,15 @@ static int forward_coredump_to_container(Context *context) { if (r < 0) return log_debug_errno(r, "Failed to set SO_PASSCRED: %m"); - r = namespace_open(leader_pid, &pidnsfd, &mntnsfd, &netnsfd, &usernsfd, &rootfd); + r = pidref_namespace_open(&leader_pid, &pidnsfd, &mntnsfd, &netnsfd, &usernsfd, &rootfd); if (r < 0) - return log_debug_errno(r, "Failed to join namespaces of PID " PID_FMT ": %m", leader_pid); + return log_debug_errno(r, "Failed to open namespaces of PID " PID_FMT ": %m", leader_pid.pid); r = namespace_fork("(sd-coredumpns)", "(sd-coredump)", NULL, 0, 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); + return log_debug_errno(r, "Failed to fork into namespaces of PID " PID_FMT ": %m", leader_pid.pid); if (r == 0) { pair[0] = safe_close(pair[0]); diff --git a/src/test/test-namespace.c b/src/test/test-namespace.c index 46350b078d9..cae65a14b10 100644 --- a/src/test/test-namespace.c +++ b/src/test/test-namespace.c @@ -9,6 +9,7 @@ #include "fd-util.h" #include "fileio.h" #include "namespace.h" +#include "pidref.h" #include "process-util.h" #include "string-util.h" #include "tests.h" @@ -365,6 +366,54 @@ TEST(process_is_owned_by_uid) { ASSERT_OK(pidref_wait_for_terminate(&pid, /* ret= */ NULL)); } +TEST(namespace_get_leader) { + int r; + + _cleanup_(pidref_done) PidRef original = PIDREF_NULL; + ASSERT_OK(pidref_set_self(&original)); + + _cleanup_(pidref_done) PidRef pid = PIDREF_NULL; + r = pidref_safe_fork("(child)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGKILL|FORK_NEW_MOUNTNS|FORK_WAIT|FORK_LOG, &pid); + ASSERT_OK(r); + if (r == 0) { + + _cleanup_(pidref_done) PidRef pid2 = PIDREF_NULL; + r = pidref_safe_fork("(child)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGKILL|FORK_WAIT|FORK_LOG, &pid2); + ASSERT_OK(r); + + if (r == 0) { + log_info("PID hierarchy: " PID_FMT " ← " PID_FMT " ← " PID_FMT, original.pid, pid.pid, pid2.pid); + + _cleanup_(pidref_done) PidRef self = PIDREF_NULL; + ASSERT_OK(pidref_set_self(&self)); + ASSERT_TRUE(pidref_equal(&self, &pid2)); + + _cleanup_(pidref_done) PidRef parent = PIDREF_NULL; + ASSERT_OK(pidref_set_parent(&parent)); + ASSERT_TRUE(pidref_equal(&parent, &pid)); + ASSERT_TRUE(!pidref_equal(&self, &pid)); + ASSERT_TRUE(!pidref_equal(&self, &parent)); + + _cleanup_(pidref_done) PidRef grandparent = PIDREF_NULL; + ASSERT_OK(pidref_get_ppid_as_pidref(&parent, &grandparent)); + ASSERT_TRUE(pidref_equal(&grandparent, &original)); + ASSERT_TRUE(!pidref_equal(&grandparent, &self)); + ASSERT_TRUE(!pidref_equal(&grandparent, &pid)); + ASSERT_TRUE(!pidref_equal(&grandparent, &pid2)); + ASSERT_TRUE(!pidref_equal(&grandparent, &parent)); + + _cleanup_(pidref_done) PidRef leader = PIDREF_NULL; + ASSERT_OK(namespace_get_leader(&self, NAMESPACE_MOUNT, &leader)); + ASSERT_TRUE(pidref_equal(&parent, &leader)); + ASSERT_TRUE(pidref_equal(&pid, &leader)); + ASSERT_TRUE(!pidref_equal(&self, &leader)); + ASSERT_TRUE(!pidref_equal(&pid2, &leader)); + ASSERT_TRUE(!pidref_equal(&original, &leader)); + ASSERT_TRUE(!pidref_equal(&grandparent, &leader)); + } + } +} + static int intro(void) { if (!have_namespaces()) return log_tests_skipped("Don't have namespace support or lacking privileges");