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.
This commit is contained in:
Lennart Poettering
2024-01-29 14:41:58 +01:00
parent 7e8aa5c2ee
commit 71be64064c
12 changed files with 261 additions and 74 deletions
+6
View File
@@ -834,3 +834,9 @@ global:
sd_id128_get_app_specific; sd_id128_get_app_specific;
sd_device_enumerator_add_match_property_required; sd_device_enumerator_add_match_property_required;
} LIBSYSTEMD_254; } LIBSYSTEMD_254;
LIBSYSTEMD_256 {
global:
sd_bus_creds_get_pidfd_dup;
sd_bus_creds_new_from_pidfd;
} LIBSYSTEMD_255;
+71 -24
View File
@@ -14,6 +14,7 @@
#include "bus-internal.h" #include "bus-internal.h"
#include "bus-message.h" #include "bus-message.h"
#include "capability-util.h" #include "capability-util.h"
#include "fd-util.h"
#include "process-util.h" #include "process-util.h"
#include "stdio-util.h" #include "stdio-util.h"
#include "string-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_message_unrefp) sd_bus_message *reply_unique = NULL, *reply = NULL;
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL; _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
const char *unique; const char *unique;
pid_t pid = 0;
int r; int r;
assert_return(bus, -EINVAL); assert_return(bus, -EINVAL);
@@ -484,7 +484,8 @@ _public_ int sd_bus_get_name_creds(
if (mask != 0) { if (mask != 0) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _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(); c = bus_creds_new();
if (!c) if (!c)
@@ -498,20 +499,24 @@ _public_ int sd_bus_get_name_creds(
c->mask |= SD_BUS_CREDS_UNIQUE_NAME; c->mask |= SD_BUS_CREDS_UNIQUE_NAME;
} }
need_pid = (mask & SD_BUS_CREDS_PID) || need_augment =
((mask & SD_BUS_CREDS_AUGMENT) && (mask & SD_BUS_CREDS_AUGMENT) &&
(mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_SUID|SD_BUS_CREDS_FSUID| (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_GID|SD_BUS_CREDS_EGID|SD_BUS_CREDS_SGID|SD_BUS_CREDS_FSGID|
SD_BUS_CREDS_SUPPLEMENTARY_GIDS| SD_BUS_CREDS_SUPPLEMENTARY_GIDS|
SD_BUS_CREDS_COMM|SD_BUS_CREDS_EXE|SD_BUS_CREDS_CMDLINE| 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_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_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_SELINUX_CONTEXT|
SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID))); 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_uid = mask & SD_BUS_CREDS_EUID;
need_selinux = mask & SD_BUS_CREDS_SELINUX_CONTEXT; 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() */ /* 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) if (r < 0)
return r; return r;
pid = p; if (!pidref_is_set(&pidref))
pidref = PIDREF_MAKE_FROM_PID(p);
if (mask & SD_BUS_CREDS_PID) { if (mask & SD_BUS_CREDS_PID) {
c->pid = p; c->pid = p;
c->mask |= SD_BUS_CREDS_PID; c->mask |= SD_BUS_CREDS_PID;
@@ -599,6 +606,26 @@ _public_ int sd_bus_get_name_creds(
r = sd_bus_message_exit_container(reply); r = sd_bus_message_exit_container(reply);
if (r < 0) if (r < 0)
return r; 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 { } else {
r = sd_bus_message_skip(reply, "v"); r = sd_bus_message_skip(reply, "v");
if (r < 0) if (r < 0)
@@ -614,7 +641,7 @@ _public_ int sd_bus_get_name_creds(
if (r < 0) if (r < 0)
return r; return r;
if (need_pid && pid == 0) if (need_pid && !pidref_is_set(&pidref))
return -EPROTO; return -EPROTO;
} }
@@ -642,7 +669,9 @@ _public_ int sd_bus_get_name_creds(
if (r < 0) if (r < 0)
return r; return r;
pid = u; if (!pidref_is_set(&pidref))
pidref = PIDREF_MAKE_FROM_PID(u);
if (mask & SD_BUS_CREDS_PID) { if (mask & SD_BUS_CREDS_PID) {
c->pid = u; c->pid = u;
c->mask |= SD_BUS_CREDS_PID; 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 (pidref_is_set(&pidref)) {
if (r < 0 && r != -ESRCH) /* Return the error, but ignore ESRCH which just means the process is already gone */ r = bus_creds_add_more(c, mask, &pidref, 0);
return r; if (r < 0 && r != -ESRCH) /* Return the error, but ignore ESRCH which just means the process is already gone */
return r;
}
} }
if (creds) 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) { _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; _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
bool do_label, do_groups, do_sockaddr_peer; _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
pid_t pid = 0; bool do_label, do_groups, do_sockaddr_peer, do_pidfd;
int r; int r;
assert_return(bus, -EINVAL); 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 && 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.sa.sa_family == AF_UNIX &&
bus->sockaddr_peer.un.sun_path[0] == 0; 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 */ /* 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; return -ENODATA;
c = bus_creds_new(); 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 (bus->ucred_valid) {
if (pid_is_valid(bus->ucred.pid)) { 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; c->mask |= SD_BUS_CREDS_PID & mask;
pidref = PIDREF_MAKE_FROM_PID(c->pid);
} }
if (uid_is_valid(bus->ucred.uid)) { 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 */ if (r < 0 && r != -ESRCH) /* If the process vanished, then don't complain, just return what we got */
return r; return r;
+114 -43
View File
@@ -53,6 +53,8 @@ void bus_creds_done(sd_bus_creds *c) {
* below. */ * below. */
strv_free(c->cmdline_array); strv_free(c->cmdline_array);
safe_close(c->pidfd);
} }
_public_ sd_bus_creds *sd_bus_creds_ref(sd_bus_creds *c) { _public_ sd_bus_creds *sd_bus_creds_ref(sd_bus_creds *c) {
@@ -129,44 +131,70 @@ _public_ uint64_t sd_bus_creds_get_augmented_mask(const sd_bus_creds *c) {
sd_bus_creds* bus_creds_new(void) { sd_bus_creds* bus_creds_new(void) {
sd_bus_creds *c; sd_bus_creds *c;
c = new0(sd_bus_creds, 1); c = new(sd_bus_creds, 1);
if (!c) if (!c)
return NULL; return NULL;
c->allocated = true; *c = (sd_bus_creds) {
c->n_ref = 1; .allocated = true,
.n_ref = 1,
SD_BUS_CREDS_INIT_FIELDS,
};
return c; 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; _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *c = NULL;
int r; int r;
assert_return(mask <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
assert_return(ret, -EINVAL);
c = bus_creds_new();
if (!c)
return -ENOMEM;
r = bus_creds_add_more(c, mask | SD_BUS_CREDS_AUGMENT, pidref, 0);
if (r < 0)
return r;
r = pidref_verify(pidref);
if (r < 0)
return r;
*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(pid >= 0, -EINVAL);
assert_return(mask <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP); assert_return(mask <= _SD_BUS_CREDS_ALL, -EOPNOTSUPP);
assert_return(ret, -EINVAL); assert_return(ret, -EINVAL);
if (pid == 0) r = pidref_set_pid(&pidref, pid);
pid = getpid_cached();
c = bus_creds_new();
if (!c)
return -ENOMEM;
r = bus_creds_add_more(c, mask | SD_BUS_CREDS_AUGMENT, pid, 0);
if (r < 0) if (r < 0)
return r; return r;
/* Check if the process existed at all, in case we haven't return bus_creds_new_from_pidref(ret, &pidref, mask);
* figured that out already */ }
r = pid_is_alive(pid);
_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) if (r < 0)
return r; return r;
if (r == 0)
return -ESRCH;
*ret = TAKE_PTR(c); return bus_creds_new_from_pidref(ret, &pidref, mask);
return 0;
} }
_public_ int sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid) { _public_ int sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid) {
@@ -280,6 +308,23 @@ _public_ int sd_bus_creds_get_pid(sd_bus_creds *c, pid_t *pid) {
return 0; 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) { _public_ int sd_bus_creds_get_ppid(sd_bus_creds *c, pid_t *ppid) {
assert_return(c, -EINVAL); assert_return(c, -EINVAL);
assert_return(ppid, -EINVAL); assert_return(ppid, -EINVAL);
@@ -750,7 +795,8 @@ static int parse_caps(sd_bus_creds *c, unsigned offset, const char *p) {
return 0; 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; uint64_t missing;
int r; 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; return 0;
/* Try to retrieve PID from creds if it wasn't passed to us */ /* Try to retrieve PID from creds if it wasn't passed to us */
if (pid > 0) { if (pidref_is_set(pidref)) {
c->pid = pid; 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; c->mask |= SD_BUS_CREDS_PID;
} else if (c->mask & SD_BUS_CREDS_PID) } else if (c->mask & SD_BUS_CREDS_PIDFD) {
pid = c->pid; r = pidref_set_pidfd(&pidref_buf, c->pidfd);
else 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... */ /* Without pid we cannot do much... */
return 0; 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; 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 | 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_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 | 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; _cleanup_fclose_ FILE *f = NULL;
const char *p; const char *p;
p = procfs_file_alloca(pid, "status"); p = procfs_file_alloca(pidref->pid, "status");
f = fopen(p, "re"); f = fopen(p, "re");
if (!f) { if (!f) {
if (errno == ENOENT) if (errno == ENOENT)
return -ESRCH; return -ESRCH;
else if (!ERRNO_IS_PRIVILEGE(errno)) if (!ERRNO_IS_PRIVILEGE(errno))
return -errno; return -errno;
} else { } 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) { if (missing & SD_BUS_CREDS_SELINUX_CONTEXT) {
const char *p; 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); r = read_one_line_file(p, &c->label);
if (r < 0) { if (r < 0) {
if (!IN_SET(r, -ENOENT, -EINVAL, -EPERM, -EACCES)) 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) { 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 (r < 0) {
if (!ERRNO_IS_PRIVILEGE(r)) if (!ERRNO_IS_PRIVILEGE(r))
return 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) { if (missing & SD_BUS_CREDS_EXE) {
r = get_process_exe(pid, &c->exe); r = get_process_exe(pidref->pid, &c->exe);
if (r == -ESRCH) { if (r == -ESRCH) {
/* Unfortunately we cannot really distinguish /* Unfortunately we cannot really distinguish
* the case here where the process does not * 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) { if (missing & SD_BUS_CREDS_CMDLINE) {
const char *p; 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); r = read_full_virtual_file(p, &c->cmdline, &c->cmdline_size);
if (r == -ENOENT) if (r == -ENOENT)
return -ESRCH; 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)) { if (tid > 0 && (missing & SD_BUS_CREDS_TID_COMM)) {
_cleanup_free_ char *p = NULL; _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; return -ENOMEM;
r = read_one_line_file(p, &c->tid_comm); 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 (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) { 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 (r < 0) {
if (!ERRNO_IS_PRIVILEGE(r)) if (!ERRNO_IS_PRIVILEGE(r))
return 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) { 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) { if (r == -ENODATA) {
/* ENODATA means: no audit session id assigned */ /* ENODATA means: no audit session id assigned */
c->audit_session_id = AUDIT_SESSION_INVALID; 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) { 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) { if (r == -ENODATA) {
/* ENODATA means: no audit login uid assigned */ /* ENODATA means: no audit login uid assigned */
c->audit_login_uid = UID_INVALID; 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) { if (missing & SD_BUS_CREDS_TTY) {
r = get_ctty(pid, NULL, &c->tty); r = get_ctty(pidref->pid, NULL, &c->tty);
if (r == -ENXIO) { if (r == -ENXIO) {
/* ENXIO means: process has no controlling TTY */ /* ENXIO means: process has no controlling TTY */
c->tty = NULL; 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; 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 r = pidref_verify(pidref);
* 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);
if (r < 0) if (r < 0)
return r; 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; return -ESRCH;
c->augmented = missing & c->mask; 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; 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) { if (c->mask & mask & SD_BUS_CREDS_TID) {
n->tid = c->tid; n->tid = c->tid;
n->mask |= SD_BUS_CREDS_TID; n->mask |= SD_BUS_CREDS_TID;
+17 -1
View File
@@ -5,6 +5,9 @@
#include "sd-bus.h" #include "sd-bus.h"
#include "pidref.h"
#include "user-util.h"
struct sd_bus_creds { struct sd_bus_creds {
bool allocated; bool allocated;
unsigned n_ref; unsigned n_ref;
@@ -27,6 +30,7 @@ struct sd_bus_creds {
pid_t ppid; pid_t ppid;
pid_t pid; pid_t pid;
pid_t tid; pid_t tid;
int pidfd;
char *comm; char *comm;
char *tid_comm; char *tid_comm;
@@ -63,10 +67,22 @@ struct sd_bus_creds {
char *description, *unescaped_description; 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); sd_bus_creds* bus_creds_new(void);
void bus_creds_done(sd_bus_creds *c); 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); int bus_creds_extend_by_pid(sd_bus_creds *c, uint64_t mask, sd_bus_creds **ret);
+2
View File
@@ -355,6 +355,8 @@ int bus_creds_dump(sd_bus_creds *c, FILE *f, bool terse) {
if (c->mask & SD_BUS_CREDS_PID) if (c->mask & SD_BUS_CREDS_PID)
fprintf(f, "%sPID=%s"PID_FMT"%s", prefix, color, c->pid, suffix); 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) if (c->mask & SD_BUS_CREDS_TID)
fprintf(f, "%sTID=%s"PID_FMT"%s", prefix, color, c->tid, suffix); fprintf(f, "%sTID=%s"PID_FMT"%s", prefix, color, c->tid, suffix);
if (c->mask & SD_BUS_CREDS_PPID) { if (c->mask & SD_BUS_CREDS_PPID) {
+1
View File
@@ -269,6 +269,7 @@ struct sd_bus {
size_t n_groups; size_t n_groups;
union sockaddr_union sockaddr_peer; union sockaddr_union sockaddr_peer;
socklen_t sockaddr_size_peer; socklen_t sockaddr_size_peer;
int pidfd;
uint64_t creds_mask; uint64_t creds_mask;
+2
View File
@@ -373,6 +373,7 @@ static int message_from_header(
if (!m) if (!m)
return -ENOMEM; return -ENOMEM;
m->creds = (sd_bus_creds) { SD_BUS_CREDS_INIT_FIELDS };
m->sealed = true; m->sealed = true;
m->header = buffer; m->header = buffer;
@@ -469,6 +470,7 @@ _public_ int sd_bus_message_new(
return -ENOMEM; return -ENOMEM;
t->n_ref = 1; t->n_ref = 1;
t->creds = (sd_bus_creds) { SD_BUS_CREDS_INIT_FIELDS };
t->bus = sd_bus_ref(bus); t->bus = sd_bus_ref(bus);
t->header = (struct bus_header*) ((uint8_t*) t + ALIGN(sizeof(struct sd_bus_message))); t->header = (struct bus_header*) ((uint8_t*) t + ALIGN(sizeof(struct sd_bus_message)));
t->header->endian = BUS_NATIVE_ENDIAN; t->header->endian = BUS_NATIVE_ENDIAN;
+8 -2
View File
@@ -643,14 +643,20 @@ static void bus_get_peercred(sd_bus *b) {
/* Get the SELinux context of the peer */ /* Get the SELinux context of the peer */
r = getpeersec(b->input_fd, &b->label); r = getpeersec(b->input_fd, &b->label);
if (r < 0 && !IN_SET(r, -EOPNOTSUPP, -ENOPROTOOPT)) 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 */ /* Get the list of auxiliary groups of the peer */
r = getpeergroups(b->input_fd, &b->groups); r = getpeergroups(b->input_fd, &b->groups);
if (r >= 0) if (r >= 0)
b->n_groups = (size_t) r; b->n_groups = (size_t) r;
else if (!IN_SET(r, -EOPNOTSUPP, -ENOPROTOOPT)) 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 /* Let's query the peers socket address, it might carry information such as the peer's comm or
* description string */ * description string */
+1
View File
@@ -256,6 +256,7 @@ _public_ int sd_bus_new(sd_bus **ret) {
.n_groups = SIZE_MAX, .n_groups = SIZE_MAX,
.close_on_exit = true, .close_on_exit = true,
.ucred = UCRED_INVALID, .ucred = UCRED_INVALID,
.pidfd = -EBADF,
.runtime_scope = _RUNTIME_SCOPE_INVALID, .runtime_scope = _RUNTIME_SCOPE_INVALID,
}; };
+21 -1
View File
@@ -4,6 +4,7 @@
#include "bus-dump.h" #include "bus-dump.h"
#include "cgroup-util.h" #include "cgroup-util.h"
#include "errno-util.h"
#include "tests.h" #include "tests.h"
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
@@ -24,11 +25,30 @@ int main(int argc, char *argv[]) {
creds = sd_bus_creds_unref(creds); creds = sd_bus_creds_unref(creds);
r = sd_bus_creds_new_from_pid(&creds, 1, _SD_BUS_CREDS_ALL); 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); assert_se(r >= 0);
putchar('\n'); putchar('\n');
bus_creds_dump(creds, NULL, true); 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; return 0;
} }
+14 -2
View File
@@ -5,6 +5,8 @@
#include "sd-bus.h" #include "sd-bus.h"
#include "bus-dump.h"
#include "bus-util.h"
#include "fd-util.h" #include "fd-util.h"
#include "process-util.h" #include "process-util.h"
#include "socket-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); assert_se(sd_bus_set_fd(bus, fd, fd) >= 0);
TAKE_FD(fd); TAKE_FD(fd);
assert_se(sd_bus_set_server(bus, true, id) >= 0); 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_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; uid_t u;
assert_se(sd_bus_creds_get_euid(c, &u) >= 0); 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(sd_bus_creds_get_pid(c, &pid) >= 0);
assert_se(pid == getpid_cached()); 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; const char *comm;
assert_se(sd_bus_creds_get_comm(c, &comm) >= 0); assert_se(sd_bus_creds_get_comm(c, &comm) >= 0);
assert_se(pid_get_comm(0, &our_comm) >= 0); assert_se(pid_get_comm(0, &our_comm) >= 0);
+4 -1
View File
@@ -90,8 +90,9 @@ __extension__ enum {
SD_BUS_CREDS_UNIQUE_NAME = 1ULL << 31, SD_BUS_CREDS_UNIQUE_NAME = 1ULL << 31,
SD_BUS_CREDS_WELL_KNOWN_NAMES = 1ULL << 32, SD_BUS_CREDS_WELL_KNOWN_NAMES = 1ULL << 32,
SD_BUS_CREDS_DESCRIPTION = 1ULL << 33, 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_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 { __extension__ enum {
@@ -402,12 +403,14 @@ int sd_bus_match_signal_async(sd_bus *bus, sd_bus_slot **ret, const char *sender
/* Credential handling */ /* 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_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_ref(sd_bus_creds *c);
sd_bus_creds* sd_bus_creds_unref(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_mask(const sd_bus_creds *c);
uint64_t sd_bus_creds_get_augmented_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_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_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_tid(sd_bus_creds *c, pid_t *tid);
int sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid); int sd_bus_creds_get_uid(sd_bus_creds *c, uid_t *uid);