From: Lennart Poettering Date: Fri, 26 Jan 2024 15:46:09 +0000 (+0100) Subject: sd-bus: add pidfd to the sd_bus_creds structure X-Git-Tag: v256-rc1~1021^2~6 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=71be64064c9e22c9edcb0c25d7ccc9e3c9ed1978;p=thirdparty%2Fsystemd.git sd-bus: add pidfd to the sd_bus_creds structure Let's continue with the pidfd'ification, and include pidfd in our sd_bus_creds structure tha tracks a peers credentials. --- diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym index 4113920ee04..22cf48c5f8d 100644 --- a/src/libsystemd/libsystemd.sym +++ b/src/libsystemd/libsystemd.sym @@ -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; diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c index 1355e41ed08..3b11d754a22 100644 --- a/src/libsystemd/sd-bus/bus-control.c +++ b/src/libsystemd/sd-bus/bus-control.c @@ -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; diff --git a/src/libsystemd/sd-bus/bus-creds.c b/src/libsystemd/sd-bus/bus-creds.c index 33ae2a00f68..adbdeaa210e 100644 --- a/src/libsystemd/sd-bus/bus-creds.c +++ b/src/libsystemd/sd-bus/bus-creds.c @@ -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; diff --git a/src/libsystemd/sd-bus/bus-creds.h b/src/libsystemd/sd-bus/bus-creds.h index 7806d9e3628..f45de1cb9c4 100644 --- a/src/libsystemd/sd-bus/bus-creds.h +++ b/src/libsystemd/sd-bus/bus-creds.h @@ -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); diff --git a/src/libsystemd/sd-bus/bus-dump.c b/src/libsystemd/sd-bus/bus-dump.c index 6d24f3b1c97..aa46fec91b9 100644 --- a/src/libsystemd/sd-bus/bus-dump.c +++ b/src/libsystemd/sd-bus/bus-dump.c @@ -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) { diff --git a/src/libsystemd/sd-bus/bus-internal.h b/src/libsystemd/sd-bus/bus-internal.h index 098a5186058..8229c432c20 100644 --- a/src/libsystemd/sd-bus/bus-internal.h +++ b/src/libsystemd/sd-bus/bus-internal.h @@ -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; diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c index e3d1eb8f33b..296f450826a 100644 --- a/src/libsystemd/sd-bus/bus-message.c +++ b/src/libsystemd/sd-bus/bus-message.c @@ -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; diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c index 8fe8854350c..a99cdcc451e 100644 --- a/src/libsystemd/sd-bus/bus-socket.c +++ b/src/libsystemd/sd-bus/bus-socket.c @@ -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 */ diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c index 4fdfc9a581a..2ad29af1055 100644 --- a/src/libsystemd/sd-bus/sd-bus.c +++ b/src/libsystemd/sd-bus/sd-bus.c @@ -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, }; diff --git a/src/libsystemd/sd-bus/test-bus-creds.c b/src/libsystemd/sd-bus/test-bus-creds.c index d18ce88a256..7eb7a38c39d 100644 --- a/src/libsystemd/sd-bus/test-bus-creds.c +++ b/src/libsystemd/sd-bus/test-bus-creds.c @@ -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; } diff --git a/src/libsystemd/sd-bus/test-bus-peersockaddr.c b/src/libsystemd/sd-bus/test-bus-peersockaddr.c index 79556e8a857..0c57d382182 100644 --- a/src/libsystemd/sd-bus/test-bus-peersockaddr.c +++ b/src/libsystemd/sd-bus/test-bus-peersockaddr.c @@ -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); diff --git a/src/systemd/sd-bus.h b/src/systemd/sd-bus.h index bd3da36c363..f1a3311992e 100644 --- a/src/systemd/sd-bus.h +++ b/src/systemd/sd-bus.h @@ -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);