From b25430deab0beea34e04cc17bc073dcbcd67973f Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 7 Jan 2025 09:28:57 +0100 Subject: [PATCH 1/7] terminal-util: pidref'ify two terminal related calls --- src/basic/terminal-util.c | 19 ++++++++++++------- src/basic/terminal-util.h | 5 +++-- src/machine/machine.c | 4 ++-- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c index ab926a4214..b5dc3f21b8 100644 --- a/src/basic/terminal-util.c +++ b/src/basic/terminal-util.c @@ -1355,14 +1355,16 @@ static int ptsname_namespace(int pty, char **ret) { return 0; } -int openpt_allocate_in_namespace(pid_t pid, int flags, char **ret_peer_path) { +int openpt_allocate_in_namespace( + const PidRef *pidref, + int flags, + char **ret_peer_path) { + _cleanup_close_ int pidnsfd = -EBADF, mntnsfd = -EBADF, usernsfd = -EBADF, rootfd = -EBADF, fd = -EBADF; _cleanup_close_pair_ int pair[2] = EBADF_PAIR; int r; - assert(pid > 0); - - r = namespace_open(pid, &pidnsfd, &mntnsfd, /* ret_netns_fd = */ NULL, &usernsfd, &rootfd); + r = pidref_namespace_open(pidref, &pidnsfd, &mntnsfd, /* ret_netns_fd = */ NULL, &usernsfd, &rootfd); if (r < 0) return r; @@ -1411,15 +1413,18 @@ int openpt_allocate_in_namespace(pid_t pid, int flags, char **ret_peer_path) { return TAKE_FD(fd); } -int open_terminal_in_namespace(pid_t pid, const char *name, int mode) { +int open_terminal_in_namespace( + const PidRef *pidref, + const char *name, + int mode) { + _cleanup_close_ int pidnsfd = -EBADF, mntnsfd = -EBADF, usernsfd = -EBADF, rootfd = -EBADF; _cleanup_close_pair_ int pair[2] = EBADF_PAIR; int r; - assert(pid > 0); assert(name); - r = namespace_open(pid, &pidnsfd, &mntnsfd, /* ret_netns_fd= */ NULL, &usernsfd, &rootfd); + r = pidref_namespace_open(pidref, &pidnsfd, &mntnsfd, /* ret_netns_fd= */ NULL, &usernsfd, &rootfd); if (r < 0) return r; diff --git a/src/basic/terminal-util.h b/src/basic/terminal-util.h index 75b3219097..7ebfe61eb4 100644 --- a/src/basic/terminal-util.h +++ b/src/basic/terminal-util.h @@ -10,6 +10,7 @@ #include #include "macro.h" +#include "pidref.h" #include "time-util.h" /* Erase characters until the end of the line */ @@ -143,8 +144,8 @@ int getttyname_harder(int fd, char **ret); int ptsname_malloc(int fd, char **ret); int openpt_allocate(int flags, char **ret_peer); -int openpt_allocate_in_namespace(pid_t pid, int flags, char **ret_peer); -int open_terminal_in_namespace(pid_t pid, const char *name, int mode); +int openpt_allocate_in_namespace(const PidRef *pidref, int flags, char **ret_peer); +int open_terminal_in_namespace(const PidRef *pidref, const char *name, int mode); int vt_restore(int fd); int vt_release(int fd, bool restore_vt); diff --git a/src/machine/machine.c b/src/machine/machine.c index 3fc2b58fdb..918cf1f952 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -681,7 +681,7 @@ int machine_openpt(Machine *m, int flags, char **ret_peer) { if (!pidref_is_set(&m->leader)) return -EINVAL; - return openpt_allocate_in_namespace(m->leader.pid, flags, ret_peer); + return openpt_allocate_in_namespace(&m->leader, flags, ret_peer); default: return -EOPNOTSUPP; @@ -700,7 +700,7 @@ int machine_open_terminal(Machine *m, const char *path, int mode) { if (!pidref_is_set(&m->leader)) return -EINVAL; - return open_terminal_in_namespace(m->leader.pid, path, mode); + return open_terminal_in_namespace(&m->leader, path, mode); default: return -EOPNOTSUPP; From 8c0da3af283ee60569090187ce186b1f4c932749 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 7 Jan 2025 09:29:27 +0100 Subject: [PATCH 2/7] tree-wide: port more code to namespace_open_by_type() --- src/nspawn/nspawn-mount.c | 11 +++-------- src/nspawn/nspawn-network.c | 11 +++-------- src/nspawn/nspawn.c | 11 +++-------- src/shared/machine-id-setup.c | 11 +++-------- src/shared/socket-netlink.c | 12 +++--------- 5 files changed, 15 insertions(+), 41 deletions(-) diff --git a/src/nspawn/nspawn-mount.c b/src/nspawn/nspawn-mount.c index af88e82d04..d5370c22b9 100644 --- a/src/nspawn/nspawn-mount.c +++ b/src/nspawn/nspawn-mount.c @@ -1447,14 +1447,9 @@ int wipe_fully_visible_api_fs(int mntns_fd) { log_debug("Wiping fully visible API FS"); - r = namespace_open(0, - /* ret_pidns_fd = */ NULL, - &orig_mntns_fd, - /* ret_netns_fd = */ NULL, - /* ret_userns_fd = */ NULL, - /* ret_root_fd = */ NULL); - if (r < 0) - return log_error_errno(r, "Failed to pin originating mount namespace: %m"); + orig_mntns_fd = namespace_open_by_type(NAMESPACE_MOUNT); + if (orig_mntns_fd < 0) + return log_error_errno(orig_mntns_fd, "Failed to pin originating mount namespace: %m"); r = namespace_enter(/* pidns_fd = */ -EBADF, mntns_fd, diff --git a/src/nspawn/nspawn-network.c b/src/nspawn/nspawn-network.c index f46995bb64..928b8c5d41 100644 --- a/src/nspawn/nspawn-network.c +++ b/src/nspawn/nspawn-network.c @@ -476,14 +476,9 @@ static int netns_child_begin(int netns_fd, int *ret_original_netns_fd) { assert(netns_fd >= 0); if (ret_original_netns_fd) { - r = namespace_open(0, - /* ret_pidns_fd = */ NULL, - /* ret_mntns_fd = */ NULL, - &original_netns_fd, - /* ret_userns_fd = */ NULL, - /* ret_root_fd = */ NULL); - if (r < 0) - return log_error_errno(r, "Failed to open original network namespace: %m"); + original_netns_fd = namespace_open_by_type(NAMESPACE_NET); + if (original_netns_fd < 0) + return log_error_errno(original_netns_fd, "Failed to open original network namespace: %m"); } r = namespace_enter(/* pidns_fd = */ -EBADF, diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 4977ebd193..bc9b91d238 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -4012,14 +4012,9 @@ static int outer_child( return r; if (arg_userns_mode != USER_NAMESPACE_NO) { - r = namespace_open(0, - /* ret_pidns_fd = */ NULL, - &mntns_fd, - /* ret_netns_fd = */ NULL, - /* ret_userns_fd = */ NULL, - /* ret_root_fd = */ NULL); - if (r < 0) - return log_error_errno(r, "Failed to pin outer mount namespace: %m"); + mntns_fd = namespace_open_by_type(NAMESPACE_MOUNT); + if (mntns_fd < 0) + return log_error_errno(mntns_fd, "Failed to pin outer mount namespace: %m"); l = send_one_fd(fd_outer_socket, mntns_fd, 0); if (l < 0) diff --git a/src/shared/machine-id-setup.c b/src/shared/machine-id-setup.c index f5e1b9ee72..4240525742 100644 --- a/src/shared/machine-id-setup.c +++ b/src/shared/machine-id-setup.c @@ -301,14 +301,9 @@ int machine_id_commit(const char *root) { fd = safe_close(fd); /* Store current mount namespace */ - r = namespace_open(0, - /* ret_pidns_fd = */ NULL, - &initial_mntns_fd, - /* ret_netns_fd = */ NULL, - /* ret_userns_fd = */ NULL, - /* ret_root_fd = */ NULL); - if (r < 0) - return log_error_errno(r, "Can't fetch current mount namespace: %m"); + initial_mntns_fd = namespace_open_by_type(NAMESPACE_MOUNT); + if (initial_mntns_fd < 0) + return log_error_errno(initial_mntns_fd, "Can't fetch current mount namespace: %m"); /* Switch to a new mount namespace, isolate ourself and unmount etc_machine_id in our new namespace */ r = detach_mount_namespace(); diff --git a/src/shared/socket-netlink.c b/src/shared/socket-netlink.c index b0500abd8b..bdb203934b 100644 --- a/src/shared/socket-netlink.c +++ b/src/shared/socket-netlink.c @@ -428,15 +428,9 @@ int netns_get_nsid(int netnsfd, uint32_t *ret) { int r; if (netnsfd < 0) { - r = namespace_open( - 0, - /* ret_pidns_fd = */ NULL, - /* ret_mntns_fd = */ NULL, - &_netns_fd, - /* ret_userns_fd = */ NULL, - /* ret_root_fd = */ NULL); - if (r < 0) - return r; + _netns_fd = namespace_open_by_type(NAMESPACE_NET); + if (_netns_fd < 0) + return _netns_fd; netnsfd = _netns_fd; } From 9237a63a806b9d05c41aa8b6bcb29490a86d1981 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 7 Jan 2025 09:53:53 +0100 Subject: [PATCH 3/7] process-util: add new helper pidref_get_ppid_as_pidref() --- src/basic/process-util.c | 38 ++++++++++++++++++++++++++++++++++++ src/basic/process-util.h | 1 + src/test/test-process-util.c | 23 ++++++++++++++++++++++ 3 files changed, 62 insertions(+) diff --git a/src/basic/process-util.c b/src/basic/process-util.c index 77045e6aa8..f48285d3d5 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -742,6 +742,44 @@ int pidref_get_ppid(const PidRef *pidref, pid_t *ret) { return 0; } +int pidref_get_ppid_as_pidref(const PidRef *pidref, PidRef *ret) { + pid_t ppid; + int r; + + assert(ret); + + r = pidref_get_ppid(pidref, &ppid); + if (r < 0) + return r; + + for (unsigned attempt = 0; attempt < 16; attempt++) { + _cleanup_(pidref_done) PidRef parent = PIDREF_NULL; + + r = pidref_set_pid(&parent, ppid); + if (r < 0) + return r; + + /* If we have a pidfd of the original PID, let's verify that the process we acquired really + * is the parent still */ + if (pidref->fd >= 0) { + r = pidref_get_ppid(pidref, &ppid); + if (r < 0) + return r; + + /* Did the PPID change since we queried it? if so we might have pinned the wrong + * process, if its PID got reused by now. Let's try again */ + if (parent.pid != ppid) + continue; + } + + *ret = TAKE_PIDREF(parent); + return 0; + } + + /* Give up after 16 tries */ + return -ENOTRECOVERABLE; +} + int pid_get_start_time(pid_t pid, usec_t *ret) { _cleanup_free_ char *line = NULL; const char *p; diff --git a/src/basic/process-util.h b/src/basic/process-util.h index 8864472af6..d4d7d87c06 100644 --- a/src/basic/process-util.h +++ b/src/basic/process-util.h @@ -54,6 +54,7 @@ int get_process_root(pid_t pid, char **ret); int get_process_environ(pid_t pid, char **ret); int pid_get_ppid(pid_t pid, pid_t *ret); int pidref_get_ppid(const PidRef *pidref, pid_t *ret); +int pidref_get_ppid_as_pidref(const PidRef *pidref, PidRef *ret); 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); diff --git a/src/test/test-process-util.c b/src/test/test-process-util.c index 5a6bcdffcc..12bac656e2 100644 --- a/src/test/test-process-util.c +++ b/src/test/test-process-util.c @@ -848,6 +848,29 @@ TEST(pid_get_ppid) { pid = ppid; } + + /* the same via pidref */ + _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL; + ASSERT_OK(pidref_set_self(&pidref)); + for (;;) { + _cleanup_free_ char *c1 = NULL, *c2 = NULL; + _cleanup_(pidref_done) PidRef parent = PIDREF_NULL; + r = pidref_get_ppid_as_pidref(&pidref, &parent); + if (r == -EADDRNOTAVAIL) { + log_info("No further parent PID"); + break; + } + + ASSERT_OK(r); + + ASSERT_OK(pidref_get_cmdline(&pidref, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &c1)); + ASSERT_OK(pidref_get_cmdline(&parent, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &c2)); + + log_info("Parent of " PID_FMT " (%s) is " PID_FMT " (%s).", pidref.pid, c1, parent.pid, c2); + + pidref_done(&pidref); + pidref = TAKE_PIDREF(parent); + } } TEST(set_oom_score_adjust) { From 8703a508355bacf3522d4f41455a238b3d866484 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 7 Jan 2025 10:12:10 +0100 Subject: [PATCH 4/7] coredump: acquire further attributes via pidref rather than pid --- src/coredump/coredump.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c index c9f6a276e5..1125298786 100644 --- a/src/coredump/coredump.c +++ b/src/coredump/coredump.c @@ -1385,10 +1385,10 @@ static int gather_pid_metadata_from_procfs(struct iovec_wrapper *iovw, Context * if (cg_pid_get_user_unit(pid, &t) >= 0) (void) iovw_put_string_field_free(iovw, "COREDUMP_USER_UNIT=", t); - if (sd_pid_get_session(pid, &t) >= 0) + if (cg_pidref_get_session(&context->pidref, &t) >= 0) (void) iovw_put_string_field_free(iovw, "COREDUMP_SESSION=", t); - if (sd_pid_get_owner_uid(pid, &owner_uid) >= 0) { + if (cg_pidref_get_owner_uid(&context->pidref, &owner_uid) >= 0) { r = asprintf(&t, UID_FMT, owner_uid); if (r > 0) (void) iovw_put_string_field_free(iovw, "COREDUMP_OWNER_UID=", t); From 36812cb65976869ef80dbe7fd552565740ab6b11 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 7 Jan 2025 10:13:42 +0100 Subject: [PATCH 5/7] coredump: port to pidref_namespace_open() --- src/coredump/coredump.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c index 1125298786..9210d30688 100644 --- a/src/coredump/coredump.c +++ b/src/coredump/coredump.c @@ -1710,12 +1710,13 @@ static int acquire_pid_mount_tree_fd(const Context *context, int *ret_fd) { if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, pair) < 0) return log_error_errno(errno, "Failed to create socket pair: %m"); - r = namespace_open(context->pidref.pid, - /* ret_pidns_fd= */ NULL, - &mntns_fd, - /* ret_netns_fd= */ NULL, - /* ret_userns_fd= */ NULL, - &root_fd); + r = pidref_namespace_open( + &context->pidref, + /* ret_pidns_fd= */ NULL, + &mntns_fd, + /* ret_netns_fd= */ NULL, + /* ret_userns_fd= */ NULL, + &root_fd); if (r < 0) return log_error_errno(r, "Failed to open mount namespace of crashing process: %m"); From 47e45ea7389ea2e4ad074110ce7ac7f768f79eb0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 8 Jan 2025 10:50:06 +0100 Subject: [PATCH 6/7] process-util: make pidref_safe_fork_full() work with FORK_WAIT (This is useful for the test case added in the next commit, where it's kinda nice being able to use pidref_safe_fork_full() and acquiring a pidref of the child in the child in one go. There's no other value in this than a bit of synctactic sugar for that test. But otoh thre's no good reason to prohibit FORK_WAIT use like this, hence either way, this commit should be a good thing.) --- src/basic/process-util.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/basic/process-util.c b/src/basic/process-util.c index f48285d3d5..1264bae3e6 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -1783,12 +1783,16 @@ int pidref_safe_fork_full( pid_t pid; int r, q; - assert(!FLAGS_SET(flags, FORK_WAIT)); - r = safe_fork_full(name, stdio_fds, except_fds, n_except_fds, flags, &pid); - if (r < 0) + if (r < 0 || !ret_pid) return r; + if (r > 0 && FLAGS_SET(flags, FORK_WAIT)) { + /* If we are in the parent and successfully waited, then the process doesn't exist anymore */ + *ret_pid = PIDREF_NULL; + return r; + } + q = pidref_set_pid(ret_pid, pid); if (q < 0) /* Let's not fail for this, no matter what, the process exists after all, and that's key */ *ret_pid = PIDREF_MAKE_FROM_PID(pid); From 0b8b13324e652cfc3b9f25dec0cf834705bbb8d0 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 7 Jan 2025 09:54:15 +0100 Subject: [PATCH 7/7] namespace-util: port namespace_get_leader() to PidRef --- src/basic/namespace-util.c | 31 +++++++++++++++++------- src/basic/namespace-util.h | 2 +- src/coredump/coredump.c | 35 ++++++++++++++++----------- src/test/test-namespace.c | 49 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 94 insertions(+), 23 deletions(-) diff --git a/src/basic/namespace-util.c b/src/basic/namespace-util.c index c7b1bcca2d..da6ef37493 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); - for (;;) { - pid_t ppid; + _cleanup_(pidref_done) PidRef current = PIDREF_NULL; + PidRef *c = pidref; - r = pid_get_ppid(pid, &ppid); + for (;;) { + _cleanup_(pidref_done) PidRef parent = PIDREF_NULL; + + 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 d1ac4f6ed4..ea2488a432 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 9210d30688..55d075fdf3 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 46350b078d..cae65a14b1 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");