mirror of
https://github.com/systemd/systemd.git
synced 2024-12-22 17:35:35 +03:00
Merge pull request #31106 from poettering/bus-creds-pidref
sd-bus: port "sd_bus_creds" object to pidfds and use it everywhere
This commit is contained in:
commit
17f3e91e81
1
TODO
1
TODO
@ -379,7 +379,6 @@ Features:
|
||||
- actually wait for POLLIN on pidref's pidfd in service logic
|
||||
- exec_spawn() + safe_fork()
|
||||
- openpt_allocate_in_namespace()
|
||||
- sd_bus_creds
|
||||
- unit_attach_pid_to_cgroup_via_bus()
|
||||
- cg_attach() – requires new kernel feature
|
||||
|
||||
|
@ -202,6 +202,7 @@ manpages = [
|
||||
'sd_bus_creds_get_fsuid',
|
||||
'sd_bus_creds_get_gid',
|
||||
'sd_bus_creds_get_owner_uid',
|
||||
'sd_bus_creds_get_pidfd_dup',
|
||||
'sd_bus_creds_get_ppid',
|
||||
'sd_bus_creds_get_selinux_context',
|
||||
'sd_bus_creds_get_session',
|
||||
@ -227,6 +228,7 @@ manpages = [
|
||||
'3',
|
||||
['sd_bus_creds_get_augmented_mask',
|
||||
'sd_bus_creds_get_mask',
|
||||
'sd_bus_creds_new_from_pidfd',
|
||||
'sd_bus_creds_ref',
|
||||
'sd_bus_creds_unref',
|
||||
'sd_bus_creds_unrefp'],
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
<refnamediv>
|
||||
<refname>sd_bus_creds_get_pid</refname>
|
||||
<refname>sd_bus_creds_get_pidfd_dup</refname>
|
||||
<refname>sd_bus_creds_get_ppid</refname>
|
||||
<refname>sd_bus_creds_get_tid</refname>
|
||||
<refname>sd_bus_creds_get_uid</refname>
|
||||
@ -64,6 +65,12 @@
|
||||
<paramdef>pid_t *<parameter>pid</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>int <function>sd_bus_creds_get_pidfd_dup</function></funcdef>
|
||||
<paramdef>sd_bus_creds *<parameter>c</parameter></paramdef>
|
||||
<paramdef>int *<parameter>ret_fd</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>int <function>sd_bus_creds_get_ppid</function></funcdef>
|
||||
<paramdef>sd_bus_creds *<parameter>c</parameter></paramdef>
|
||||
@ -289,11 +296,14 @@
|
||||
<citerefentry><refentrytitle>sd_bus_creds_get_mask</refentrytitle><manvolnum>3</manvolnum></citerefentry>
|
||||
to determine the mask of fields available.</para>
|
||||
|
||||
<para><function>sd_bus_creds_get_pid()</function> will retrieve
|
||||
the PID (process identifier). Similarly,
|
||||
<function>sd_bus_creds_get_ppid()</function> will retrieve the
|
||||
parent PID. Note that PID 1 has no parent process, in which case
|
||||
-ENXIO is returned.</para>
|
||||
<para><function>sd_bus_creds_get_pid()</function> will retrieve the PID (process identifier). Similarly,
|
||||
<function>sd_bus_creds_get_ppid()</function> will retrieve the parent PID. Note that PID 1 has no parent
|
||||
process, in which case -ENXIO is returned.</para>
|
||||
|
||||
<para><function>sd_bus_creds_get_pidfd_dup()</function> will retrieve the PID file descriptor (pidfd),
|
||||
see <citerefentry
|
||||
project='man-pages'><refentrytitle>pidfd_open</refentrytitle><manvolnum>2</manvolnum></citerefentry> for
|
||||
details. The file descriptor is duplicated and thus must be closed by the caller.</para>
|
||||
|
||||
<para><function>sd_bus_creds_get_tid()</function> will retrieve the
|
||||
TID (thread identifier).</para>
|
||||
@ -543,6 +553,7 @@
|
||||
<function>sd_bus_creds_get_tty()</function>, and
|
||||
<function>sd_bus_creds_get_description()</function> were added in version 220.</para>
|
||||
<para><function>sd_bus_creds_get_user_slice()</function> was added in version 223.</para>
|
||||
<para><function>sd_bus_creds_get_pidfd_dup()</function> was added in version 256.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
<refnamediv>
|
||||
<refname>sd_bus_creds_new_from_pid</refname>
|
||||
<refname>sd_bus_creds_new_from_pidfd</refname>
|
||||
<refname>sd_bus_creds_get_mask</refname>
|
||||
<refname>sd_bus_creds_get_augmented_mask</refname>
|
||||
<refname>sd_bus_creds_ref</refname>
|
||||
@ -37,6 +38,13 @@
|
||||
<paramdef>sd_bus_creds **<parameter>ret</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>int <function>sd_bus_creds_new_from_pidfd</function></funcdef>
|
||||
<paramdef>int <parameter>pidfd</parameter></paramdef>
|
||||
<paramdef>uint64_t <parameter>creds_mask</parameter></paramdef>
|
||||
<paramdef>sd_bus_creds **<parameter>ret</parameter></paramdef>
|
||||
</funcprototype>
|
||||
|
||||
<funcprototype>
|
||||
<funcdef>uint64_t <function>sd_bus_creds_get_mask</function></funcdef>
|
||||
<paramdef>sd_bus_creds *<parameter>c</parameter></paramdef>
|
||||
@ -98,6 +106,7 @@
|
||||
<constant>SD_BUS_CREDS_UNIQUE_NAME</constant>,
|
||||
<constant>SD_BUS_CREDS_WELL_KNOWN_NAMES</constant>,
|
||||
<constant>SD_BUS_CREDS_DESCRIPTION</constant>,
|
||||
<constant>SD_BUS_CREDS_PIDFD</constant>,
|
||||
<constant>SD_BUS_CREDS_AUGMENT</constant>,
|
||||
<constant>_SD_BUS_CREDS_ALL</constant>
|
||||
</para>
|
||||
@ -116,91 +125,65 @@
|
||||
and
|
||||
<citerefentry><refentrytitle>sd_bus_message_get_creds</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para>
|
||||
|
||||
<para>The information that will be stored is determined by
|
||||
<parameter>creds_mask</parameter>. It may contain a subset of ORed
|
||||
constants <constant>SD_BUS_CREDS_PID</constant>,
|
||||
<constant>SD_BUS_CREDS_PPID</constant>,
|
||||
<constant>SD_BUS_CREDS_TID</constant>,
|
||||
<constant>SD_BUS_CREDS_UID</constant>,
|
||||
<constant>SD_BUS_CREDS_EUID</constant>,
|
||||
<constant>SD_BUS_CREDS_SUID</constant>,
|
||||
<constant>SD_BUS_CREDS_FSUID</constant>,
|
||||
<constant>SD_BUS_CREDS_GID</constant>,
|
||||
<constant>SD_BUS_CREDS_EGID</constant>,
|
||||
<constant>SD_BUS_CREDS_SGID</constant>,
|
||||
<constant>SD_BUS_CREDS_FSGID</constant>,
|
||||
<constant>SD_BUS_CREDS_SUPPLEMENTARY_GIDS</constant>,
|
||||
<constant>SD_BUS_CREDS_COMM</constant>,
|
||||
<constant>SD_BUS_CREDS_TID_COMM</constant>,
|
||||
<constant>SD_BUS_CREDS_EXE</constant>,
|
||||
<constant>SD_BUS_CREDS_CMDLINE</constant>,
|
||||
<constant>SD_BUS_CREDS_CGROUP</constant>,
|
||||
<constant>SD_BUS_CREDS_UNIT</constant>,
|
||||
<constant>SD_BUS_CREDS_SLICE</constant>,
|
||||
<constant>SD_BUS_CREDS_USER_UNIT</constant>,
|
||||
<constant>SD_BUS_CREDS_USER_SLICE</constant>,
|
||||
<constant>SD_BUS_CREDS_SESSION</constant>,
|
||||
<constant>SD_BUS_CREDS_OWNER_UID</constant>,
|
||||
<constant>SD_BUS_CREDS_EFFECTIVE_CAPS</constant>,
|
||||
<constant>SD_BUS_CREDS_PERMITTED_CAPS</constant>,
|
||||
<constant>SD_BUS_CREDS_INHERITABLE_CAPS</constant>,
|
||||
<constant>SD_BUS_CREDS_BOUNDING_CAPS</constant>,
|
||||
<constant>SD_BUS_CREDS_SELINUX_CONTEXT</constant>,
|
||||
<constant>SD_BUS_CREDS_AUDIT_SESSION_ID</constant>,
|
||||
<constant>SD_BUS_CREDS_AUDIT_LOGIN_UID</constant>,
|
||||
<constant>SD_BUS_CREDS_TTY</constant>,
|
||||
<constant>SD_BUS_CREDS_UNIQUE_NAME</constant>,
|
||||
<constant>SD_BUS_CREDS_WELL_KNOWN_NAMES</constant>, and
|
||||
<constant>SD_BUS_CREDS_DESCRIPTION</constant>. Use the special
|
||||
value <constant>_SD_BUS_CREDS_ALL</constant> to request all
|
||||
supported fields. The <constant>SD_BUS_CREDS_AUGMENT</constant>
|
||||
constant may not be ORed into the mask for invocations of
|
||||
<function>sd_bus_creds_new_from_pid()</function>.</para>
|
||||
<para><function>sd_bus_creds_new_from_pidfd()</function> is identical to
|
||||
<function>sd_bus_creds_new_from_pid()</function>, but takes a PID file descriptor rather than a numeric
|
||||
PID as reference to the process. See <citerefentry
|
||||
project='man-pages'><refentrytitle>pidfd_open</refentrytitle><manvolnum>2</manvolnum></citerefentry>.</para>
|
||||
|
||||
<para>The information that will be stored is determined by <parameter>creds_mask</parameter>. It may
|
||||
contain a subset of ORed constants <constant>SD_BUS_CREDS_PID</constant>,
|
||||
<constant>SD_BUS_CREDS_PPID</constant>, <constant>SD_BUS_CREDS_TID</constant>,
|
||||
<constant>SD_BUS_CREDS_UID</constant>, <constant>SD_BUS_CREDS_EUID</constant>,
|
||||
<constant>SD_BUS_CREDS_SUID</constant>, <constant>SD_BUS_CREDS_FSUID</constant>,
|
||||
<constant>SD_BUS_CREDS_GID</constant>, <constant>SD_BUS_CREDS_EGID</constant>,
|
||||
<constant>SD_BUS_CREDS_SGID</constant>, <constant>SD_BUS_CREDS_FSGID</constant>,
|
||||
<constant>SD_BUS_CREDS_SUPPLEMENTARY_GIDS</constant>, <constant>SD_BUS_CREDS_COMM</constant>,
|
||||
<constant>SD_BUS_CREDS_TID_COMM</constant>, <constant>SD_BUS_CREDS_EXE</constant>,
|
||||
<constant>SD_BUS_CREDS_CMDLINE</constant>, <constant>SD_BUS_CREDS_CGROUP</constant>,
|
||||
<constant>SD_BUS_CREDS_UNIT</constant>, <constant>SD_BUS_CREDS_SLICE</constant>,
|
||||
<constant>SD_BUS_CREDS_USER_UNIT</constant>, <constant>SD_BUS_CREDS_USER_SLICE</constant>,
|
||||
<constant>SD_BUS_CREDS_SESSION</constant>, <constant>SD_BUS_CREDS_OWNER_UID</constant>,
|
||||
<constant>SD_BUS_CREDS_EFFECTIVE_CAPS</constant>, <constant>SD_BUS_CREDS_PERMITTED_CAPS</constant>,
|
||||
<constant>SD_BUS_CREDS_INHERITABLE_CAPS</constant>, <constant>SD_BUS_CREDS_BOUNDING_CAPS</constant>,
|
||||
<constant>SD_BUS_CREDS_SELINUX_CONTEXT</constant>, <constant>SD_BUS_CREDS_AUDIT_SESSION_ID</constant>,
|
||||
<constant>SD_BUS_CREDS_AUDIT_LOGIN_UID</constant>, <constant>SD_BUS_CREDS_TTY</constant>,
|
||||
<constant>SD_BUS_CREDS_UNIQUE_NAME</constant>, <constant>SD_BUS_CREDS_WELL_KNOWN_NAMES</constant>,
|
||||
<constant>SD_BUS_CREDS_DESCRIPTION</constant>, and <constant>SD_BUS_CREDS_PIDFD</constant>. Use the
|
||||
special value <constant>_SD_BUS_CREDS_ALL</constant> to request all supported fields. The
|
||||
<constant>SD_BUS_CREDS_AUGMENT</constant> constant may not be ORed into the mask for invocations of
|
||||
<function>sd_bus_creds_new_from_pid()</function> or
|
||||
<function>sd_bus_creds_new_from_pidfd()</function>.</para>
|
||||
|
||||
<para>Fields can be retrieved from the credentials object using
|
||||
<citerefentry><refentrytitle>sd_bus_creds_get_pid</refentrytitle><manvolnum>3</manvolnum></citerefentry>
|
||||
and other functions which correspond directly to the constants
|
||||
listed above.</para>
|
||||
|
||||
<para>A mask of fields which were actually successfully retrieved
|
||||
can be retrieved with
|
||||
<function>sd_bus_creds_get_mask()</function>. If the credentials
|
||||
object was created with
|
||||
<function>sd_bus_creds_new_from_pid()</function>, this will be a
|
||||
subset of fields requested in <parameter>creds_mask</parameter>.
|
||||
<para>A mask of fields which were actually successfully retrieved can be retrieved with
|
||||
<function>sd_bus_creds_get_mask()</function>. If the credentials object was created with
|
||||
<function>sd_bus_creds_new_from_pid()</function> or <function>sd_bus_creds_new_from_pidfd()</function>,
|
||||
this will be a subset of fields requested in <parameter>creds_mask</parameter>.
|
||||
</para>
|
||||
|
||||
<para>Similar to <function>sd_bus_creds_get_mask()</function>, the
|
||||
function <function>sd_bus_creds_get_augmented_mask()</function>
|
||||
returns a bitmask of field constants. The mask indicates which
|
||||
credential fields have been retrieved in a non-atomic fashion. For
|
||||
credential objects created via
|
||||
<function>sd_bus_creds_new_from_pid()</function>, this mask will be
|
||||
identical to the mask returned by
|
||||
<function>sd_bus_creds_get_mask()</function>. However, for
|
||||
credential objects retrieved via
|
||||
<function>sd_bus_get_name_creds()</function>, this mask will be set
|
||||
for the credential fields that could not be determined atomically
|
||||
at peer connection time, and which were later added by reading
|
||||
augmenting credential data from
|
||||
<filename>/proc/</filename>. Similarly, for credential objects
|
||||
retrieved via <function>sd_bus_get_owner_creds()</function>, the
|
||||
mask is set for the fields that could not be determined atomically
|
||||
at bus creation time, but have been augmented. Similarly, for
|
||||
credential objects retrieved via
|
||||
<function>sd_bus_message_get_creds()</function>, the mask is set
|
||||
for the fields that could not be determined atomically at message
|
||||
sending time, but have been augmented. The mask returned by
|
||||
<function>sd_bus_creds_get_augmented_mask()</function> is always a
|
||||
subset of (or identical to) the mask returned by
|
||||
<function>sd_bus_creds_get_mask()</function> for the same
|
||||
object. The latter call hence returns all credential fields
|
||||
available in the credential object, the former then marks the
|
||||
subset of those that have been augmented. Note that augmented
|
||||
fields are unsuitable for authorization decisions, as they may be
|
||||
retrieved at different times, thus being subject to races. Hence,
|
||||
augmented fields should be used exclusively for informational
|
||||
purposes.
|
||||
<para>Similar to <function>sd_bus_creds_get_mask()</function>, the function
|
||||
<function>sd_bus_creds_get_augmented_mask()</function> returns a bitmask of field constants. The mask
|
||||
indicates which credential fields have been retrieved in a non-atomic fashion. For credential objects
|
||||
created via <function>sd_bus_creds_new_from_pid()</function> or
|
||||
<function>sd_bus_creds_new_from_pidfd()</function>, this mask will be identical to the mask returned by
|
||||
<function>sd_bus_creds_get_mask()</function>. However, for credential objects retrieved via
|
||||
<function>sd_bus_get_name_creds()</function>, this mask will be set for the credential fields that could
|
||||
not be determined atomically at peer connection time, and which were later added by reading augmenting
|
||||
credential data from <filename>/proc/</filename>. Similarly, for credential objects retrieved via
|
||||
<function>sd_bus_get_owner_creds()</function>, the mask is set for the fields that could not be
|
||||
determined atomically at bus creation time, but have been augmented. Similarly, for credential objects
|
||||
retrieved via <function>sd_bus_message_get_creds()</function>, the mask is set for the fields that could
|
||||
not be determined atomically at message sending time, but have been augmented. The mask returned by
|
||||
<function>sd_bus_creds_get_augmented_mask()</function> is always a subset of (or identical to) the mask
|
||||
returned by <function>sd_bus_creds_get_mask()</function> for the same object. The latter call hence
|
||||
returns all credential fields available in the credential object, the former then marks the subset of
|
||||
those that have been augmented. Note that augmented fields are unsuitable for authorization decisions, as
|
||||
they may be retrieved at different times, thus being subject to races. Hence, augmented fields should be
|
||||
used exclusively for informational purposes.
|
||||
</para>
|
||||
|
||||
<para><function>sd_bus_creds_ref()</function> creates a new
|
||||
@ -234,9 +217,9 @@
|
||||
<refsect1>
|
||||
<title>Return Value</title>
|
||||
|
||||
<para>On success, <function>sd_bus_creds_new_from_pid()</function>
|
||||
returns 0 or a positive integer. On failure, it returns a negative
|
||||
errno-style error code.</para>
|
||||
<para>On success, <function>sd_bus_creds_new_from_pid()</function> and
|
||||
<function>sd_bus_creds_new_from_pidfd()</function> return 0 or a positive integer. On failure, they return
|
||||
a negative errno-style error code.</para>
|
||||
|
||||
<para><function>sd_bus_creds_get_mask()</function> returns the
|
||||
mask of successfully acquired fields.</para>
|
||||
@ -256,9 +239,9 @@
|
||||
<refsect1>
|
||||
<title>Reference ownership</title>
|
||||
|
||||
<para>Function <function>sd_bus_creds_new_from_pid()</function>
|
||||
creates a new object and the caller owns the sole reference. When
|
||||
not needed anymore, this reference should be destroyed with
|
||||
<para>The functions <function>sd_bus_creds_new_from_pid()</function> and
|
||||
<function>sd_bus_creds_new_from_pidfd()</function> create a new object and the caller owns the sole
|
||||
reference. When not needed anymore, this reference should be destroyed with
|
||||
<citerefentry><refentrytitle>sd_bus_creds_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
|
||||
</para>
|
||||
|
||||
@ -307,6 +290,7 @@
|
||||
<function>sd_bus_creds_unref()</function> were added in version 209.</para>
|
||||
<para><function>sd_bus_creds_get_augmented_mask()</function> was added in version 223.</para>
|
||||
<para><function>sd_bus_creds_unrefp()</function> was added in version 229.</para>
|
||||
<para><function>sd_bus_creds_new_from_pidfd()</function> was added in version 256.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
|
@ -930,12 +930,14 @@ int getpeersec(int fd, char **ret) {
|
||||
}
|
||||
|
||||
int getpeergroups(int fd, gid_t **ret) {
|
||||
socklen_t n = sizeof(gid_t) * 64;
|
||||
_cleanup_free_ gid_t *d = NULL;
|
||||
|
||||
assert(fd >= 0);
|
||||
assert(ret);
|
||||
|
||||
long ngroups_max = sysconf(_SC_NGROUPS_MAX);
|
||||
socklen_t n = sizeof(gid_t) * MAX((socklen_t) ngroups_max, 64U);
|
||||
|
||||
for (;;) {
|
||||
d = malloc(n);
|
||||
if (!d)
|
||||
@ -953,7 +955,7 @@ int getpeergroups(int fd, gid_t **ret) {
|
||||
assert_se(n % sizeof(gid_t) == 0);
|
||||
n /= sizeof(gid_t);
|
||||
|
||||
if ((socklen_t) (int) n != n)
|
||||
if (n > INT_MAX)
|
||||
return -E2BIG;
|
||||
|
||||
*ret = TAKE_PTR(d);
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "bus-common-errors.h"
|
||||
#include "bus-get-properties.h"
|
||||
#include "bus-log-control-api.h"
|
||||
#include "bus-util.h"
|
||||
#include "chase.h"
|
||||
#include "confidential-virt.h"
|
||||
#include "data-fd-util.h"
|
||||
@ -464,18 +465,13 @@ static int bus_get_unit_by_name(Manager *m, sd_bus_message *message, const char
|
||||
* its sleeve: if the name is specified empty we use the client's unit. */
|
||||
|
||||
if (isempty(name)) {
|
||||
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
|
||||
pid_t pid;
|
||||
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
|
||||
|
||||
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
|
||||
r = bus_query_sender_pidref(message, &pidref);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_creds_get_pid(creds, &pid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
u = manager_get_unit_by_pid(m, pid);
|
||||
u = manager_get_unit_by_pidref(m, &pidref);
|
||||
if (!u)
|
||||
return sd_bus_error_set(error, BUS_ERROR_NO_SUCH_UNIT, "Client not member of any unit.");
|
||||
} else {
|
||||
@ -542,7 +538,7 @@ static int method_get_unit(sd_bus_message *message, void *userdata, sd_bus_error
|
||||
|
||||
static int method_get_unit_by_pid(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
Manager *m = ASSERT_PTR(userdata);
|
||||
pid_t pid;
|
||||
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
|
||||
Unit *u;
|
||||
int r;
|
||||
|
||||
@ -552,27 +548,20 @@ static int method_get_unit_by_pid(sd_bus_message *message, void *userdata, sd_bu
|
||||
|
||||
/* Anyone can call this method */
|
||||
|
||||
r = sd_bus_message_read(message, "u", &pid);
|
||||
r = sd_bus_message_read(message, "u", &pidref.pid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (pid < 0)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid PID " PID_FMT, pid);
|
||||
|
||||
if (pid == 0) {
|
||||
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
|
||||
|
||||
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_creds_get_pid(creds, &pid);
|
||||
if (pidref.pid < 0)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid PID " PID_FMT, pidref.pid);
|
||||
if (pidref.pid == 0) {
|
||||
r = bus_query_sender_pidref(message, &pidref);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
u = manager_get_unit_by_pid(m, pid);
|
||||
u = manager_get_unit_by_pidref(m, &pidref);
|
||||
if (!u)
|
||||
return sd_bus_error_setf(error, BUS_ERROR_NO_UNIT_FOR_PID, "PID "PID_FMT" does not belong to any loaded unit.", pid);
|
||||
return sd_bus_error_setf(error, BUS_ERROR_NO_UNIT_FOR_PID, "PID "PID_FMT" does not belong to any loaded unit.", pidref.pid);
|
||||
|
||||
return reply_unit_path(u, message, error);
|
||||
}
|
||||
@ -601,21 +590,16 @@ static int method_get_unit_by_invocation_id(sd_bus_message *message, void *userd
|
||||
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid invocation ID");
|
||||
|
||||
if (sd_id128_is_null(id)) {
|
||||
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
|
||||
pid_t pid;
|
||||
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
|
||||
|
||||
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
|
||||
r = bus_query_sender_pidref(message, &pidref);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_creds_get_pid(creds, &pid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
u = manager_get_unit_by_pid(m, pid);
|
||||
u = manager_get_unit_by_pidref(m, &pidref);
|
||||
if (!u)
|
||||
return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT,
|
||||
"Client " PID_FMT " not member of any unit.", pid);
|
||||
"Client " PID_FMT " not member of any unit.", pidref.pid);
|
||||
} else {
|
||||
u = hashmap_get(m->units_by_invocation_id, &id);
|
||||
if (!u)
|
||||
@ -2934,7 +2918,7 @@ static int method_dump_unit_descriptor_store(sd_bus_message *message, void *user
|
||||
}
|
||||
|
||||
static int aux_scope_from_message(Manager *m, sd_bus_message *message, Unit **ret_scope, sd_bus_error *error) {
|
||||
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
|
||||
_cleanup_(pidref_done) PidRef sender_pidref = PIDREF_NULL;
|
||||
_cleanup_free_ PidRef *pidrefs = NULL;
|
||||
const char *name;
|
||||
Unit *from, *scope;
|
||||
@ -2942,20 +2926,15 @@ static int aux_scope_from_message(Manager *m, sd_bus_message *message, Unit **re
|
||||
CGroupContext *cc;
|
||||
size_t n_pids = 0;
|
||||
uint64_t flags;
|
||||
pid_t pid;
|
||||
int r;
|
||||
|
||||
assert(ret_scope);
|
||||
|
||||
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
|
||||
r = bus_query_sender_pidref(message, &sender_pidref);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_creds_get_pid(creds, &pid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
from = manager_get_unit_by_pid(m, pid);
|
||||
from = manager_get_unit_by_pidref(m, &sender_pidref);
|
||||
if (!from)
|
||||
return sd_bus_error_set(error, BUS_ERROR_NO_SUCH_UNIT, "Client not member of any unit.");
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "alloc-util.h"
|
||||
#include "bus-common-errors.h"
|
||||
#include "bus-get-properties.h"
|
||||
#include "bus-util.h"
|
||||
#include "dbus-cgroup.h"
|
||||
#include "dbus-kill.h"
|
||||
#include "dbus-manager.h"
|
||||
@ -84,7 +85,7 @@ static int bus_scope_set_transient_property(
|
||||
return bus_set_transient_oom_policy(u, name, &s->oom_policy, message, flags, error);
|
||||
|
||||
if (streq(name, "PIDs")) {
|
||||
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
|
||||
_cleanup_(pidref_done) PidRef sender_pidref = PIDREF_NULL;
|
||||
unsigned n = 0;
|
||||
|
||||
r = sd_bus_message_enter_container(message, 'a', "u");
|
||||
@ -94,7 +95,7 @@ static int bus_scope_set_transient_property(
|
||||
for (;;) {
|
||||
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
|
||||
uint32_t upid;
|
||||
pid_t pid;
|
||||
PidRef *p;
|
||||
|
||||
r = sd_bus_message_read(message, "u", &upid);
|
||||
if (r < 0)
|
||||
@ -103,28 +104,27 @@ static int bus_scope_set_transient_property(
|
||||
break;
|
||||
|
||||
if (upid == 0) {
|
||||
if (!creds) {
|
||||
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
|
||||
if (!pidref_is_set(&sender_pidref)) {
|
||||
r = bus_query_sender_pidref(message, &sender_pidref);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
r = sd_bus_creds_get_pid(creds, &pid);
|
||||
p = &sender_pidref;
|
||||
} else {
|
||||
r = pidref_set_pid(&pidref, upid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else
|
||||
pid = (uid_t) upid;
|
||||
|
||||
r = pidref_set_pid(&pidref, pid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
p = &pidref;
|
||||
}
|
||||
|
||||
r = unit_pid_attachable(u, &pidref, error);
|
||||
r = unit_pid_attachable(u, p, error);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
|
||||
r = unit_watch_pidref(u, &pidref, /* exclusive= */ false);
|
||||
r = unit_watch_pidref(u, p, /* exclusive= */ false);
|
||||
if (r < 0 && r != -EEXIST)
|
||||
return r;
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "bus-common-errors.h"
|
||||
#include "bus-get-properties.h"
|
||||
#include "bus-polkit.h"
|
||||
#include "bus-util.h"
|
||||
#include "cgroup-util.h"
|
||||
#include "condition.h"
|
||||
#include "dbus-job.h"
|
||||
@ -1485,7 +1486,7 @@ int bus_unit_method_attach_processes(sd_bus_message *message, void *userdata, sd
|
||||
if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(u)))
|
||||
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Unit is not active, refusing.");
|
||||
|
||||
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID, &creds);
|
||||
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_PIDFD, &creds);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -1496,7 +1497,6 @@ int bus_unit_method_attach_processes(sd_bus_message *message, void *userdata, sd
|
||||
_cleanup_(pidref_freep) PidRef *pidref = NULL;
|
||||
uid_t process_uid, sender_uid;
|
||||
uint32_t upid;
|
||||
pid_t pid;
|
||||
|
||||
r = sd_bus_message_read(message, "u", &upid);
|
||||
if (r < 0)
|
||||
@ -1505,13 +1505,14 @@ int bus_unit_method_attach_processes(sd_bus_message *message, void *userdata, sd
|
||||
break;
|
||||
|
||||
if (upid == 0) {
|
||||
r = sd_bus_creds_get_pid(creds, &pid);
|
||||
_cleanup_(pidref_done) PidRef p = PIDREF_NULL;
|
||||
r = bus_creds_get_pidref(creds, &p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else
|
||||
pid = (uid_t) upid;
|
||||
|
||||
r = pidref_new_from_pid(pid, &pidref);
|
||||
r = pidref_dup(&p, &pidref);
|
||||
} else
|
||||
r = pidref_new_from_pid(upid, &pidref);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -1537,9 +1538,9 @@ int bus_unit_method_attach_processes(sd_bus_message *message, void *userdata, sd
|
||||
return sd_bus_error_set_errnof(error, r, "Failed to retrieve process UID: %m");
|
||||
|
||||
if (process_uid != sender_uid)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Process " PID_FMT " not owned by client's UID. Refusing.", pid);
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Process " PID_FMT " not owned by client's UID. Refusing.", pidref->pid);
|
||||
if (process_uid != u->ref_uid)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Process " PID_FMT " not owned by target unit's UID. Refusing.", pid);
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Process " PID_FMT " not owned by target unit's UID. Refusing.", pidref->pid);
|
||||
}
|
||||
|
||||
r = set_ensure_consume(&pids, &pidref_hash_ops_free, TAKE_PTR(pidref));
|
||||
|
@ -232,6 +232,8 @@ static int mac_selinux_filter(sd_bus_message *message, void *userdata, sd_bus_er
|
||||
return 0;
|
||||
|
||||
path = sd_bus_message_get_path(message);
|
||||
if (!path)
|
||||
return 0;
|
||||
|
||||
if (object_path_startswith("/org/freedesktop/systemd1", path)) {
|
||||
r = mac_selinux_access_check(message, verb, error);
|
||||
@ -241,25 +243,20 @@ static int mac_selinux_filter(sd_bus_message *message, void *userdata, sd_bus_er
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (streq_ptr(path, "/org/freedesktop/systemd1/unit/self")) {
|
||||
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
|
||||
pid_t pid;
|
||||
if (streq(path, "/org/freedesktop/systemd1/unit/self")) {
|
||||
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
|
||||
|
||||
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
|
||||
r = bus_query_sender_pidref(message, &pidref);
|
||||
if (r < 0)
|
||||
return 0;
|
||||
|
||||
r = sd_bus_creds_get_pid(creds, &pid);
|
||||
if (r < 0)
|
||||
return 0;
|
||||
|
||||
u = manager_get_unit_by_pid(m, pid);
|
||||
u = manager_get_unit_by_pidref(m, &pidref);
|
||||
} else {
|
||||
r = manager_get_job_from_dbus_path(m, path, &j);
|
||||
if (r >= 0)
|
||||
u = j->unit;
|
||||
else
|
||||
manager_load_unit_from_dbus_path(m, path, NULL, &u);
|
||||
(void) manager_load_unit_from_dbus_path(m, path, NULL, &u);
|
||||
}
|
||||
if (!u)
|
||||
return 0;
|
||||
@ -280,24 +277,19 @@ static int find_unit(Manager *m, sd_bus *bus, const char *path, Unit **unit, sd_
|
||||
assert(bus);
|
||||
assert(path);
|
||||
|
||||
if (streq_ptr(path, "/org/freedesktop/systemd1/unit/self")) {
|
||||
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
|
||||
if (streq(path, "/org/freedesktop/systemd1/unit/self")) {
|
||||
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
|
||||
sd_bus_message *message;
|
||||
pid_t pid;
|
||||
|
||||
message = sd_bus_get_current_message(bus);
|
||||
if (!message)
|
||||
return 0;
|
||||
|
||||
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
|
||||
r = bus_query_sender_pidref(message, &pidref);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_creds_get_pid(creds, &pid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
u = manager_get_unit_by_pid(m, pid);
|
||||
u = manager_get_unit_by_pidref(m, &pidref);
|
||||
if (!u)
|
||||
return 0;
|
||||
} else {
|
||||
|
@ -248,7 +248,7 @@ int mac_selinux_access_check_internal(
|
||||
tclass = "system";
|
||||
}
|
||||
|
||||
sd_bus_creds_get_cmdline(creds, &cmdline);
|
||||
(void) sd_bus_creds_get_cmdline(creds, &cmdline);
|
||||
cl = strv_join(cmdline, " ");
|
||||
|
||||
struct audit_info audit_info = {
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
@ -483,8 +483,9 @@ _public_ int sd_bus_get_name_creds(
|
||||
}
|
||||
|
||||
if (mask != 0) {
|
||||
bool need_pid, need_uid, need_gids, need_selinux, need_separate_calls, need_pidfd, need_augment;
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
bool need_pid, need_uid, need_selinux, need_separate_calls;
|
||||
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
|
||||
|
||||
c = bus_creds_new();
|
||||
if (!c)
|
||||
@ -498,20 +499,25 @@ _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_uid = mask & SD_BUS_CREDS_EUID;
|
||||
need_selinux = mask & SD_BUS_CREDS_SELINUX_CONTEXT;
|
||||
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));
|
||||
|
||||
if (need_pid + need_uid + need_selinux > 1) {
|
||||
need_pid = (mask & SD_BUS_CREDS_PID) || need_augment;
|
||||
need_uid = mask & SD_BUS_CREDS_EUID;
|
||||
need_gids = mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
|
||||
need_selinux = mask & SD_BUS_CREDS_SELINUX_CONTEXT;
|
||||
need_pidfd = (mask & SD_BUS_CREDS_PIDFD) || need_augment;
|
||||
|
||||
if (need_pid + need_uid + need_selinux + need_pidfd + need_gids > 1) {
|
||||
|
||||
/* If we need more than one of the credentials, then use GetConnectionCredentials() */
|
||||
|
||||
@ -572,7 +578,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 +607,69 @@ _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 if (need_gids && streq(m, "UnixGroupIDs")) {
|
||||
|
||||
/* Note that D-Bus actualy only gives us a combined list of
|
||||
* primary gid and supplementary gids. And we don't know
|
||||
* which one the primary one is. We'll take the whole shebang
|
||||
* hence and use it as the supplementary group list, and not
|
||||
* initialize the primary gid field. This is slightly
|
||||
* incorrect of course, but only slightly, as in effect if
|
||||
* the primary gid is also listed in the supplementary gid
|
||||
* it has zero effect. */
|
||||
|
||||
r = sd_bus_message_enter_container(reply, 'v', "au");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_enter_container(reply, 'a', "u");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
for (;;) {
|
||||
uint32_t u;
|
||||
|
||||
r = sd_bus_message_read(reply, "u", &u);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
if (!GREEDY_REALLOC(c->supplementary_gids, c->n_supplementary_gids+1))
|
||||
return -ENOMEM;
|
||||
|
||||
c->supplementary_gids[c->n_supplementary_gids++] = (gid_t) u;
|
||||
}
|
||||
|
||||
r = sd_bus_message_exit_container(reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_message_exit_container(reply);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
c->mask |= SD_BUS_CREDS_SUPPLEMENTARY_GIDS;
|
||||
} else {
|
||||
r = sd_bus_message_skip(reply, "v");
|
||||
if (r < 0)
|
||||
@ -614,7 +685,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 +713,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 +783,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 +840,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 +861,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 +873,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 +937,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;
|
||||
|
||||
|
@ -640,8 +640,8 @@ _public_ int sd_bus_set_property(
|
||||
}
|
||||
|
||||
_public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_bus_creds **ret) {
|
||||
uint64_t missing;
|
||||
sd_bus_creds *c;
|
||||
int r;
|
||||
|
||||
assert_return(call, -EINVAL);
|
||||
assert_return(call->sealed, -EPERM);
|
||||
@ -653,36 +653,22 @@ _public_ int sd_bus_query_sender_creds(sd_bus_message *call, uint64_t mask, sd_b
|
||||
return -ENOTCONN;
|
||||
|
||||
c = sd_bus_message_get_creds(call);
|
||||
|
||||
/* All data we need? */
|
||||
if (c && (mask & ~SD_BUS_CREDS_AUGMENT & ~c->mask) == 0) {
|
||||
if (c)
|
||||
missing = mask & ~SD_BUS_CREDS_AUGMENT & ~c->mask;
|
||||
else
|
||||
missing = mask & ~SD_BUS_CREDS_AUGMENT;
|
||||
if (missing == 0) { /* All data we need? */
|
||||
*ret = sd_bus_creds_ref(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* No data passed? Or not enough data passed to retrieve the missing bits? */
|
||||
if (!c || !(c->mask & SD_BUS_CREDS_PID)) {
|
||||
/* We couldn't read anything from the call, let's try
|
||||
* to get it from the sender or peer. */
|
||||
/* There's a sender, use that */
|
||||
if (call->sender && call->bus->bus_client)
|
||||
return sd_bus_get_name_creds(call->bus, call->sender, mask, ret);
|
||||
|
||||
if (call->sender)
|
||||
/* There's a sender, but the creds are missing. */
|
||||
return sd_bus_get_name_creds(call->bus, call->sender, mask, ret);
|
||||
else
|
||||
/* There's no sender. For direct connections
|
||||
* the credentials of the AF_UNIX peer matter,
|
||||
* which may be queried via sd_bus_get_owner_creds(). */
|
||||
return sd_bus_get_owner_creds(call->bus, mask, ret);
|
||||
}
|
||||
|
||||
r = bus_creds_extend_by_pid(c, mask, ret);
|
||||
if (r == -ESRCH) {
|
||||
/* Process doesn't exist anymore? propagate the few things we have */
|
||||
*ret = sd_bus_creds_ref(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return r;
|
||||
/* There's no sender. For direct connections the credentials of the AF_UNIX peer matter, which may be
|
||||
* queried via sd_bus_get_owner_creds(). */
|
||||
return sd_bus_get_owner_creds(call->bus, mask, ret);
|
||||
}
|
||||
|
||||
_public_ int sd_bus_query_sender_privilege(sd_bus_message *call, int capability) {
|
||||
|
@ -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,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 *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(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(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 = pidref_set_pid(&pidref, pid);
|
||||
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);
|
||||
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;
|
||||
if (r == 0)
|
||||
return -ESRCH;
|
||||
|
||||
*ret = TAKE_PTR(c);
|
||||
return 0;
|
||||
return bus_creds_new_from_pidref(ret, &pidref, mask);
|
||||
}
|
||||
|
||||
_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;
|
||||
}
|
||||
|
||||
_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;
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -5,10 +5,39 @@
|
||||
|
||||
#include "sd-bus.h"
|
||||
|
||||
#include "bus-dump.h"
|
||||
#include "bus-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "process-util.h"
|
||||
#include "socket-util.h"
|
||||
#include "sort-util.h"
|
||||
#include "tests.h"
|
||||
#include "user-util.h"
|
||||
|
||||
static bool gid_list_contained(const gid_t *a, size_t n, const gid_t *b, size_t m) {
|
||||
assert_se(a || n == 0);
|
||||
assert_se(b || m == 0);
|
||||
|
||||
/* Checks if every entry in a[] is also in b[] */
|
||||
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
size_t j;
|
||||
|
||||
for (j = 0; j < m; j++)
|
||||
if (a[i] == b[j])
|
||||
break;
|
||||
|
||||
if (j >= m)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool gid_list_same(const gid_t *a, size_t n, const gid_t *b, size_t m) {
|
||||
return gid_list_contained(a, n, b, m) &&
|
||||
gid_list_contained(b, m, a, n);
|
||||
}
|
||||
|
||||
static void *server(void *p) {
|
||||
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
||||
@ -27,11 +56,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|SD_BUS_CREDS_SUPPLEMENTARY_GIDS) >= 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|SD_BUS_CREDS_SUPPLEMENTARY_GIDS, &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 +76,26 @@ 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 gid_t *gl = NULL;
|
||||
int n;
|
||||
n = sd_bus_creds_get_supplementary_gids(c, &gl);
|
||||
|
||||
if (n >= 0) {
|
||||
_cleanup_free_ gid_t *gg = NULL;
|
||||
r = getgroups_alloc(&gg);
|
||||
assert_se(r >= 0);
|
||||
|
||||
assert_se(gid_list_same(gl, n, gg, r));
|
||||
}
|
||||
|
||||
const char *comm;
|
||||
assert_se(sd_bus_creds_get_comm(c, &comm) >= 0);
|
||||
assert_se(pid_get_comm(0, &our_comm) >= 0);
|
||||
|
@ -759,8 +759,8 @@ static int create_session(
|
||||
void *userdata,
|
||||
sd_bus_error *error,
|
||||
uid_t uid,
|
||||
pid_t pid,
|
||||
int pidfd,
|
||||
pid_t leader_pid,
|
||||
int leader_pidfd,
|
||||
const char *service,
|
||||
const char *type,
|
||||
const char *class,
|
||||
@ -793,32 +793,18 @@ static int create_session(
|
||||
if (flags != 0)
|
||||
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Flags must be zero.");
|
||||
|
||||
if (pidfd >= 0) {
|
||||
r = pidref_set_pidfd(&leader, pidfd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else if (pid == 0) {
|
||||
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
|
||||
pid_t p;
|
||||
if (leader_pidfd >= 0)
|
||||
r = pidref_set_pidfd(&leader, leader_pidfd);
|
||||
else if (leader_pid == 0)
|
||||
r = bus_query_sender_pidref(message, &leader);
|
||||
else {
|
||||
if (leader_pid < 0)
|
||||
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Leader PID is not valid");
|
||||
|
||||
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_creds_get_pid(creds, &p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = pidref_set_pid(&leader, p);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else {
|
||||
assert(pid > 0);
|
||||
|
||||
r = pidref_set_pid(&leader, pid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = pidref_set_pid(&leader, leader_pid);
|
||||
}
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (leader.pid == 1 || leader.pid == getpid_cached())
|
||||
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
|
||||
@ -1096,32 +1082,32 @@ fail:
|
||||
|
||||
static int method_create_session(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
const char *service, *type, *class, *cseat, *tty, *display, *remote_user, *remote_host, *desktop;
|
||||
pid_t leader;
|
||||
pid_t leader_pid;
|
||||
uint32_t vtnr;
|
||||
uid_t uid;
|
||||
int remote;
|
||||
uint32_t vtnr = 0;
|
||||
int r;
|
||||
int remote, r;
|
||||
|
||||
assert(message);
|
||||
|
||||
assert_cc(sizeof(pid_t) == sizeof(uint32_t));
|
||||
assert_cc(sizeof(uid_t) == sizeof(uint32_t));
|
||||
|
||||
r = sd_bus_message_read(message,
|
||||
"uusssssussbss",
|
||||
&uid,
|
||||
&leader,
|
||||
&service,
|
||||
&type,
|
||||
&class,
|
||||
&desktop,
|
||||
&cseat,
|
||||
&vtnr,
|
||||
&tty,
|
||||
&display,
|
||||
&remote,
|
||||
&remote_user,
|
||||
&remote_host);
|
||||
r = sd_bus_message_read(
|
||||
message,
|
||||
"uusssssussbss",
|
||||
&uid,
|
||||
&leader_pid,
|
||||
&service,
|
||||
&type,
|
||||
&class,
|
||||
&desktop,
|
||||
&cseat,
|
||||
&vtnr,
|
||||
&tty,
|
||||
&display,
|
||||
&remote,
|
||||
&remote_user,
|
||||
&remote_host);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -1130,7 +1116,7 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
|
||||
userdata,
|
||||
error,
|
||||
uid,
|
||||
leader,
|
||||
leader_pid,
|
||||
/* pidfd = */ -EBADF,
|
||||
service,
|
||||
type,
|
||||
@ -1148,29 +1134,28 @@ static int method_create_session(sd_bus_message *message, void *userdata, sd_bus
|
||||
|
||||
static int method_create_session_pidfd(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
const char *service, *type, *class, *cseat, *tty, *display, *remote_user, *remote_host, *desktop;
|
||||
int leaderfd = -EBADF;
|
||||
uid_t uid;
|
||||
int remote;
|
||||
uint32_t vtnr = 0;
|
||||
uint64_t flags;
|
||||
int r;
|
||||
uint32_t vtnr;
|
||||
uid_t uid;
|
||||
int leader_fd = -EBADF, remote, r;
|
||||
|
||||
r = sd_bus_message_read(message,
|
||||
"uhsssssussbsst",
|
||||
&uid,
|
||||
&leaderfd,
|
||||
&service,
|
||||
&type,
|
||||
&class,
|
||||
&desktop,
|
||||
&cseat,
|
||||
&vtnr,
|
||||
&tty,
|
||||
&display,
|
||||
&remote,
|
||||
&remote_user,
|
||||
&remote_host,
|
||||
&flags);
|
||||
r = sd_bus_message_read(
|
||||
message,
|
||||
"uhsssssussbsst",
|
||||
&uid,
|
||||
&leader_fd,
|
||||
&service,
|
||||
&type,
|
||||
&class,
|
||||
&desktop,
|
||||
&cseat,
|
||||
&vtnr,
|
||||
&tty,
|
||||
&display,
|
||||
&remote,
|
||||
&remote_user,
|
||||
&remote_host,
|
||||
&flags);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -1179,8 +1164,8 @@ static int method_create_session_pidfd(sd_bus_message *message, void *userdata,
|
||||
userdata,
|
||||
error,
|
||||
uid,
|
||||
/* pid = */ 0,
|
||||
leaderfd,
|
||||
/* leader_pid = */ 0,
|
||||
leader_fd,
|
||||
service,
|
||||
type,
|
||||
class,
|
||||
@ -3506,7 +3491,6 @@ static int method_inhibit(sd_bus_message *message, void *userdata, sd_bus_error
|
||||
Manager *m = ASSERT_PTR(userdata);
|
||||
InhibitMode mm;
|
||||
InhibitWhat w;
|
||||
pid_t pid;
|
||||
uid_t uid;
|
||||
int r;
|
||||
|
||||
@ -3557,7 +3541,7 @@ static int method_inhibit(sd_bus_message *message, void *userdata, sd_bus_error
|
||||
if (r == 0)
|
||||
return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
|
||||
|
||||
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID, &creds);
|
||||
r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID|SD_BUS_CREDS_PID|SD_BUS_CREDS_PIDFD, &creds);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@ -3565,14 +3549,10 @@ static int method_inhibit(sd_bus_message *message, void *userdata, sd_bus_error
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_creds_get_pid(creds, &pid);
|
||||
r = bus_creds_get_pidref(creds, &pidref);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = pidref_set_pid(&pidref, pid);
|
||||
if (r < 0)
|
||||
return sd_bus_error_set_errnof(error, r, "Failed pin source process "PID_FMT": %m", pid);
|
||||
|
||||
if (hashmap_size(m->inhibitors) >= m->inhibitors_max)
|
||||
return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED,
|
||||
"Maximum number of inhibitors (%" PRIu64 ") reached, refusing further inhibitors.",
|
||||
|
@ -710,3 +710,47 @@ int bus_property_get_string_set(
|
||||
|
||||
return bus_message_append_string_set(reply, *s);
|
||||
}
|
||||
|
||||
int bus_creds_get_pidref(
|
||||
sd_bus_creds *c,
|
||||
PidRef *ret) {
|
||||
|
||||
int pidfd = -EBADF;
|
||||
pid_t pid;
|
||||
int r;
|
||||
|
||||
assert(c);
|
||||
assert(ret);
|
||||
|
||||
r = sd_bus_creds_get_pid(c, &pid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = sd_bus_creds_get_pidfd_dup(c, &pidfd);
|
||||
if (r < 0 && r != -ENODATA)
|
||||
return r;
|
||||
|
||||
*ret = (PidRef) {
|
||||
.pid = pid,
|
||||
.fd = pidfd,
|
||||
};
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bus_query_sender_pidref(
|
||||
sd_bus_message *m,
|
||||
PidRef *ret) {
|
||||
|
||||
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
assert(ret);
|
||||
|
||||
r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_PID|SD_BUS_CREDS_PIDFD, &creds);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return bus_creds_get_pidref(creds, ret);
|
||||
}
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
#include "errno-util.h"
|
||||
#include "macro.h"
|
||||
#include "pidref.h"
|
||||
#include "runtime-scope.h"
|
||||
#include "set.h"
|
||||
#include "string-util.h"
|
||||
@ -73,3 +74,6 @@ extern const struct hash_ops bus_message_hash_ops;
|
||||
int bus_message_append_string_set(sd_bus_message *m, Set *s);
|
||||
|
||||
int bus_property_get_string_set(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
|
||||
|
||||
int bus_creds_get_pidref(sd_bus_creds *c, PidRef *ret);
|
||||
int bus_query_sender_pidref(sd_bus_message *m, PidRef *ret);
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user