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..62a0540c39a 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,11 +346,13 @@ 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 - authorization purposes, as they are subject to races. + 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 PIDFD counterparts, + but accept a connected AF_UNIX socket and retrieve information about the connected + peer process. On kernels that support SO_PEERPIDFD (Linux 6.5 or newer), these calls + are not subject to recycle race conditions. @@ -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/basic/cgroup-util.c b/src/basic/cgroup-util.c index f3ba59d528a..a5aa3e1a5b7 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -696,14 +696,14 @@ int cg_get_root_path(char **ret_path) { return 0; } -int cg_shift_path(const char *cgroup, const char *root, const char **ret_shifted) { +int cg_shift_path(const char *cgroup, const char *cached_root, const char **ret_shifted) { int r; assert(cgroup); assert(ret_shifted); _cleanup_free_ char *rt = NULL; - if (!root) { + if (!cached_root) { /* If the root was specified let's use that, otherwise * let's determine it from PID 1 */ @@ -711,14 +711,14 @@ int cg_shift_path(const char *cgroup, const char *root, const char **ret_shifted if (r < 0) return r; - root = rt; + cached_root = rt; } - *ret_shifted = path_startswith_full(cgroup, root, PATH_STARTSWITH_RETURN_LEADING_SLASH|PATH_STARTSWITH_REFUSE_DOT_DOT) ?: cgroup; + *ret_shifted = path_startswith_full(cgroup, cached_root, PATH_STARTSWITH_RETURN_LEADING_SLASH|PATH_STARTSWITH_REFUSE_DOT_DOT) ?: cgroup; return 0; } -int cg_pid_get_path_shifted(pid_t pid, const char *root, char **ret_cgroup) { +int cg_pid_get_path_shifted(pid_t pid, const char *cached_root, char **ret_cgroup) { _cleanup_free_ char *raw = NULL; const char *c; int r; @@ -730,7 +730,7 @@ int cg_pid_get_path_shifted(pid_t pid, const char *root, char **ret_cgroup) { if (r < 0) return r; - r = cg_shift_path(raw, root, &c); + r = cg_shift_path(raw, cached_root, &c); if (r < 0) return r; @@ -742,7 +742,7 @@ int cg_pid_get_path_shifted(pid_t pid, const char *root, char **ret_cgroup) { return strdup_to(ret_cgroup, c); } -int cg_pidref_get_path_shifted(const PidRef *pidref, const char *root, char **ret_cgroup) { +int cg_pidref_get_path_shifted(const PidRef *pidref, const char *cached_root, char **ret_cgroup) { _cleanup_free_ char *raw = NULL; const char *c; int r; @@ -753,7 +753,7 @@ int cg_pidref_get_path_shifted(const PidRef *pidref, const char *root, char **re if (r < 0) return r; - r = cg_shift_path(raw, root, &c); + r = cg_shift_path(raw, cached_root, &c); if (r < 0) return r; @@ -765,21 +765,37 @@ int cg_pidref_get_path_shifted(const PidRef *pidref, const char *root, char **re return strdup_to(ret_cgroup, c); } -int cg_path_decode_unit(const char *cgroup, char **ret_unit) { +static const char* skip_unit(const char *cgroup) { assert(cgroup); size_t n = strcspn(cgroup, "/"); if (n < 3) - return -ENXIO; + return NULL; char *c = strndupa_safe(cgroup, n); c = cg_unescape(c); if (!unit_name_is_valid(c, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) + return NULL; + + return cgroup + n; +} + +int cg_path_decode_unit(const char *cgroup, char **ret_unit) { + assert(cgroup); + + const char *end = skip_unit(cgroup); + if (!end) return -ENXIO; - if (ret_unit) - return strdup_to(ret_unit, c); + if (ret_unit) { + const char *start = cg_unescape(cgroup); + _cleanup_free_ char *unit = strndup(start, end - start); + if (!unit) + return -ENOMEM; + + *ret_unit = TAKE_PTR(unit); + } return 0; } @@ -855,25 +871,24 @@ int cg_path_get_unit_full(const char *path, char **ret_unit, char **ret_subgroup return 0; } -int cg_path_get_unit_path(const char *path, char **ret) { - _cleanup_free_ char *path_copy = NULL; - char *unit_name; +static const char* skip_unit_path(const char *cgroup) { + const char *end = skip_slices(cgroup); + return skip_unit(end); +} +int cg_path_get_unit_path(const char *path, char **ret_path) { assert(path); - assert(ret); + assert(ret_path); - path_copy = strdup(path); - if (!path_copy) - return -ENOMEM; - - unit_name = (char*) skip_slices(path_copy); - unit_name[strcspn(unit_name, "/")] = 0; - - if (!unit_name_is_valid(cg_unescape(unit_name), UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) + const char *end = skip_unit_path(path); + if (!end) return -ENXIO; - *ret = TAKE_PTR(path_copy); + _cleanup_free_ char *unit_path = strndup(path, end - path); + if (!unit_path) + return -ENOMEM; + *ret_path = TAKE_PTR(unit_path); return 0; } @@ -888,6 +903,34 @@ int cg_pid_get_unit_full(pid_t pid, char **ret_unit, char **ret_subgroup) { return cg_path_get_unit_full(cgroup, ret_unit, ret_subgroup); } +int cg_pid_get_unit_path(pid_t pid, char **ret_path) { + int r; + + assert(pid >= 0); + assert(ret_path); + + _cleanup_free_ char *cgroup = NULL; + r = cg_pid_get_path(pid, &cgroup); + if (r < 0) + return r; + + const char *end; + r = cg_shift_path(cgroup, /* cached_root= */ NULL, &end); + if (r < 0) + return r; + + end = skip_unit_path(end); + if (!end) + return -ENXIO; + + _cleanup_free_ char *unit_path = strndup(cgroup, end - cgroup); + if (!unit_path) + return -ENOMEM; + + *ret_path = TAKE_PTR(unit_path); + return 0; +} + int cg_pidref_get_unit_full(const PidRef *pidref, char **ret_unit, char **ret_subgroup) { int r; @@ -912,6 +955,28 @@ int cg_pidref_get_unit_full(const PidRef *pidref, char **ret_unit, char **ret_su return 0; } +int cg_pidref_get_unit_path(const PidRef *pidref, char **ret_path) { + int r; + + if (!pidref_is_set(pidref)) + return -ESRCH; + if (pidref_is_remote(pidref)) + return -EREMOTE; + + _cleanup_free_ char *unit_path = NULL; + r = cg_pid_get_unit_path(pidref->pid, &unit_path); + if (r < 0) + return r; + + r = pidref_verify(pidref); + if (r < 0) + return r; + + if (ret_path) + *ret_path = TAKE_PTR(unit_path); + return 0; +} + static const char* skip_session(const char *p) { size_t n; @@ -1011,6 +1076,30 @@ int cg_path_get_user_unit_full(const char *path, char **ret_unit, char **ret_sub return cg_path_get_unit_full(t, ret_unit, ret_subgroup); } +static const char* skip_user_unit_path(const char *cgroup) { + const char *end = skip_user_prefix(cgroup); + if (!end) + return NULL; + + return skip_unit_path(end); +} + +int cg_path_get_user_unit_path(const char *path, char **ret_path) { + assert(path); + assert(ret_path); + + const char *end = skip_user_unit_path(path); + if (!end) + return -ENXIO; + + _cleanup_free_ char *unit_path = strndup(path, end - path); + if (!unit_path) + return -ENOMEM; + + *ret_path = TAKE_PTR(unit_path); + return 0; +} + int cg_pid_get_user_unit_full(pid_t pid, char **ret_unit, char **ret_subgroup) { int r; @@ -1022,6 +1111,34 @@ int cg_pid_get_user_unit_full(pid_t pid, char **ret_unit, char **ret_subgroup) { return cg_path_get_user_unit_full(cgroup, ret_unit, ret_subgroup); } +int cg_pid_get_user_unit_path(pid_t pid, char **ret_path) { + int r; + + assert(pid >= 0); + assert(ret_path); + + _cleanup_free_ char *cgroup = NULL; + r = cg_pid_get_path(pid, &cgroup); + if (r < 0) + return r; + + const char *end; + r = cg_shift_path(cgroup, /* cached_root= */ NULL, &end); + if (r < 0) + return r; + + end = skip_user_unit_path(end); + if (!end) + return -ENXIO; + + _cleanup_free_ char *unit_path = strndup(cgroup, end - cgroup); + if (!unit_path) + return -ENOMEM; + + *ret_path = TAKE_PTR(unit_path); + return 0; +} + int cg_pidref_get_user_unit_full(const PidRef *pidref, char **ret_unit, char **ret_subgroup) { int r; @@ -1046,6 +1163,28 @@ int cg_pidref_get_user_unit_full(const PidRef *pidref, char **ret_unit, char **r return 0; } +int cg_pidref_get_user_unit_path(const PidRef *pidref, char **ret_path) { + int r; + + if (!pidref_is_set(pidref)) + return -ESRCH; + if (pidref_is_remote(pidref)) + return -EREMOTE; + + _cleanup_free_ char *unit_path = NULL; + r = cg_pid_get_user_unit_path(pidref->pid, &unit_path); + if (r < 0) + return r; + + r = pidref_verify(pidref); + if (r < 0) + return r; + + if (ret_path) + *ret_path = TAKE_PTR(unit_path); + return 0; +} + int cg_path_get_machine_name(const char *path, char **ret_machine) { _cleanup_free_ char *u = NULL; const char *sl; @@ -1070,6 +1209,28 @@ int cg_pid_get_machine_name(pid_t pid, char **ret_machine) { return cg_path_get_machine_name(cgroup, ret_machine); } +int cg_pidref_get_machine_name(const PidRef *pidref, char **ret_machine) { + int r; + + if (!pidref_is_set(pidref)) + return -ESRCH; + if (pidref_is_remote(pidref)) + return -EREMOTE; + + _cleanup_free_ char *machine = NULL; + r = cg_pid_get_machine_name(pidref->pid, &machine); + if (r < 0) + return r; + + r = pidref_verify(pidref); + if (r < 0) + return r; + + if (ret_machine) + *ret_machine = TAKE_PTR(machine); + return 0; +} + int cg_path_get_session(const char *path, char **ret_session) { _cleanup_free_ char *unit = NULL; char *start, *end; @@ -1232,6 +1393,28 @@ int cg_pid_get_slice(pid_t pid, char **ret_slice) { return cg_path_get_slice(cgroup, ret_slice); } +int cg_pidref_get_slice(const PidRef *pidref, char **ret_slice) { + int r; + + if (!pidref_is_set(pidref)) + return -ESRCH; + if (pidref_is_remote(pidref)) + return -EREMOTE; + + _cleanup_free_ char *slice = NULL; + r = cg_pid_get_slice(pidref->pid, &slice); + if (r < 0) + return r; + + r = pidref_verify(pidref); + if (r < 0) + return r; + + if (ret_slice) + *ret_slice = TAKE_PTR(slice); + return 0; +} + int cg_path_get_user_slice(const char *p, char **ret_slice) { const char *t; assert(p); @@ -1256,6 +1439,28 @@ int cg_pid_get_user_slice(pid_t pid, char **ret_slice) { return cg_path_get_user_slice(cgroup, ret_slice); } +int cg_pidref_get_user_slice(const PidRef *pidref, char **ret_slice) { + int r; + + if (!pidref_is_set(pidref)) + return -ESRCH; + if (pidref_is_remote(pidref)) + return -EREMOTE; + + _cleanup_free_ char *slice = NULL; + r = cg_pid_get_user_slice(pidref->pid, &slice); + if (r < 0) + return r; + + r = pidref_verify(pidref); + if (r < 0) + return r; + + if (ret_slice) + *ret_slice = TAKE_PTR(slice); + return 0; +} + bool cg_needs_escape(const char *p) { /* Checks if the specified path is a valid cgroup name by our rules, or if it must be escaped. Note diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h index ec91239460b..755f1fd5514 100644 --- a/src/basic/cgroup-util.h +++ b/src/basic/cgroup-util.h @@ -185,7 +185,8 @@ int cg_path_get_unit_full(const char *path, char **ret_unit, char **ret_subgroup static inline int cg_path_get_unit(const char *path, char **ret_unit) { return cg_path_get_unit_full(path, ret_unit, /* ret_subgroup= */ NULL); } -int cg_path_get_unit_path(const char *path, char **ret_unit); +int cg_path_get_unit_path(const char *path, char **ret_path); +int cg_path_get_user_unit_path(const char *path, char **ret_path); int cg_path_get_user_unit_full(const char *path, char **ret_unit, char **ret_subgroup); static inline int cg_path_get_user_unit(const char *path, char **ret_unit) { return cg_path_get_user_unit_full(path, ret_unit, /* ret_subgroup= */ NULL); @@ -206,21 +207,28 @@ int cg_pid_get_unit_full(pid_t pid, char **ret_unit, char **ret_subgroup); static inline int cg_pid_get_unit(pid_t pid, char **ret_unit) { return cg_pid_get_unit_full(pid, ret_unit, /* ret_subgroup= */ NULL); } +int cg_pid_get_unit_path(pid_t pid, char **ret_path); int cg_pidref_get_unit_full(const PidRef *pidref, char **ret_unit, char **ret_subgroup); static inline int cg_pidref_get_unit(const PidRef *pidref, char **ret_unit) { return cg_pidref_get_unit_full(pidref, ret_unit, /* ret_subgroup= */ NULL); } +int cg_pidref_get_unit_path(const PidRef *pidref, char **ret_path); int cg_pid_get_user_unit_full(pid_t pid, char **ret_unit, char **ret_subgroup); static inline int cg_pid_get_user_unit(pid_t pid, char **ret_unit) { return cg_pid_get_user_unit_full(pid, ret_unit, /* ret_subgroup= */ NULL); } +int cg_pid_get_user_unit_path(pid_t pid, char **ret_path); int cg_pidref_get_user_unit_full(const PidRef *pidref, char **ret_unit, char **ret_subgroup); static inline int cg_pidref_get_user_unit(const PidRef *pidref, char **ret_unit) { return cg_pidref_get_user_unit_full(pidref, ret_unit, /* ret_subgroup= */ NULL); } +int cg_pidref_get_user_unit_path(const PidRef *pidref, char **ret_path); int cg_pid_get_machine_name(pid_t pid, char **ret_machine); +int cg_pidref_get_machine_name(const PidRef *pidref, char **ret_machine); int cg_pid_get_slice(pid_t pid, char **ret_slice); +int cg_pidref_get_slice(const PidRef *pidref, char **ret_slice); int cg_pid_get_user_slice(pid_t pid, char **ret_slice); +int cg_pidref_get_user_slice(const PidRef *pidref, char **ret_slice); int cg_path_decode_unit(const char *cgroup, char **ret_unit); 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..41c39913b7f 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; @@ -356,55 +436,55 @@ _public_ int sd_peer_get_unit(int fd, char **ret_unit) { } _public_ int sd_peer_get_user_unit(int fd, char **ret_unit) { - struct ucred ucred; int r; assert_return(fd >= 0, -EBADF); - r = getpeercred(fd, &ucred); + _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL; + r = getpeerpidref(fd, &pidref); if (r < 0) return r; - return cg_pid_get_user_unit(ucred.pid, ret_unit); + return cg_pidref_get_user_unit(&pidref, ret_unit); } _public_ int sd_peer_get_machine_name(int fd, char **ret_machine) { - struct ucred ucred; int r; assert_return(fd >= 0, -EBADF); - r = getpeercred(fd, &ucred); + _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL; + r = getpeerpidref(fd, &pidref); if (r < 0) return r; - return cg_pid_get_machine_name(ucred.pid, ret_machine); + return cg_pidref_get_machine_name(&pidref, ret_machine); } _public_ int sd_peer_get_slice(int fd, char **ret_slice) { - struct ucred ucred; int r; assert_return(fd >= 0, -EBADF); - r = getpeercred(fd, &ucred); + _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL; + r = getpeerpidref(fd, &pidref); if (r < 0) return r; - return cg_pid_get_slice(ucred.pid, ret_slice); + return cg_pidref_get_slice(&pidref, ret_slice); } _public_ int sd_peer_get_user_slice(int fd, char **ret_slice) { - struct ucred ucred; int r; assert_return(fd >= 0, -EBADF); - r = getpeercred(fd, &ucred); + _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL; + r = getpeerpidref(fd, &pidref); if (r < 0) return r; - return cg_pid_get_user_slice(ucred.pid, ret_slice); + return cg_pidref_get_user_slice(&pidref, ret_slice); } _public_ int sd_peer_get_cgroup(int fd, char **ret_cgroup) { @@ -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 f625055e1fe..e5851bb8ddb 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(), /* flags= */ 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); diff --git a/src/test/test-cgroup-util.c b/src/test/test-cgroup-util.c index 5f89fd6ba77..224983272ac 100644 --- a/src/test/test-cgroup-util.c +++ b/src/test/test-cgroup-util.c @@ -148,6 +148,33 @@ TEST(path_get_user_unit) { check_p_g_u_u("/capsule.slice/capsule@#.service/foo.slice/foo-bar.slice/run-p9-i1.service", -ENXIO, /* result= */ NULL); } +static void check_p_g_u_u_p(const char *path, int code, const char *result) { + _cleanup_free_ char *unit_path = NULL; + int r; + + r = cg_path_get_user_unit_path(path, &unit_path); + printf("%s: %s → %s %d expected %s %d\n", __func__, path, unit_path, r, strnull(result), code); + ASSERT_EQ(r, code); + ASSERT_STREQ(unit_path, result); +} + +TEST(path_get_user_unit_path) { + check_p_g_u_u_p("/user.slice/user-1000.slice/user@1000.service/app.slice/foobar.service", 0, "/user.slice/user-1000.slice/user@1000.service/app.slice/foobar.service"); + check_p_g_u_u_p("/user.slice/user-1000.slice/user@1000.service/app.slice/foobar.service/", 0, "/user.slice/user-1000.slice/user@1000.service/app.slice/foobar.service"); + check_p_g_u_u_p("/user.slice/user-1000.slice/user@1000.service/app.slice/foobar.service/asdf", 0, "/user.slice/user-1000.slice/user@1000.service/app.slice/foobar.service"); + check_p_g_u_u_p("/user.slice/user-1000.slice/user@1000.service/app.slice/foobar@baz.service", 0, "/user.slice/user-1000.slice/user@1000.service/app.slice/foobar@baz.service"); + check_p_g_u_u_p("/user.slice/user-1000.slice/user@1000.service/app.slice/foobar@baz.service/asdf", 0, "/user.slice/user-1000.slice/user@1000.service/app.slice/foobar@baz.service"); + check_p_g_u_u_p("/user.slice/user-1000.slice/user@1000.service/app.slice/_cpu.service", 0, "/user.slice/user-1000.slice/user@1000.service/app.slice/_cpu.service"); + check_p_g_u_u_p("/user.slice/user-1000.slice/user@1000.service/app.slice/_cpu.service/asdf", 0, "/user.slice/user-1000.slice/user@1000.service/app.slice/_cpu.service"); + check_p_g_u_u_p("/user.slice/user-1000.slice/user@1000.service/app.slice/example.slice/foobar.service", 0, "/user.slice/user-1000.slice/user@1000.service/app.slice/example.slice/foobar.service"); + check_p_g_u_u_p("/capsule.slice/capsule@test.service/app.slice/foobar.service", 0, "/capsule.slice/capsule@test.service/app.slice/foobar.service"); + check_p_g_u_u_p("/user.slice/user-1000.slice/session-2.scope/foobar.service", 0, "/user.slice/user-1000.slice/session-2.scope/foobar.service"); + check_p_g_u_u_p("sadfdsafsda", -ENXIO, NULL); + check_p_g_u_u_p("/user.slice/user-1000.slice/user@1000.service/app.slice/foo###bar.service", -ENXIO, NULL); + check_p_g_u_u_p("/user.slice/user-1000.slice/user@1000.service/app.slice/foobar@.service", -ENXIO, NULL); + check_p_g_u_u_p("/system.slice/foobar.service", -ENXIO, NULL); +} + static void check_p_g_s(const char *path, int code, const char *result) { _cleanup_free_ char *s = NULL;