diff --git a/man/rules/meson.build b/man/rules/meson.build
index 90324fe1ec..194cc0b904 100644
--- a/man/rules/meson.build
+++ b/man/rules/meson.build
@@ -815,7 +815,15 @@ manpages = [
'sd_pid_get_slice',
'sd_pid_get_unit',
'sd_pid_get_user_slice',
- 'sd_pid_get_user_unit'],
+ 'sd_pid_get_user_unit',
+ '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_user_slice',
+ 'sd_pidfd_get_user_unit'],
'HAVE_PAM'],
['sd_seat_get_active',
'3',
diff --git a/man/sd_pid_get_owner_uid.xml b/man/sd_pid_get_owner_uid.xml
index c516083a5b..5ce5a19144 100644
--- a/man/sd_pid_get_owner_uid.xml
+++ b/man/sd_pid_get_owner_uid.xml
@@ -25,6 +25,14 @@
sd_pid_get_slice
sd_pid_get_user_slice
sd_pid_get_cgroup
+ sd_pidfd_get_owner_uid
+ sd_pidfd_get_session
+ sd_pidfd_get_user_unit
+ sd_pidfd_get_unit
+ sd_pidfd_get_machine_name
+ sd_pidfd_get_slice
+ sd_pidfd_get_user_slice
+ sd_pidfd_get_cgroup
sd_peer_get_owner_uid
sd_peer_get_session
sd_peer_get_user_unit
@@ -90,6 +98,54 @@
char **cgroup
+
+ int sd_pidfd_get_owner_uid
+ int pidfd
+ uid_t *uid
+
+
+
+ int sd_pidfd_get_session
+ int pidfd
+ char **session
+
+
+
+ int sd_pidfd_get_user_unit
+ int pidfd
+ char **unit
+
+
+
+ int sd_pidfd_get_unit
+ int pidfd
+ char **unit
+
+
+
+ int sd_pidfd_get_machine_name
+ int pidfd
+ char **name
+
+
+
+ int sd_pidfd_get_slice
+ int pidfd
+ char **slice
+
+
+
+ int sd_pidfd_get_user_slice
+ int pidfd
+ char **slice
+
+
+
+ int sd_pidfd_get_cgroup
+ int pidfd
+ char **cgroup
+
+
int sd_peer_get_owner_uid
int fd
@@ -222,6 +278,20 @@
functions is passed as 0, the operation is executed for the
calling process.
+ The sd_pidfd_get_owner_uid(),
+ sd_pidfd_get_session(),
+ sd_pidfd_get_user_unit(),
+ 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
+ pidfd_open2.
+
The sd_peer_get_owner_uid(),
sd_peer_get_session(),
sd_peer_get_user_unit(),
diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym
index 07acb99271..0f2230a42f 100644
--- a/src/libsystemd/libsystemd.sym
+++ b/src/libsystemd/libsystemd.sym
@@ -802,4 +802,12 @@ global:
sd_bus_emit_signal_to;
sd_bus_emit_signal_tov;
sd_bus_message_new_signal_to;
+ 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_user_slice;
+ sd_pidfd_get_user_unit;
} LIBSYSTEMD_252;
diff --git a/src/libsystemd/sd-login/sd-login.c b/src/libsystemd/sd-login/sd-login.c
index 90b5ebb4b7..d483889fd1 100644
--- a/src/libsystemd/sd-login/sd-login.c
+++ b/src/libsystemd/sd-login/sd-login.c
@@ -22,6 +22,7 @@
#include "macro.h"
#include "parse-util.h"
#include "path-util.h"
+#include "process-util.h"
#include "socket-util.h"
#include "stdio-util.h"
#include "string-util.h"
@@ -134,6 +135,206 @@ _public_ int sd_pid_get_cgroup(pid_t pid, char **cgroup) {
return 0;
}
+_public_ int sd_pidfd_get_session(int pidfd, char **ret_session) {
+ _cleanup_free_ char *session = NULL;
+ pid_t pid;
+ int r;
+
+ assert_return(pidfd >= 0, -EBADF);
+ assert_return(ret_session, -EINVAL);
+
+ r = pidfd_get_pid(pidfd, &pid);
+ if (r < 0)
+ return r;
+
+ r = sd_pid_get_session(pid, &session);
+ if (r < 0)
+ return r;
+
+ r = pidfd_verify_pid(pidfd, pid);
+ if (r < 0)
+ return r;
+
+ *ret_session = TAKE_PTR(session);
+
+ return 0;
+}
+
+_public_ int sd_pidfd_get_unit(int pidfd, char **ret_unit) {
+ _cleanup_free_ char *unit = NULL;
+ pid_t pid;
+ int r;
+
+ assert_return(pidfd >= 0, -EBADF);
+ assert_return(ret_unit, -EINVAL);
+
+ r = pidfd_get_pid(pidfd, &pid);
+ if (r < 0)
+ return r;
+
+ r = sd_pid_get_unit(pid, &unit);
+ if (r < 0)
+ return r;
+
+ r = pidfd_verify_pid(pidfd, pid);
+ if (r < 0)
+ return r;
+
+ *ret_unit = TAKE_PTR(unit);
+
+ return 0;
+}
+
+_public_ int sd_pidfd_get_user_unit(int pidfd, char **ret_unit) {
+ _cleanup_free_ char *unit = NULL;
+ pid_t pid;
+ int r;
+
+ assert_return(pidfd >= 0, -EBADF);
+ assert_return(ret_unit, -EINVAL);
+
+ r = pidfd_get_pid(pidfd, &pid);
+ if (r < 0)
+ return r;
+
+ r = sd_pid_get_user_unit(pid, &unit);
+ if (r < 0)
+ return r;
+
+ r = pidfd_verify_pid(pidfd, pid);
+ if (r < 0)
+ return r;
+
+ *ret_unit = TAKE_PTR(unit);
+
+ return 0;
+}
+
+_public_ int sd_pidfd_get_machine_name(int pidfd, char **ret_name) {
+ _cleanup_free_ char *name = NULL;
+ pid_t pid;
+ int r;
+
+ assert_return(pidfd >= 0, -EBADF);
+ assert_return(ret_name, -EINVAL);
+
+ r = pidfd_get_pid(pidfd, &pid);
+ if (r < 0)
+ return r;
+
+ r = sd_pid_get_machine_name(pid, &name);
+ if (r < 0)
+ return r;
+
+ r = pidfd_verify_pid(pidfd, pid);
+ if (r < 0)
+ return r;
+
+ *ret_name = TAKE_PTR(name);
+
+ return 0;
+}
+
+_public_ int sd_pidfd_get_slice(int pidfd, char **ret_slice) {
+ _cleanup_free_ char *slice = NULL;
+ pid_t pid;
+ int r;
+
+ assert_return(pidfd >= 0, -EBADF);
+ assert_return(ret_slice, -EINVAL);
+
+ r = pidfd_get_pid(pidfd, &pid);
+ if (r < 0)
+ return r;
+
+ r = sd_pid_get_slice(pid, &slice);
+ if (r < 0)
+ return r;
+
+ r = pidfd_verify_pid(pidfd, pid);
+ if (r < 0)
+ return r;
+
+ *ret_slice = TAKE_PTR(slice);
+
+ return 0;
+}
+
+_public_ int sd_pidfd_get_user_slice(int pidfd, char **ret_slice) {
+ _cleanup_free_ char *slice = NULL;
+ pid_t pid;
+ int r;
+
+ assert_return(pidfd >= 0, -EBADF);
+ assert_return(ret_slice, -EINVAL);
+
+ r = pidfd_get_pid(pidfd, &pid);
+ if (r < 0)
+ return r;
+
+ r = sd_pid_get_user_slice(pid, &slice);
+ if (r < 0)
+ return r;
+
+ r = pidfd_verify_pid(pidfd, pid);
+ if (r < 0)
+ return r;
+
+ *ret_slice = TAKE_PTR(slice);
+
+ return 0;
+}
+
+_public_ int sd_pidfd_get_owner_uid(int pidfd, uid_t *ret_uid) {
+ uid_t uid;
+ pid_t pid;
+ int r;
+
+ assert_return(pidfd >= 0, -EINVAL);
+ assert_return(ret_uid, -EINVAL);
+
+ r = pidfd_get_pid(pidfd, &pid);
+ if (r < 0)
+ return r;
+
+ r = sd_pid_get_owner_uid(pid, &uid);
+ if (r < 0)
+ return r;
+
+ r = pidfd_verify_pid(pidfd, pid);
+ if (r < 0)
+ return r;
+
+ *ret_uid = uid;
+
+ return 0;
+}
+
+_public_ int sd_pidfd_get_cgroup(int pidfd, char **ret_cgroup) {
+ _cleanup_free_ char *cgroup = NULL;
+ pid_t pid;
+ int r;
+
+ assert_return(pidfd >= 0, -EBADF);
+ assert_return(ret_cgroup, -EINVAL);
+
+ r = pidfd_get_pid(pidfd, &pid);
+ if (r < 0)
+ return r;
+
+ r = sd_pid_get_cgroup(pid, &cgroup);
+ if (r < 0)
+ return r;
+
+ r = pidfd_verify_pid(pidfd, pid);
+ if (r < 0)
+ return r;
+
+ *ret_cgroup = TAKE_PTR(cgroup);
+
+ return 0;
+}
+
_public_ int sd_peer_get_session(int fd, char **session) {
struct ucred ucred = UCRED_INVALID;
int r;
diff --git a/src/libsystemd/sd-login/test-login.c b/src/libsystemd/sd-login/test-login.c
index 96a8c567fc..1710cdeb91 100644
--- a/src/libsystemd/sd-login/test-login.c
+++ b/src/libsystemd/sd-login/test-login.c
@@ -9,6 +9,8 @@
#include "fd-util.h"
#include "format-util.h"
#include "log.h"
+#include "missing_syscall.h"
+#include "process-util.h"
#include "string-util.h"
#include "strv.h"
#include "tests.h"
@@ -44,6 +46,7 @@ TEST(login) {
*type = NULL, *class = NULL, *state = NULL, *state2 = NULL,
*seat = NULL, *session = NULL,
*unit = NULL, *user_unit = NULL, *slice = NULL;
+ _cleanup_close_ int pidfd = -EBADFD;
int r;
uid_t u, u2 = UID_INVALID;
char *t, **seats = NULL, **sessions = NULL;
@@ -71,6 +74,35 @@ TEST(login) {
log_info("sd_pid_get_cgroup(0, …) → %s / \"%s\"", e(r), strnull(cgroup));
assert_se(IN_SET(r, 0, -ENOMEDIUM));
+ pidfd = pidfd_open(getpid_cached(), 0);
+ if (pidfd >= 0) {
+ _cleanup_free_ char *cgroup2 = NULL, *session2 = NULL,
+ *unit2 = NULL, *user_unit2 = NULL, *slice2 = NULL;
+
+ r = sd_pidfd_get_unit(pidfd, &unit2);
+ log_info("sd_pidfd_get_unit(pidfd, …) → %s / \"%s\"", e(r), strnull(unit2));
+ 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_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_se(IN_SET(r, 0, -ENODATA));
+
+ r = sd_pidfd_get_owner_uid(pidfd, &u2);
+ log_info("sd_pidfd_get_owner_uid(pidfd, …) → %s / "UID_FMT, e(r), u2);
+ assert_se(IN_SET(r, 0, -ENODATA));
+
+ r = sd_pidfd_get_session(pidfd, &session2);
+ log_info("sd_pidfd_get_session(pidfd, …) → %s / \"%s\"", e(r), strnull(session2));
+
+ r = sd_pidfd_get_cgroup(pidfd, &cgroup2);
+ log_info("sd_pidfd_get_cgroup(pidfd, …) → %s / \"%s\"", e(r), strnull(cgroup2));
+ assert_se(IN_SET(r, 0, -ENOMEDIUM));
+ }
+
r = sd_uid_get_display(u2, &display_session);
log_info("sd_uid_get_display("UID_FMT", …) → %s / \"%s\"", u2, e(r), strnull(display_session));
if (u2 == UID_INVALID)
diff --git a/src/systemd/sd-login.h b/src/systemd/sd-login.h
index 54970532ec..85dd086e2b 100644
--- a/src/systemd/sd-login.h
+++ b/src/systemd/sd-login.h
@@ -80,6 +80,18 @@ int sd_pid_get_machine_name(pid_t pid, char **machine);
* hierarchy. */
int sd_pid_get_cgroup(pid_t pid, char **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. */
+int sd_pidfd_get_session(pid_t pid, char **session);
+int sd_pidfd_get_owner_uid(pid_t pid, uid_t *uid);
+int sd_pidfd_get_unit(pid_t pid, char **unit);
+int sd_pidfd_get_user_unit(pid_t pid, char **unit);
+int sd_pidfd_get_slice(pid_t pid, char **slice);
+int sd_pidfd_get_user_slice(pid_t pid, char **slice);
+int sd_pidfd_get_machine_name(pid_t pid, char **machine);
+int sd_pidfd_get_cgroup(pid_t pid, char **cgroup);
+
/* Similar to sd_pid_get_session(), but retrieves data about the peer
* of a connected AF_UNIX socket */
int sd_peer_get_session(int fd, char **session);