]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
namespace-util: port namespace_get_leader() to PidRef 35895/head
authorLennart Poettering <lennart@poettering.net>
Tue, 7 Jan 2025 08:54:15 +0000 (09:54 +0100)
committerLennart Poettering <lennart@poettering.net>
Fri, 10 Jan 2025 13:22:49 +0000 (14:22 +0100)
src/basic/namespace-util.c
src/basic/namespace-util.h
src/coredump/coredump.c
src/test/test-namespace.c

index c7b1bcca2d32ae26ac08952d43721f404256fe0e..da6ef37493841c5b04137602cb04baaf70c5db26 100644 (file)
@@ -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(&current))
+                                *ret = TAKE_PIDREF(current);
+                        else {
+                                r = pidref_copy(c, ret);
+                                if (r < 0)
+                                        return r;
+                        }
+
                         return 0;
                 }
 
-                pid = ppid;
+                pidref_done(&current);
+                current = TAKE_PIDREF(parent);
+                c = &current;
         }
 }
 
index d1ac4f6ed408e5e42237351f0f3c3147fb94309c..ea2488a4320967568f72f121f14f8383a093831a 100644 (file)
@@ -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);
index 9210d30688d3234215c29889db2d465f991504bc..55d075fdf365e276ec983ef86dfe05d521d58d50 100644 (file)
@@ -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]);
 
index 46350b078d952dde49bc22ed5fe313be7b715b0b..cae65a14b107c7319c72c2084d3902a081a11999 100644 (file)
@@ -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");