]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-login: add sd_pidfd_* APIs 26114/head
authorLuca Boccassi <bluca@debian.org>
Thu, 19 Jan 2023 23:20:55 +0000 (23:20 +0000)
committerLuca Boccassi <bluca@debian.org>
Fri, 20 Jan 2023 12:18:05 +0000 (12:18 +0000)
Same as the sd_pid_* counterparts, but take a pid file descriptor instead of
a pid, so that the callers can be sure that the returned values are really
about the process they asked for, and not about a recycled PID.

man/rules/meson.build
man/sd_pid_get_owner_uid.xml
src/libsystemd/libsystemd.sym
src/libsystemd/sd-login/sd-login.c
src/libsystemd/sd-login/test-login.c
src/systemd/sd-login.h

index 90324fe1ecf82a60e05f9603e99149e7dd69ebaf..194cc0b904c58c245a5635055ba5de83ea3226da 100644 (file)
@@ -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',
index c516083a5b9303447714f1a6146695e9b67de69c..5ce5a19144a3fcda6b8c66c9523a4e7e7d800c5f 100644 (file)
     <refname>sd_pid_get_slice</refname>
     <refname>sd_pid_get_user_slice</refname>
     <refname>sd_pid_get_cgroup</refname>
+    <refname>sd_pidfd_get_owner_uid</refname>
+    <refname>sd_pidfd_get_session</refname>
+    <refname>sd_pidfd_get_user_unit</refname>
+    <refname>sd_pidfd_get_unit</refname>
+    <refname>sd_pidfd_get_machine_name</refname>
+    <refname>sd_pidfd_get_slice</refname>
+    <refname>sd_pidfd_get_user_slice</refname>
+    <refname>sd_pidfd_get_cgroup</refname>
     <refname>sd_peer_get_owner_uid</refname>
     <refname>sd_peer_get_session</refname>
     <refname>sd_peer_get_user_unit</refname>
         <paramdef>char **<parameter>cgroup</parameter></paramdef>
       </funcprototype>
 
+      <funcprototype>
+        <funcdef>int <function>sd_pidfd_get_owner_uid</function></funcdef>
+        <paramdef>int <parameter>pidfd</parameter></paramdef>
+        <paramdef>uid_t *<parameter>uid</parameter></paramdef>
+      </funcprototype>
+
+      <funcprototype>
+        <funcdef>int <function>sd_pidfd_get_session</function></funcdef>
+        <paramdef>int <parameter>pidfd</parameter></paramdef>
+        <paramdef>char **<parameter>session</parameter></paramdef>
+      </funcprototype>
+
+      <funcprototype>
+        <funcdef>int <function>sd_pidfd_get_user_unit</function></funcdef>
+        <paramdef>int <parameter>pidfd</parameter></paramdef>
+        <paramdef>char **<parameter>unit</parameter></paramdef>
+      </funcprototype>
+
+      <funcprototype>
+        <funcdef>int <function>sd_pidfd_get_unit</function></funcdef>
+        <paramdef>int <parameter>pidfd</parameter></paramdef>
+        <paramdef>char **<parameter>unit</parameter></paramdef>
+      </funcprototype>
+
+      <funcprototype>
+        <funcdef>int <function>sd_pidfd_get_machine_name</function></funcdef>
+        <paramdef>int <parameter>pidfd</parameter></paramdef>
+        <paramdef>char **<parameter>name</parameter></paramdef>
+      </funcprototype>
+
+      <funcprototype>
+        <funcdef>int <function>sd_pidfd_get_slice</function></funcdef>
+        <paramdef>int <parameter>pidfd</parameter></paramdef>
+        <paramdef>char **<parameter>slice</parameter></paramdef>
+      </funcprototype>
+
+      <funcprototype>
+        <funcdef>int <function>sd_pidfd_get_user_slice</function></funcdef>
+        <paramdef>int <parameter>pidfd</parameter></paramdef>
+        <paramdef>char **<parameter>slice</parameter></paramdef>
+      </funcprototype>
+
+      <funcprototype>
+        <funcdef>int <function>sd_pidfd_get_cgroup</function></funcdef>
+        <paramdef>int <parameter>pidfd</parameter></paramdef>
+        <paramdef>char **<parameter>cgroup</parameter></paramdef>
+      </funcprototype>
+
       <funcprototype>
         <funcdef>int <function>sd_peer_get_owner_uid</function></funcdef>
         <paramdef>int <parameter>fd</parameter></paramdef>
     functions is passed as 0, the operation is executed for the
     calling process.</para>
 
+    <para>The <function>sd_pidfd_get_owner_uid()</function>,
+    <function>sd_pidfd_get_session()</function>,
+    <function>sd_pidfd_get_user_unit()</function>,
+    <function>sd_pidfd_get_unit()</function>,
+    <function>sd_pidfd_get_machine_name()</function>,
+    <function>sd_pidfd_get_slice()</function>,
+    <function>sd_pidfd_get_user_slice()</function> and
+    <function>sd_pidfd_get_cgroup()</function> calls operate similarly to their PID counterparts, but accept a
+    <constant>PIDFD</constant> instead of a <constant>PID</constant>, 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 <constant>PIDFD</constant>. A suitable file descriptor may be
+    acquired via
+    <citerefentry project='man-pages'><refentrytitle>pidfd_open</refentrytitle><manvolnum>2</manvolnum></citerefentry>.</para>
+
     <para>The <function>sd_peer_get_owner_uid()</function>,
     <function>sd_peer_get_session()</function>,
     <function>sd_peer_get_user_unit()</function>,
index 07acb992717e59b4f6dd6aa67e149264f67c62d0..0f2230a42f97afbb09dc4a4e463ea41f856181d9 100644 (file)
@@ -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;
index 90b5ebb4b7f9a056f898a6c376dd4f912fdaf4e3..d483889fd18531c8bc8d3dadd2fa65a6531d2041 100644 (file)
@@ -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;
index 96a8c567fc7654204a7f05902a1ed79c2de693ea..1710cdeb919b7d03cb35bf0e11cbf0e4421a368f 100644 (file)
@@ -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)
index 54970532eca8a63394090763176bbeec9cc0ce3c..85dd086e2b94e384887d849a166bc9256c89bf78 100644 (file)
@@ -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);