diff --git a/man/rules/meson.build b/man/rules/meson.build index 5edc46aaeea..3d995cb18e6 100644 --- a/man/rules/meson.build +++ b/man/rules/meson.build @@ -925,23 +925,29 @@ manpages = [ 'sd_peer_get_session', 'sd_peer_get_slice', 'sd_peer_get_unit', + 'sd_peer_get_unit_cgroup', 'sd_peer_get_user_slice', 'sd_peer_get_user_unit', + 'sd_peer_get_user_unit_cgroup', 'sd_pid_get_cgroup', 'sd_pid_get_machine_name', 'sd_pid_get_session', 'sd_pid_get_slice', 'sd_pid_get_unit', + 'sd_pid_get_unit_cgroup', 'sd_pid_get_user_slice', 'sd_pid_get_user_unit', + 'sd_pid_get_user_unit_cgroup', 'sd_pidfd_get_cgroup', 'sd_pidfd_get_machine_name', 'sd_pidfd_get_owner_uid', 'sd_pidfd_get_session', 'sd_pidfd_get_slice', 'sd_pidfd_get_unit', + 'sd_pidfd_get_unit_cgroup', 'sd_pidfd_get_user_slice', - 'sd_pidfd_get_user_unit'], + 'sd_pidfd_get_user_unit', + 'sd_pidfd_get_user_unit_cgroup'], 'HAVE_PAM'], ['sd_pidfd_get_inode_id', '3', [], ''], ['sd_seat_get_active', diff --git a/man/sd_pid_get_owner_uid.xml b/man/sd_pid_get_owner_uid.xml index 4b5da8bccd9..7e61fc36147 100644 --- a/man/sd_pid_get_owner_uid.xml +++ b/man/sd_pid_get_owner_uid.xml @@ -25,6 +25,8 @@ sd_pid_get_slice sd_pid_get_user_slice sd_pid_get_cgroup + sd_pid_get_unit_cgroup + sd_pid_get_user_unit_cgroup sd_pidfd_get_owner_uid sd_pidfd_get_session sd_pidfd_get_user_unit @@ -33,6 +35,8 @@ sd_pidfd_get_slice sd_pidfd_get_user_slice sd_pidfd_get_cgroup + sd_pidfd_get_unit_cgroup + sd_pidfd_get_user_unit_cgroup sd_peer_get_owner_uid sd_peer_get_session sd_peer_get_user_unit @@ -41,6 +45,8 @@ sd_peer_get_slice sd_peer_get_user_slice sd_peer_get_cgroup + sd_peer_get_unit_cgroup + sd_peer_get_user_unit_cgroup Determine the owner uid of the user unit or session, or the session, user unit, system unit, container/VM or slice that a specific PID or socket peer belongs to @@ -98,6 +104,18 @@ char **cgroup + + int sd_pid_get_unit_cgroup + pid_t pid + char **cgroup + + + + int sd_pid_get_user_unit_cgroup + pid_t pid + char **cgroup + + int sd_pidfd_get_owner_uid int pidfd @@ -146,6 +164,18 @@ char **cgroup + + int sd_pidfd_get_unit_cgroup + int pidfd + char **cgroup + + + + int sd_pidfd_get_user_unit_cgroup + int pidfd + char **cgroup + + int sd_peer_get_owner_uid int fd @@ -193,6 +223,18 @@ int fd char **cgroup + + + int sd_peer_get_unit_cgroup + int fd + char **cgroup + + + + int sd_peer_get_user_unit_cgroup + int fd + char **cgroup + @@ -266,7 +308,17 @@ sd_pid_get_cgroup() returns the control group path of the specified process, relative to the root of the hierarchy. Returns the path without trailing slash, except for processes located in the root control group, where "/" is returned. To find the actual control group path - in the file system, the returned path needs to be prefixed with /sys/fs/cgroup/. + in the file system, the returned path needs to be prefixed with /sys/fs/cgroup/. + The returned string needs to be freed with the libc + free3 + call after use. + + sd_pid_get_unit_cgroup() is like sd_pid_get_cgroup(), + but returns the control group path of the systemd system unit that contains the process. If the process + is not part of a systemd unit, then this function fails with -ENODATA. + + sd_pid_get_user_unit_cgroup() is like sd_pid_get_unit_cgroup(), + but operates on systemd user units (as managed by the user's systemd instance). If the pid parameter of any of these functions is passed as 0, the operation is executed for the @@ -278,12 +330,14 @@ sd_pidfd_get_unit(), sd_pidfd_get_machine_name(), sd_pidfd_get_slice(), - sd_pidfd_get_user_slice() and - sd_pidfd_get_cgroup() calls operate similarly to their PID counterparts, but accept a - PIDFD instead of a PID, which means they are not subject to recycle - race conditions as the process is pinned by the file descriptor during the whole duration of the invocation. - Note that these require a kernel that supports PIDFD. A suitable file descriptor may be - acquired via + sd_pidfd_get_user_slice(), + sd_pidfd_get_cgroup(), + sd_pidfd_get_unit_cgroup(), and + sd_pidfd_get_user_unit_cgroup(), calls operate similarly to their PID counterparts, + but accept a PIDFD instead of a PID, which means they are not + subject to recycle race conditions as the process is pinned by the file descriptor during the whole + duration of the invocation. Note that these require a kernel that supports PIDFD. + A suitable file descriptor may be acquired via pidfd_open2. The sd_peer_get_owner_uid(), @@ -292,10 +346,12 @@ sd_peer_get_unit(), sd_peer_get_machine_name(), sd_peer_get_slice(), - sd_peer_get_user_slice() and - sd_peer_get_cgroup() calls operate similarly to their PID counterparts, but accept a - connected AF_UNIX socket and retrieve information about the connected peer process. - Note that these fields are retrieved via /proc/, and hence are not suitable for + sd_peer_get_user_slice(), + sd_peer_get_cgroup(), + sd_peer_get_unit_cgroup(), and + sd_peer_get_user_unit_cgroup() calls operate similarly to their PID counterparts, but + accept a connected AF_UNIX socket and retrieve information about the connected peer + process. Note that these fields are retrieved via /proc/, and hence are not suitable for authorization purposes, as they are subject to races. @@ -386,6 +442,12 @@ sd_pidfd_get_slice(), sd_pidfd_get_user_slice(), and sd_pidfd_get_cgroup() were added in version 253. + sd_pid_get_unit_cgroup(), + sd_pid_get_user_unit_cgroup(), + sd_pidfd_get_unit_cgroup(), + sd_pidfd_get_user_unit_cgroup(), + sd_peer_get_unit_cgroup(), and + sd_peer_get_user_unit_cgroup() were added in version 263. diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym index 597cbe62abe..f91b568fe87 100644 --- a/src/libsystemd/libsystemd.sym +++ b/src/libsystemd/libsystemd.sym @@ -1121,4 +1121,10 @@ global: sd_varlink_invoke_and_upgrade; sd_varlink_invoke_and_upgradeb; sd_varlink_wants_reply; + sd_pid_get_unit_cgroup; + sd_pid_get_user_unit_cgroup; + sd_pidfd_get_unit_cgroup; + sd_pidfd_get_user_unit_cgroup; + sd_peer_get_unit_cgroup; + sd_peer_get_user_unit_cgroup; } LIBSYSTEMD_262; diff --git a/src/libsystemd/sd-login/sd-login.c b/src/libsystemd/sd-login/sd-login.c index ffe5541fd58..a8bf92ecc1e 100644 --- a/src/libsystemd/sd-login/sd-login.c +++ b/src/libsystemd/sd-login/sd-login.c @@ -124,6 +124,38 @@ _public_ int sd_pid_get_cgroup(pid_t pid, char **ret_cgroup) { return 0; } +_public_ int sd_pid_get_unit_cgroup(pid_t pid, char **ret_cgroup) { + int r; + + assert_return(pid >= 0, -EINVAL); + + _cleanup_free_ char *c = NULL; + r = cg_pid_get_unit_path(pid, &c); + if (r < 0) + return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r; + + if (ret_cgroup) + *ret_cgroup = TAKE_PTR(c); + + return 0; +} + +_public_ int sd_pid_get_user_unit_cgroup(pid_t pid, char **ret_cgroup) { + int r; + + assert_return(pid >= 0, -EINVAL); + + _cleanup_free_ char *c = NULL; + r = cg_pid_get_user_unit_path(pid, &c); + if (r < 0) + return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r; + + if (ret_cgroup) + *ret_cgroup = TAKE_PTR(c); + + return 0; +} + _public_ int sd_pidfd_get_session(int pidfd, char **ret_session) { _cleanup_free_ char *session = NULL; pid_t pid; @@ -316,6 +348,54 @@ _public_ int sd_pidfd_get_cgroup(int pidfd, char **ret_cgroup) { return 0; } +_public_ int sd_pidfd_get_unit_cgroup(int pidfd, char **ret_cgroup) { + _cleanup_free_ char *cgroup = NULL; + pid_t pid; + int r; + + assert_return(pidfd >= 0, -EBADF); + + r = pidfd_get_pid(pidfd, &pid); + if (r < 0) + return r; + + r = sd_pid_get_unit_cgroup(pid, &cgroup); + if (r < 0) + return r; + + r = pidfd_verify_pid(pidfd, pid); + if (r < 0) + return r; + + if (ret_cgroup) + *ret_cgroup = TAKE_PTR(cgroup); + return 0; +} + +_public_ int sd_pidfd_get_user_unit_cgroup(int pidfd, char **ret_cgroup) { + _cleanup_free_ char *cgroup = NULL; + pid_t pid; + int r; + + assert_return(pidfd >= 0, -EBADF); + + r = pidfd_get_pid(pidfd, &pid); + if (r < 0) + return r; + + r = sd_pid_get_user_unit_cgroup(pid, &cgroup); + if (r < 0) + return r; + + r = pidfd_verify_pid(pidfd, pid); + if (r < 0) + return r; + + if (ret_cgroup) + *ret_cgroup = TAKE_PTR(cgroup); + return 0; +} + _public_ int sd_peer_get_session(int fd, char **ret_session) { int r; @@ -437,6 +517,46 @@ _public_ int sd_peer_get_cgroup(int fd, char **ret_cgroup) { return 0; } +_public_ int sd_peer_get_unit_cgroup(int fd, char **ret_cgroup) { + int r; + + assert_return(fd >= 0, -EBADF); + + _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL; + r = getpeerpidref(fd, &pidref); + if (r < 0) + return r; + + _cleanup_free_ char *c = NULL; + r = cg_pidref_get_unit_path(&pidref, &c); + if (r < 0) + return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r; + + if (ret_cgroup) + *ret_cgroup = TAKE_PTR(c); + return 0; +} + +_public_ int sd_peer_get_user_unit_cgroup(int fd, char **ret_cgroup) { + int r; + + assert_return(fd >= 0, -EBADF); + + _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL; + r = getpeerpidref(fd, &pidref); + if (r < 0) + return r; + + _cleanup_free_ char *c = NULL; + r = cg_pidref_get_user_unit_path(&pidref, &c); + if (r < 0) + return IN_SET(r, -ENXIO, -ENOMEDIUM) ? -ENODATA : r; + + if (ret_cgroup) + *ret_cgroup = TAKE_PTR(c); + return 0; +} + static int file_of_uid(uid_t uid, char **ret) { assert_return(uid_is_valid(uid), -EINVAL); diff --git a/src/libsystemd/sd-login/test-login.c b/src/libsystemd/sd-login/test-login.c index 4c7b2776ad2..6e88ef1d8a2 100644 --- a/src/libsystemd/sd-login/test-login.c +++ b/src/libsystemd/sd-login/test-login.c @@ -45,7 +45,8 @@ TEST(login) { *display = NULL, *remote_user = NULL, *remote_host = NULL, *type = NULL, *class = NULL, *state = NULL, *state2 = NULL, *seat = NULL, *session = NULL, - *unit = NULL, *user_unit = NULL, *slice = NULL; + *unit = NULL, *user_unit = NULL, *slice = NULL, + *unit_cgroup = NULL, *user_unit_cgroup = NULL; _cleanup_close_ int pidfd = -EBADF; int r; uid_t u, u2 = UID_INVALID; @@ -55,10 +56,18 @@ TEST(login) { log_info("sd_pid_get_unit(0, …) → %s / \"%s\"", e(r), strnull(unit)); ASSERT_TRUE(IN_SET(r, 0, -ENODATA)); + r = sd_pid_get_unit_cgroup(/* pid= */ 0, &unit_cgroup); + log_info("sd_pid_get_unit_cgroup(0, …) → %s / \"%s\"", e(r), strnull(unit_cgroup)); + assert_se(IN_SET(r, 0, -ENODATA)); + r = sd_pid_get_user_unit(/* pid= */ 0, &user_unit); log_info("sd_pid_get_user_unit(0, …) → %s / \"%s\"", e(r), strnull(user_unit)); ASSERT_TRUE(IN_SET(r, 0, -ENODATA)); + r = sd_pid_get_user_unit_cgroup(/* pid= */ 0, &user_unit_cgroup); + log_info("sd_pid_get_user_unit_cgroup(0, …) → %s / \"%s\"", e(r), strnull(user_unit_cgroup)); + assert_se(IN_SET(r, 0, -ENODATA)); + /* Coverage for https://github.com/systemd/systemd/issues/39949 */ ASSERT_TRUE(!unit || !user_unit || !streq(unit, user_unit)); @@ -80,16 +89,25 @@ TEST(login) { pidfd = pidfd_open(getpid_cached(), 0); if (pidfd >= 0) { _cleanup_free_ char *cgroup2 = NULL, *session2 = NULL, - *unit2 = NULL, *user_unit2 = NULL, *slice2 = NULL; + *unit2 = NULL, *user_unit2 = NULL, *slice2 = NULL, + *unit_cgroup2 = NULL, *user_unit_cgroup2 = NULL; r = sd_pidfd_get_unit(pidfd, &unit2); log_info("sd_pidfd_get_unit(pidfd, …) → %s / \"%s\"", e(r), strnull(unit2)); ASSERT_TRUE(IN_SET(r, 0, -ENODATA)); + r = sd_pidfd_get_unit_cgroup(pidfd, &unit_cgroup2); + log_info("sd_pidfd_get_unit_cgroup(pidfd, …) → %s / \"%s\"", e(r), strnull(unit_cgroup2)); + assert_se(IN_SET(r, 0, -ENODATA)); + r = sd_pidfd_get_user_unit(pidfd, &user_unit2); log_info("sd_pidfd_get_user_unit(pidfd, …) → %s / \"%s\"", e(r), strnull(user_unit2)); ASSERT_TRUE(IN_SET(r, 0, -ENODATA)); + r = sd_pidfd_get_user_unit_cgroup(pidfd, &user_unit_cgroup2); + log_info("sd_pidfd_get_user_unit_cgroup(pidfd, …) → %s / \"%s\"", e(r), strnull(user_unit_cgroup2)); + assert_se(IN_SET(r, 0, -ENODATA)); + r = sd_pidfd_get_slice(pidfd, &slice2); log_info("sd_pidfd_get_slice(pidfd, …) → %s / \"%s\"", e(r), strnull(slice2)); ASSERT_TRUE(IN_SET(r, 0, -ENODATA)); diff --git a/src/systemd/sd-login.h b/src/systemd/sd-login.h index f9cfaf6a2fe..08de7d8f2ff 100644 --- a/src/systemd/sd-login.h +++ b/src/systemd/sd-login.h @@ -77,6 +77,16 @@ int sd_pid_get_machine_name(pid_t pid, char **ret_machine); * hierarchy. */ int sd_pid_get_cgroup(pid_t pid, char **ret_cgroup); +/* Get systemd non-slice unit (i.e. service) control group from PID, + * for system services. This will return an error for non-service + * processes. */ +int sd_pid_get_unit_cgroup(pid_t pid, char **ret_cgroup); + +/* Get systemd non-slice unit (i.e. service) control group from PID, + * for user services. This will return an error for non-service + * processes. */ +int sd_pid_get_user_unit_cgroup(pid_t pid, char **ret_cgroup); + /* Equivalent to the corresponding sd_pid_get* functions, but take a * PIDFD instead of a PID, to ensure there can be no possible PID * recycle issues before/after the calls. */ @@ -88,6 +98,8 @@ int sd_pidfd_get_slice(int pidfd, char **ret_slice); int sd_pidfd_get_user_slice(int pidfd, char **ret_slice); int sd_pidfd_get_machine_name(int pidfd, char **ret_machine); int sd_pidfd_get_cgroup(int pidfd, char **ret_cgroup); +int sd_pidfd_get_unit_cgroup(int pidfd, char **ret_cgroup); +int sd_pidfd_get_user_unit_cgroup(int pidfd, char **ret_cgroup); /* Similar to sd_pid_get_session(), but retrieves data about the peer * of a connected AF_UNIX socket */ @@ -121,6 +133,14 @@ int sd_peer_get_machine_name(int fd, char **ret_machine); * of a connected AF_UNIX socket. */ int sd_peer_get_cgroup(int fd, char **ret_cgroup); +/* Similar to sd_pid_get_unit_cgroup(), but retrieves data about the peer + * of a connected AF_UNIX socket. */ +int sd_peer_get_unit_cgroup(int fd, char **ret_cgroup); + +/* Similar to sd_pid_get_user_unit_cgroup(), but retrieves data about the peer + * of a connected AF_UNIX socket. */ +int sd_peer_get_user_unit_cgroup(int fd, char **ret_cgroup); + /* Get state from UID. Possible states: offline, lingering, online, active, closing */ int sd_uid_get_state(uid_t uid, char **ret_state);