]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-bus: add pidfd to the sd_bus_creds structure
authorLennart Poettering <lennart@poettering.net>
Fri, 26 Jan 2024 15:46:09 +0000 (16:46 +0100)
committerLennart Poettering <lennart@poettering.net>
Mon, 29 Jan 2024 13:41:58 +0000 (14:41 +0100)
Let's continue with the pidfd'ification, and include pidfd in our
sd_bus_creds structure tha tracks a peers credentials.

12 files changed:
src/libsystemd/libsystemd.sym
src/libsystemd/sd-bus/bus-control.c
src/libsystemd/sd-bus/bus-creds.c
src/libsystemd/sd-bus/bus-creds.h
src/libsystemd/sd-bus/bus-dump.c
src/libsystemd/sd-bus/bus-internal.h
src/libsystemd/sd-bus/bus-message.c
src/libsystemd/sd-bus/bus-socket.c
src/libsystemd/sd-bus/sd-bus.c
src/libsystemd/sd-bus/test-bus-creds.c
src/libsystemd/sd-bus/test-bus-peersockaddr.c
src/systemd/sd-bus.h

index 4113920ee045bd56e1bb7333eed6d0b79682bb07..22cf48c5f8db7b05c3479edf595d243a360b9a46 100644 (file)
@@ -834,3 +834,9 @@ global:
         sd_id128_get_app_specific;
         sd_device_enumerator_add_match_property_required;
 } LIBSYSTEMD_254;
+
+LIBSYSTEMD_256 {
+global:
+        sd_bus_creds_get_pidfd_dup;
+        sd_bus_creds_new_from_pidfd;
+} LIBSYSTEMD_255;
index 1355e41ed08c6eb420ca91aa8543a767cc8adb3e..3b11d754a22aaaa9d586f73b6eaa9a721f423851 100644 (file)
@@ -14,6 +14,7 @@
 #include "bus-internal.h"
 #include "bus-message.h"
 #include "capability-util.h"
+#include "fd-util.h"
 #include "process-util.h"
 #include "stdio-util.h"
 #include "string-util.h"
@@ -430,7 +431,6 @@ _public_ int sd_bus_get_name_creds(
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply_unique = NULL, *reply = NULL;
         _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
         const char *unique;
-        pid_t pid = 0;
         int r;
 
         assert_return(bus, -EINVAL);
@@ -484,7 +484,8 @@ _public_ int sd_bus_get_name_creds(
 
         if (mask != 0) {
                 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-                bool need_pid, need_uid, need_selinux, need_separate_calls;
+                bool need_pid, need_uid, need_selinux, need_separate_calls, need_pidfd, need_augment;
+                _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
 
                 c = bus_creds_new();
                 if (!c)
@@ -498,20 +499,24 @@ _public_ int sd_bus_get_name_creds(
                         c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
                 }
 
-                need_pid = (mask & SD_BUS_CREDS_PID) ||
-                        ((mask & SD_BUS_CREDS_AUGMENT) &&
-                         (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
-                                  SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
-                                  SD_BUS_CREDS_SUPPLEMENTARY_GIDS|
-                                  SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
-                                  SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID|
-                                  SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
-                                  SD_BUS_CREDS_SELINUX_CONTEXT|
-                                  SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)));
+                need_augment =
+                        (mask & SD_BUS_CREDS_AUGMENT) &&
+                        (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID|
+                                 SD_BUS_CREDS_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
+                                 SD_BUS_CREDS_SUPPLEMENTARY_GIDS|
+                                 SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE|
+                                 SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID|
+                                 SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS|
+                                 SD_BUS_CREDS_SELINUX_CONTEXT|
+                                 SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID|
+                                 SD_BUS_CREDS_PIDFD));
+
+                need_pid = (mask & SD_BUS_CREDS_PID) || need_augment;
                 need_uid = mask & SD_BUS_CREDS_EUID;
                 need_selinux = mask & SD_BUS_CREDS_SELINUX_CONTEXT;
+                need_pidfd = (mask & SD_BUS_CREDS_PIDFD) || need_augment;
 
-                if (need_pid + need_uid + need_selinux > 1) {
+                if (need_pid + need_uid + need_selinux + need_pidfd > 1) {
 
                         /* If we need more than one of the credentials, then use GetConnectionCredentials() */
 
@@ -572,7 +577,9 @@ _public_ int sd_bus_get_name_creds(
                                                 if (r < 0)
                                                         return r;
 
-                                                pid = p;
+                                                if (!pidref_is_set(&pidref))
+                                                        pidref = PIDREF_MAKE_FROM_PID(p);
+
                                                 if (mask & SD_BUS_CREDS_PID) {
                                                         c->pid = p;
                                                         c->mask |= SD_BUS_CREDS_PID;
@@ -599,6 +606,26 @@ _public_ int sd_bus_get_name_creds(
                                                 r = sd_bus_message_exit_container(reply);
                                                 if (r < 0)
                                                         return r;
+                                        } else if (need_pidfd && streq(m, "ProcessFD")) {
+                                                int fd;
+
+                                                r = sd_bus_message_read(reply, "v", "h", &fd);
+                                                if (r < 0)
+                                                        return r;
+
+                                                pidref_done(&pidref);
+                                                r = pidref_set_pidfd(&pidref, fd);
+                                                if (r < 0)
+                                                        return r;
+
+                                                if (mask & SD_BUS_CREDS_PIDFD) {
+                                                        fd = fcntl(fd, F_DUPFD_CLOEXEC, 3);
+                                                        if (fd < 0)
+                                                                return -errno;
+
+                                                        close_and_replace(c->pidfd, fd);
+                                                        c->mask |= SD_BUS_CREDS_PIDFD;
+                                                }
                                         } else {
                                                 r = sd_bus_message_skip(reply, "v");
                                                 if (r < 0)
@@ -614,7 +641,7 @@ _public_ int sd_bus_get_name_creds(
                                 if (r < 0)
                                         return r;
 
-                                if (need_pid && pid == 0)
+                                if (need_pid && !pidref_is_set(&pidref))
                                         return -EPROTO;
                         }
 
@@ -642,7 +669,9 @@ _public_ int sd_bus_get_name_creds(
                                 if (r < 0)
                                         return r;
 
-                                pid = u;
+                                if (!pidref_is_set(&pidref))
+                                        pidref = PIDREF_MAKE_FROM_PID(u);
+
                                 if (mask & SD_BUS_CREDS_PID) {
                                         c->pid = u;
                                         c->mask |= SD_BUS_CREDS_PID;
@@ -710,9 +739,11 @@ _public_ int sd_bus_get_name_creds(
                         }
                 }
 
-                r = bus_creds_add_more(c, mask, pid, 0);
-                if (r < 0 && r != -ESRCH) /* Return the error, but ignore ESRCH which just means the process is already gone */
-                        return r;
+                if (pidref_is_set(&pidref)) {
+                        r = bus_creds_add_more(c, mask, &pidref, 0);
+                        if (r < 0 && r != -ESRCH) /* Return the error, but ignore ESRCH which just means the process is already gone */
+                                return r;
+                }
         }
 
         if (creds)
@@ -765,8 +796,8 @@ not_found:
 
 _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **ret) {
         _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
-        bool do_label, do_groups, do_sockaddr_peer;
-        pid_t pid = 0;
+        _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
+        bool do_label, do_groups, do_sockaddr_peer, do_pidfd;
         int r;
 
         assert_return(bus, -EINVAL);
@@ -786,9 +817,10 @@ _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **r
         do_sockaddr_peer = bus->sockaddr_size_peer >= offsetof(struct sockaddr_un, sun_path) + 1 &&
                 bus->sockaddr_peer.sa.sa_family == AF_UNIX &&
                 bus->sockaddr_peer.un.sun_path[0] == 0;
+        do_pidfd = bus->pidfd >= 0 && (mask & SD_BUS_CREDS_PIDFD);
 
         /* Avoid allocating anything if we have no chance of returning useful data */
-        if (!bus->ucred_valid && !do_label && !do_groups && !do_sockaddr_peer)
+        if (!bus->ucred_valid && !do_label && !do_groups && !do_sockaddr_peer && !do_pidfd)
                 return -ENODATA;
 
         c = bus_creds_new();
@@ -797,8 +829,10 @@ _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **r
 
         if (bus->ucred_valid) {
                 if (pid_is_valid(bus->ucred.pid)) {
-                        pid = c->pid = bus->ucred.pid;
+                        c->pid = bus->ucred.pid;
                         c->mask |= SD_BUS_CREDS_PID & mask;
+
+                        pidref = PIDREF_MAKE_FROM_PID(c->pid);
                 }
 
                 if (uid_is_valid(bus->ucred.uid)) {
@@ -859,7 +893,20 @@ _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **r
                 }
         }
 
-        r = bus_creds_add_more(c, mask, pid, 0);
+        if (do_pidfd) {
+                c->pidfd = fcntl(bus->pidfd, F_DUPFD_CLOEXEC, 3);
+                if (c->pidfd < 0)
+                        return -errno;
+
+                pidref_done(&pidref);
+                r = pidref_set_pidfd(&pidref, bus->pidfd);
+                if (r < 0)
+                        return r;
+
+                c->mask |= SD_BUS_CREDS_PIDFD;
+        }
+
+        r = bus_creds_add_more(c, mask, &pidref, 0);
         if (r < 0 && r != -ESRCH) /* If the process vanished, then don't complain, just return what we got */
                 return r;
 
index 33ae2a00f6859c329d850d7ef067955109b39880..adbdeaa210e6e1e31bf9fcfc6842078f3d9b2c00 100644 (file)
@@ -53,6 +53,8 @@ void bus_creds_done(sd_bus_creds *c) {
                                     * below. */
 
         strv_free(c->cmdline_array);
+
+        safe_close(c->pidfd);
 }
 
 _public_ sd_bus_creds *sd_bus_creds_ref(sd_bus_creds *c) {
@@ -129,46 +131,72 @@ _public_ uint64_t sd_bus_creds_get_augmented_mask(const sd_bus_creds *c) {
 sd_bus_creds* bus_creds_new(void) {
         sd_bus_creds *c;
 
-        c = new0(sd_bus_creds, 1);
+        c = new(sd_bus_creds, 1);
         if (!c)
                 return NULL;
 
-        c->allocated = true;
-        c->n_ref = 1;
+        *c = (sd_bus_creds) {
+                .allocated = true,
+                .n_ref = 1,
+                SD_BUS_CREDS_INIT_FIELDS,
+        };
+
         return c;
 }
 
-_public_ int sd_bus_creds_new_from_pid(sd_bus_creds **ret, pid_t pid, uint64_t mask) {
+static int bus_creds_new_from_pidref(sd_bus_creds **ret, PidRef *pidref, uint64_t mask) {
         _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
         int r;
 
-        assert_return(pid >= 0, -EINVAL);
         assert_return(mask <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
         assert_return(ret, -EINVAL);
 
-        if (pid == 0)
-                pid = getpid_cached();
-
         c = bus_creds_new();
         if (!c)
                 return -ENOMEM;
 
-        r = bus_creds_add_more(c, mask | SD_BUS_CREDS_AUGMENT, pid, 0);
+        r = bus_creds_add_more(c, mask | SD_BUS_CREDS_AUGMENT, pidref, 0);
         if (r < 0)
                 return r;
 
-        /* Check if the process existed at all, in case we haven't
-         * figured that out already */
-        r = pid_is_alive(pid);
+        r = pidref_verify(pidref);
         if (r < 0)
                 return r;
-        if (r == 0)
-                return -ESRCH;
 
         *ret = TAKE_PTR(c);
         return 0;
 }
 
+_public_ int sd_bus_creds_new_from_pid(sd_bus_creds **ret, pid_t pid, uint64_t mask) {
+        _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
+        int r;
+
+        assert_return(pid >= 0, -EINVAL);
+        assert_return(mask <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
+        assert_return(ret, -EINVAL);
+
+        r = pidref_set_pid(&pidref, pid);
+        if (r < 0)
+                return r;
+
+        return bus_creds_new_from_pidref(ret, &pidref, mask);
+}
+
+_public_ int sd_bus_creds_new_from_pidfd(sd_bus_creds **ret, int pidfd, uint64_t mask) {
+        _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
+        int r;
+
+        assert_return(mask <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
+        assert_return(ret, -EINVAL);
+        assert_return(pidfd >= 0, -EBADF);
+
+        r = pidref_set_pidfd(&pidref, pidfd);
+        if (r < 0)
+                return r;
+
+        return bus_creds_new_from_pidref(ret, &pidref, mask);
+}
+
 _public_ int sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid) {
         assert_return(c, -EINVAL);
         assert_return(uid, -EINVAL);
@@ -280,6 +308,23 @@ _public_ int sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid) {
         return 0;
 }
 
+_public_ int sd_bus_creds_get_pidfd_dup(sd_bus_creds *c, int *ret_fd) {
+        _cleanup_close_ int copy = -EBADF;
+
+        assert_return(c, -EINVAL);
+        assert_return(ret_fd, -EINVAL);
+
+        if (!(c->mask & SD_BUS_CREDS_PIDFD))
+                return -ENODATA;
+
+        copy = fcntl(c->pidfd, F_DUPFD_CLOEXEC, 3);
+        if (copy < 0)
+                return -errno;
+
+        *ret_fd = TAKE_FD(copy);
+        return 0;
+}
+
 _public_ int sd_bus_creds_get_ppid(sd_bus_creds *c, pid_t *ppid) {
         assert_return(c, -EINVAL);
         assert_return(ppid, -EINVAL);
@@ -750,7 +795,8 @@ static int parse_caps(sd_bus_creds *c, unsigned offset, const char *p) {
         return 0;
 }
 
-int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
+int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, PidRef *pidref, pid_t tid) {
+        _cleanup_(pidref_done) PidRef pidref_buf = PIDREF_NULL;
         uint64_t missing;
         int r;
 
@@ -761,12 +807,26 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
                 return 0;
 
         /* Try to retrieve PID from creds if it wasn't passed to us */
-        if (pid > 0) {
-                c->pid = pid;
+        if (pidref_is_set(pidref)) {
+                if ((c->mask & SD_BUS_CREDS_PID) && c->pid != pidref->pid) /* Insist that things match if already set */
+                        return -EBUSY;
+
+                c->pid = pidref->pid;
                 c->mask |= SD_BUS_CREDS_PID;
-        } else if (c->mask & SD_BUS_CREDS_PID)
-                pid = c->pid;
-        else
+        } else if (c->mask & SD_BUS_CREDS_PIDFD) {
+                r = pidref_set_pidfd(&pidref_buf, c->pidfd);
+                if (r < 0)
+                        return r;
+
+                pidref = &pidref_buf;
+
+        } else if (c->mask & SD_BUS_CREDS_PID) {
+                r = pidref_set_pid(&pidref_buf, c->pid);
+                if (r < 0)
+                        return r;
+
+                pidref = &pidref_buf;
+        } else
                 /* Without pid we cannot do much... */
                 return 0;
 
@@ -784,6 +844,14 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
                 c->mask |= SD_BUS_CREDS_TID;
         }
 
+        if ((missing & SD_BUS_CREDS_PIDFD) && pidref->fd >= 0) {
+                c->pidfd = fcntl(pidref->fd, F_DUPFD_CLOEXEC, 3);
+                if (c->pidfd < 0)
+                        return -errno;
+
+                c->mask |= SD_BUS_CREDS_PIDFD;
+        }
+
         if (missing & (SD_BUS_CREDS_PPID |
                        SD_BUS_CREDS_UID | SD_BUS_CREDS_EUID | SD_BUS_CREDS_SUID | SD_BUS_CREDS_FSUID |
                        SD_BUS_CREDS_GID | SD_BUS_CREDS_EGID | SD_BUS_CREDS_SGID | SD_BUS_CREDS_FSGID |
@@ -794,13 +862,13 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
                 _cleanup_fclose_ FILE *f = NULL;
                 const char *p;
 
-                p = procfs_file_alloca(pid, "status");
+                p = procfs_file_alloca(pidref->pid, "status");
 
                 f = fopen(p, "re");
                 if (!f) {
                         if (errno == ENOENT)
                                 return -ESRCH;
-                        else if (!ERRNO_IS_PRIVILEGE(errno))
+                        if (!ERRNO_IS_PRIVILEGE(errno))
                                 return -errno;
                 } else {
 
@@ -958,7 +1026,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
         if (missing & SD_BUS_CREDS_SELINUX_CONTEXT) {
                 const char *p;
 
-                p = procfs_file_alloca(pid, "attr/current");
+                p = procfs_file_alloca(pidref->pid, "attr/current");
                 r = read_one_line_file(p, &c->label);
                 if (r < 0) {
                         if (!IN_SET(r, -ENOENT, -EINVAL, -EPERM, -EACCES))
@@ -968,7 +1036,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
         }
 
         if (missing & SD_BUS_CREDS_COMM) {
-                r = pid_get_comm(pid, &c->comm);
+                r = pid_get_comm(pidref->pid, &c->comm);
                 if (r < 0) {
                         if (!ERRNO_IS_PRIVILEGE(r))
                                 return r;
@@ -977,7 +1045,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
         }
 
         if (missing & SD_BUS_CREDS_EXE) {
-                r = get_process_exe(pid, &c->exe);
+                r = get_process_exe(pidref->pid, &c->exe);
                 if (r == -ESRCH) {
                         /* Unfortunately we cannot really distinguish
                          * the case here where the process does not
@@ -998,7 +1066,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
         if (missing & SD_BUS_CREDS_CMDLINE) {
                 const char *p;
 
-                p = procfs_file_alloca(pid, "cmdline");
+                p = procfs_file_alloca(pidref->pid, "cmdline");
                 r = read_full_virtual_file(p, &c->cmdline, &c->cmdline_size);
                 if (r == -ENOENT)
                         return -ESRCH;
@@ -1016,7 +1084,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
         if (tid > 0 && (missing & SD_BUS_CREDS_TID_COMM)) {
                 _cleanup_free_ char *p = NULL;
 
-                if (asprintf(&p, "/proc/"PID_FMT"/task/"PID_FMT"/comm", pid, tid) < 0)
+                if (asprintf(&p, "/proc/"PID_FMT"/task/"PID_FMT"/comm", pidref->pid, tid) < 0)
                         return -ENOMEM;
 
                 r = read_one_line_file(p, &c->tid_comm);
@@ -1032,7 +1100,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
         if (missing & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_USER_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID)) {
 
                 if (!c->cgroup) {
-                        r = cg_pid_get_path(NULL, pid, &c->cgroup);
+                        r = cg_pid_get_path(NULL, pidref->pid, &c->cgroup);
                         if (r < 0) {
                                 if (!ERRNO_IS_PRIVILEGE(r))
                                         return r;
@@ -1050,7 +1118,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
         }
 
         if (missing & SD_BUS_CREDS_AUDIT_SESSION_ID) {
-                r = audit_session_from_pid(pid, &c->audit_session_id);
+                r = audit_session_from_pid(pidref->pid, &c->audit_session_id);
                 if (r == -ENODATA) {
                         /* ENODATA means: no audit session id assigned */
                         c->audit_session_id = AUDIT_SESSION_INVALID;
@@ -1063,7 +1131,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
         }
 
         if (missing & SD_BUS_CREDS_AUDIT_LOGIN_UID) {
-                r = audit_loginuid_from_pid(pid, &c->audit_login_uid);
+                r = audit_loginuid_from_pid(pidref->pid, &c->audit_login_uid);
                 if (r == -ENODATA) {
                         /* ENODATA means: no audit login uid assigned */
                         c->audit_login_uid = UID_INVALID;
@@ -1076,7 +1144,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
         }
 
         if (missing & SD_BUS_CREDS_TTY) {
-                r = get_ctty(pid, NULL, &c->tty);
+                r = get_ctty(pidref->pid, NULL, &c->tty);
                 if (r == -ENXIO) {
                         /* ENXIO means: process has no controlling TTY */
                         c->tty = NULL;
@@ -1088,16 +1156,12 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) {
                         c->mask |= SD_BUS_CREDS_TTY;
         }
 
-        /* In case only the exe path was to be read we cannot distinguish the case where the exe path was
-         * unreadable because the process was a kernel thread, or when the process didn't exist at
-         * all. Hence, let's do a final check, to be sure. */
-        r = pid_is_alive(pid);
+        r = pidref_verify(pidref);
         if (r < 0)
                 return r;
-        if (r == 0)
-                return -ESRCH;
 
-        if (tid > 0 && tid != pid && pid_is_unwaited(tid) == 0)
+        /* Validate tid is still valid, too */
+        if (tid > 0 && tid != pidref->pid && pid_is_unwaited(tid) == 0)
                 return -ESRCH;
 
         c->augmented = missing & c->mask;
@@ -1131,6 +1195,13 @@ int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret)
                 n->mask |= SD_BUS_CREDS_PID;
         }
 
+        if (c->mask & mask & SD_BUS_CREDS_PIDFD) {
+                n->pidfd = fcntl(c->pidfd, F_DUPFD_CLOEXEC, 3);
+                if (n->pidfd < 0)
+                        return -errno;
+                n->mask |= SD_BUS_CREDS_PIDFD;
+        }
+
         if (c->mask & mask & SD_BUS_CREDS_TID) {
                 n->tid = c->tid;
                 n->mask |= SD_BUS_CREDS_TID;
index 7806d9e3628f916dc3494b991d8c15b7e53df6fe..f45de1cb9c47fc88aeaa0d7b46b1bc795013e7c4 100644 (file)
@@ -5,6 +5,9 @@
 
 #include "sd-bus.h"
 
+#include "pidref.h"
+#include "user-util.h"
+
 struct sd_bus_creds {
         bool allocated;
         unsigned n_ref;
@@ -27,6 +30,7 @@ struct sd_bus_creds {
         pid_t ppid;
         pid_t pid;
         pid_t tid;
+        int pidfd;
 
         char *comm;
         char *tid_comm;
@@ -63,10 +67,22 @@ struct sd_bus_creds {
         char *description, *unescaped_description;
 };
 
+#define SD_BUS_CREDS_INIT_FIELDS        \
+        .uid = UID_INVALID,             \
+        .euid = UID_INVALID,            \
+        .suid = UID_INVALID,            \
+        .fsuid = UID_INVALID,           \
+        .gid = GID_INVALID,             \
+        .egid = GID_INVALID,            \
+        .sgid = GID_INVALID,            \
+        .fsgid = GID_INVALID,           \
+        .pidfd = -EBADF,                \
+        .audit_login_uid = UID_INVALID
+
 sd_bus_creds* bus_creds_new(void);
 
 void bus_creds_done(sd_bus_creds *c);
 
-int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid);
+int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, PidRef *pidref, pid_t tid);
 
 int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret);
index 6d24f3b1c97fa7f049ccaa6995ba1a1985d3da9b..aa46fec91b92fa21477662b625e064bb9d13ea45 100644 (file)
@@ -355,6 +355,8 @@ int bus_creds_dump(sd_bus_creds *c, FILE *f, bool terse) {
 
         if (c->mask & SD_BUS_CREDS_PID)
                 fprintf(f, "%sPID=%s"PID_FMT"%s", prefix, color, c->pid, suffix);
+        if (c->mask & SD_BUS_CREDS_PIDFD)
+                fprintf(f, "%sPIDFD=%syes%s", prefix, color, suffix);
         if (c->mask & SD_BUS_CREDS_TID)
                 fprintf(f, "%sTID=%s"PID_FMT"%s", prefix, color, c->tid, suffix);
         if (c->mask & SD_BUS_CREDS_PPID) {
index 098a51860587b80e00911cc23f9a84715682d4f2..8229c432c20d83a95d3e0689b0ca16f79190436b 100644 (file)
@@ -269,6 +269,7 @@ struct sd_bus {
         size_t n_groups;
         union sockaddr_union sockaddr_peer;
         socklen_t sockaddr_size_peer;
+        int pidfd;
 
         uint64_t creds_mask;
 
index e3d1eb8f33b7752bcddde0130e92564082fa5fa5..296f450826a3c472299c03ab5badc50ace562478 100644 (file)
@@ -373,6 +373,7 @@ static int message_from_header(
         if (!m)
                 return -ENOMEM;
 
+        m->creds = (sd_bus_creds) { SD_BUS_CREDS_INIT_FIELDS };
         m->sealed = true;
         m->header = buffer;
 
@@ -469,6 +470,7 @@ _public_ int sd_bus_message_new(
                 return -ENOMEM;
 
         t->n_ref = 1;
+        t->creds = (sd_bus_creds) { SD_BUS_CREDS_INIT_FIELDS };
         t->bus = sd_bus_ref(bus);
         t->header = (struct bus_header*) ((uint8_t*) t + ALIGN(sizeof(struct sd_bus_message)));
         t->header->endian = BUS_NATIVE_ENDIAN;
index 8fe8854350c98159427d4c9ba0857d5175375e5a..a99cdcc451ec897d6d874e81846481c7f78f5db0 100644 (file)
@@ -643,14 +643,20 @@ static void bus_get_peercred(sd_bus *b) {
         /* Get the SELinux context of the peer */
         r = getpeersec(b->input_fd, &b->label);
         if (r < 0 && !IN_SET(r, -EOPNOTSUPP, -ENOPROTOOPT))
-                log_debug_errno(r, "Failed to determine peer security context: %m");
+                log_debug_errno(r, "Failed to determine peer security context, ignoring: %m");
 
         /* Get the list of auxiliary groups of the peer */
         r = getpeergroups(b->input_fd, &b->groups);
         if (r >= 0)
                 b->n_groups = (size_t) r;
         else if (!IN_SET(r, -EOPNOTSUPP, -ENOPROTOOPT))
-                log_debug_errno(r, "Failed to determine peer's group list: %m");
+                log_debug_errno(r, "Failed to determine peer's group list, ignoring: %m");
+
+        r = getpeerpidfd(b->input_fd);
+        if (r < 0)
+                log_debug_errno(r, "Failed to determin peer pidfd, ignoring: %m");
+        else
+                close_and_replace(b->pidfd, r);
 
         /* Let's query the peers socket address, it might carry information such as the peer's comm or
          * description string */
index 4fdfc9a581a587701f22a31d50358cc5cfffc641..2ad29af10557eaa5e2560a3235f2c8936bf6cb3d 100644 (file)
@@ -256,6 +256,7 @@ _public_ int sd_bus_new(sd_bus **ret) {
                 .n_groups = SIZE_MAX,
                 .close_on_exit = true,
                 .ucred = UCRED_INVALID,
+                .pidfd = -EBADF,
                 .runtime_scope = _RUNTIME_SCOPE_INVALID,
         };
 
index d18ce88a25612bfb13c0a982e8b8e38a92752819..7eb7a38c39dc83623a354aa389549d3dd53503b6 100644 (file)
@@ -4,6 +4,7 @@
 
 #include "bus-dump.h"
 #include "cgroup-util.h"
+#include "errno-util.h"
 #include "tests.h"
 
 int main(int argc, char *argv[]) {
@@ -24,11 +25,30 @@ int main(int argc, char *argv[]) {
         creds = sd_bus_creds_unref(creds);
 
         r = sd_bus_creds_new_from_pid(&creds, 1, _SD_BUS_CREDS_ALL);
-        if (r != -EACCES) {
+        if (!ERRNO_IS_NEG_PRIVILEGE(r)) {
                 assert_se(r >= 0);
                 putchar('\n');
                 bus_creds_dump(creds, NULL, true);
         }
 
+        creds = sd_bus_creds_unref(creds);
+
+        _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL;
+        r = sd_bus_default_system(&bus);
+        if (r < 0)
+                log_warning_errno(r, "Unable to connect to system bus, skipping rest of test.");
+        else {
+                const char *unique;
+
+                assert_se(sd_bus_get_unique_name(bus, &unique) >= 0);
+
+                r = sd_bus_get_name_creds(bus, unique, _SD_BUS_CREDS_ALL, &creds);
+                log_full_errno(r < 0 ? LOG_ERR : LOG_DEBUG, r, "sd_bus_get_name_creds: %m");
+                assert_se(r >= 0);
+
+                putchar('\n');
+                bus_creds_dump(creds, NULL, true);
+        }
+
         return 0;
 }
index 79556e8a8574d7a7778f5c2f02ed8ae238e9a8f0..0c57d3821824c6c2c8a292fd52dfaca1d38a3292 100644 (file)
@@ -5,6 +5,8 @@
 
 #include "sd-bus.h"
 
+#include "bus-dump.h"
+#include "bus-util.h"
 #include "fd-util.h"
 #include "process-util.h"
 #include "socket-util.h"
@@ -27,11 +29,13 @@ static void *server(void *p) {
         assert_se(sd_bus_set_fd(bus, fd, fd) >= 0);
         TAKE_FD(fd);
         assert_se(sd_bus_set_server(bus, true, id) >= 0);
-        assert_se(sd_bus_negotiate_creds(bus, 1, SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|SD_BUS_CREDS_DESCRIPTION) >= 0);
+        assert_se(sd_bus_negotiate_creds(bus, 1, SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|SD_BUS_CREDS_DESCRIPTION|SD_BUS_CREDS_PIDFD) >= 0);
 
         assert_se(sd_bus_start(bus) >= 0);
 
-        assert_se(sd_bus_get_owner_creds(bus, SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|SD_BUS_CREDS_DESCRIPTION, &c) >= 0);
+        assert_se(sd_bus_get_owner_creds(bus, SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_PID|SD_BUS_CREDS_COMM|SD_BUS_CREDS_DESCRIPTION|SD_BUS_CREDS_PIDFD, &c) >= 0);
+
+        bus_creds_dump(c, /* f= */ NULL, /* terse= */ false);
 
         uid_t u;
         assert_se(sd_bus_creds_get_euid(c, &u) >= 0);
@@ -45,6 +49,14 @@ static void *server(void *p) {
         assert_se(sd_bus_creds_get_pid(c, &pid) >= 0);
         assert_se(pid == getpid_cached());
 
+        int pidfd = -EBADF;
+        if (sd_bus_creds_get_pidfd_dup(c, &pidfd) >= 0) {
+                _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
+
+                assert_se(pidref_set_pidfd_take(&pidref, pidfd) >= 0);
+                assert_se(pidref.pid == getpid_cached());
+        }
+
         const char *comm;
         assert_se(sd_bus_creds_get_comm(c, &comm) >= 0);
         assert_se(pid_get_comm(0, &our_comm) >= 0);
index bd3da36c36314e817dfb7ddc9e297c32f98617f6..f1a3311992e693418652d8f36064bc2a291398fb 100644 (file)
@@ -90,8 +90,9 @@ __extension__ enum {
         SD_BUS_CREDS_UNIQUE_NAME        = 1ULL << 31,
         SD_BUS_CREDS_WELL_KNOWN_NAMES   = 1ULL << 32,
         SD_BUS_CREDS_DESCRIPTION        = 1ULL << 33,
+        SD_BUS_CREDS_PIDFD              = 1ULL << 34,
         SD_BUS_CREDS_AUGMENT            = 1ULL << 63, /* special flag, if on sd-bus will augment creds struct, in a potentially race-full way. */
-        _SD_BUS_CREDS_ALL               = (1ULL << 34) -1
+        _SD_BUS_CREDS_ALL               = (1ULL << 35) -1
 };
 
 __extension__ enum {
@@ -402,12 +403,14 @@ int sd_bus_match_signal_async(sd_bus *bus, sd_bus_slot **ret, const char *sender
 /* Credential handling */
 
 int sd_bus_creds_new_from_pid(sd_bus_creds **ret, pid_t pid, uint64_t creds_mask);
+int sd_bus_creds_new_from_pidfd(sd_bus_creds **ret, int pidfd, uint64_t creds_mask);
 sd_bus_creds* sd_bus_creds_ref(sd_bus_creds *c);
 sd_bus_creds* sd_bus_creds_unref(sd_bus_creds *c);
 uint64_t sd_bus_creds_get_mask(const sd_bus_creds *c);
 uint64_t sd_bus_creds_get_augmented_mask(const sd_bus_creds *c);
 
 int sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid);
+int sd_bus_creds_get_pidfd_dup(sd_bus_creds *c, int *ret_fd);
 int sd_bus_creds_get_ppid(sd_bus_creds *c, pid_t *ppid);
 int sd_bus_creds_get_tid(sd_bus_creds *c, pid_t *tid);
 int sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid);