bus-kernel.c revision 11c9f1e48a683fb2e78ee531016099d567baa19a
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek This file is part of systemd.
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek Copyright 2013 Lennart Poettering
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek systemd is free software; you can redistribute it and/or modify it
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek under the terms of the GNU Lesser General Public License as published by
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek the Free Software Foundation; either version 2.1 of the License, or
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek (at your option) any later version.
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek systemd is distributed in the hope that it will be useful, but
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek WITHOUT ANY WARRANTY; without even the implied warranty of
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek Lesser General Public License for more details.
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek You should have received a copy of the GNU Lesser General Public License
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek along with systemd; If not, see <http://www.gnu.org/licenses/>.
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek/* When we include libgen.h because we need dirname() we immediately
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek * undefine basename() since libgen.h defines it as a macro to the POSIX
8eea868708923a092ee85d6146ba4c04b7baea06Zbigniew Jędrzejewski-Szmek * version which is really broken. We prefer GNU basename(). */
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek#define UNIQUE_NAME_MAX (3+DECIMAL_STR_MAX(uint64_t))
8eea868708923a092ee85d6146ba4c04b7baea06Zbigniew Jędrzejewski-Szmekint bus_kernel_parse_unique_name(const char *s, uint64_t *id) {
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmekstatic void append_payload_vec(struct kdbus_item **d, const void *p, size_t sz) {
8eea868708923a092ee85d6146ba4c04b7baea06Zbigniew Jędrzejewski-Szmek /* Note that p can be NULL, which encodes a region full of
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek * zeroes, which is useful to optimize certain padding
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek (*d)->size = offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec);
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek (*d)->type = KDBUS_ITEM_PAYLOAD_VEC;
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek (*d)->vec.address = PTR_TO_UINT64(p);
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmekstatic void append_payload_memfd(struct kdbus_item **d, int memfd, size_t start, size_t sz) {
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek (*d)->size = offsetof(struct kdbus_item, memfd) + sizeof(struct kdbus_memfd);
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek (*d)->type = KDBUS_ITEM_PAYLOAD_MEMFD;
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmek *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
2968644080fd103062f070e83edd620e0a58c44dZbigniew Jędrzejewski-Szmekstatic void append_destination(struct kdbus_item **d, const char *s, size_t length) {
assert(d);
assert(s);
*d = ALIGN8_PTR(*d);
struct kdbus_item *i;
assert(d);
i = ALIGN8_PTR(*d);
return &i->bloom_filter;
assert(d);
*d = ALIGN8_PTR(*d);
assert(t);
void *data;
assert(m);
bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "message-type", bus_message_type_to_string(m->header->type));
if (m->interface)
if (m->member)
if (m->path) {
bloom_add_prefixes(data, m->bus->bloom_size, m->bus->bloom_n_hash, "path-slash-prefix", m->path, '/');
r = sd_bus_message_rewind(m, true);
const char *t, *contents;
char type;
r = sd_bus_message_exit_container(m);
struct kdbus_item *d;
const char *destination;
bool well_known;
assert(b);
assert(m);
if (m->kdbus)
if (destination) {
well_known = r == 0;
well_known = false;
sizeof(struct kdbus_memfd)));
if (well_known) {
if (m->n_fds > 0)
if (!m->kdbus) {
r = -ENOMEM;
goto fail;
m->free_kdbus = true;
if (well_known)
if (well_known)
goto fail;
goto fail;
if (m->n_fds > 0)
fail:
m->poisoned = true;
assert(m);
static void message_set_timestamp(sd_bus *bus, sd_bus_message *m, const struct kdbus_timestamp *ts) {
assert(m);
if (!ts)
struct kdbus_item *d;
unsigned n_fds = 0;
bool last_was_memfd = false;
assert(k);
size_t l;
switch (d->type) {
case KDBUS_ITEM_PAYLOAD_OFF:
if (!header) {
last_was_memfd = false;
case KDBUS_ITEM_PAYLOAD_MEMFD:
return -EBADMSG;
last_was_memfd = true;
case KDBUS_ITEM_FDS: {
return -ENOMEM;
fds = f;
n_fds += j;
case KDBUS_ITEM_SECLABEL:
return -EBADMSG;
if (!header)
return -EBADMSG;
return -EBADMSG;
return -EPROTOTYPE;
bus,
seclabel, 0, &m);
size_t l;
switch (d->type) {
case KDBUS_ITEM_PAYLOAD_OFF: {
if (!part) {
r = -ENOMEM;
goto fail;
case KDBUS_ITEM_PAYLOAD_MEMFD: {
r = -EBADMSG;
goto fail;
if (!part) {
r = -ENOMEM;
goto fail;
case KDBUS_ITEM_PIDS:
case KDBUS_ITEM_CREDS:
case KDBUS_ITEM_TIMESTAMP:
case KDBUS_ITEM_PID_COMM:
case KDBUS_ITEM_TID_COMM:
case KDBUS_ITEM_EXE:
case KDBUS_ITEM_CMDLINE:
case KDBUS_ITEM_CGROUP:
m->creds.mask |= (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) & bus->creds_mask;
goto fail;
case KDBUS_ITEM_AUDIT:
case KDBUS_ITEM_CAPS:
r = -EBADMSG;
goto fail;
m->creds.mask |= (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS) & bus->creds_mask;
case KDBUS_ITEM_DST_NAME:
r = -EBADMSG;
goto fail;
case KDBUS_ITEM_OWNED_NAME:
r = -EBADMSG;
goto fail;
char **wkn;
size_t n;
if (!wkn) {
r = -ENOMEM;
goto fail;
case KDBUS_ITEM_AUXGROUPS:
size_t i, n;
gid_t *g;
r = -ENOMEM;
goto fail;
g[i] = d->data64[i];
case KDBUS_ITEM_FDS:
case KDBUS_ITEM_SECLABEL:
r = bus_message_parse_fields(m);
goto fail;
r = -EBADMSG;
goto fail;
r = -EBADMSG;
goto fail;
r = -EBADMSG;
goto fail;
r = -EBADMSG;
goto fail;
if (destination)
snprintf(m->destination_buffer, sizeof(m->destination_buffer), ":1.%llu", (unsigned long long) k->dst_id);
m->kdbus = k;
m->release_kdbus = true;
m->free_fds = true;
fail:
unset_memfds(m);
const char *name;
assert(b);
if (b->is_server)
return -EINVAL;
if (b->description) {
return -ENOMEM;
name = g;
return -ENOMEM;
return -ENOMEM;
name = g;
if (!b->description)
return -ENOMEM;
if (b->fake_creds_valid)
if (b->fake_pids_valid)
if (b->fake_label) {
if (b->fake_creds_valid) {
if (b->fake_pids_valid) {
if (b->fake_label) {
return -ESOCKTNOSUPPORT;
return -errno;
if (!b->kdbus_buffer) {
r = -errno;
goto fail;
r = -ESOCKTNOSUPPORT;
goto fail;
r = -EOPNOTSUPP;
goto fail;
r = -ENOMEM;
goto fail;
b->is_kernel = true;
b->bus_client = true;
return bus_start_running(b);
fail:
assert(b);
if (b->is_server)
return -EINVAL;
if (b->input_fd < 0)
return -errno;
return bus_kernel_take_fd(b);
return -errno;
struct kdbus_item *d;
assert(k);
assert(m);
* kernel, so that it can pass CPU time/scheduling to the
if (hint_sync_call) {
sd_bus_error_setf(&error, SD_BUS_ERROR_SERVICE_UNKNOWN, "Destination %s not known", m->destination);
log_debug("Could not deliver message to %s as destination is not known. Ignoring.", m->destination);
sd_bus_error_setf(&error, SD_BUS_ERROR_SERVICE_UNKNOWN, "Activation of %s not requested", m->destination);
log_debug("Could not deliver message to %s as destination is not activated. Ignoring.", m->destination);
return -errno;
bus,
&error,
&reply);
} else if (hint_sync_call) {
struct kdbus_msg *k;
assert(k);
log_debug("Ignoring message with unknown payload type %llu.", (unsigned long long) k->payload_type);
static int push_name_owner_changed(
const char *name,
const char *old_owner,
const char *new_owner,
bus,
"/org/freedesktop/DBus",
m = NULL;
static int translate_name_change(
const struct kdbus_msg *k,
const struct kdbus_item *d,
assert(k);
assert(d);
if (d->type == KDBUS_ITEM_NAME_ADD || (d->name_change.old_id.flags & (KDBUS_NAME_IN_QUEUE|KDBUS_NAME_ACTIVATOR)))
old_owner[0] = 0;
if (d->type == KDBUS_ITEM_NAME_REMOVE || (d->name_change.new_id.flags & (KDBUS_NAME_IN_QUEUE|KDBUS_NAME_ACTIVATOR))) {
new_owner[0] = 0;
static int translate_id_change(
const struct kdbus_msg *k,
const struct kdbus_item *d,
assert(k);
assert(d);
return push_name_owner_changed(
ts);
static int translate_reply(
const struct kdbus_msg *k,
const struct kdbus_item *d,
assert(k);
assert(d);
bus,
k->cookie_reply,
m = NULL;
static int (* const translate[])(sd_bus *bus, const struct kdbus_msg *k, const struct kdbus_item *d, const struct kdbus_timestamp *ts) = {
assert(k);
if (d->type >= _KDBUS_ITEM_KERNEL_BASE && d->type < _KDBUS_ITEM_KERNEL_BASE + ELEMENTSOF(translate)) {
if (found)
return -EBADMSG;
found = d;
if (!found) {
struct kdbus_msg *k;
if (hint_priority) {
log_debug("%s: kdbus reports %" PRIu64 " dropped broadcast messages, ignoring.", strna(bus->description), (uint64_t) recv.dropped_msgs);
return -errno;
log_debug("Ignoring message with unknown payload type %llu.", (unsigned long long) k->payload_type);
struct memfd_cache *c;
int fd;
return -EOPNOTSUPP;
*mapped = 0;
*allocated = 0;
return fd;
if (size > 0)
struct memfd_cache *c;
assert(b);
for (i = 0; i < b->n_memfd_cache; i++)
uint64_t f = 0;
f |= KDBUS_NAME_QUEUE;
uint64_t m = 0;
m |= KDBUS_ATTACH_CREDS;
m |= KDBUS_ATTACH_PIDS;
m |= KDBUS_ATTACH_PID_COMM;
m |= KDBUS_ATTACH_TID_COMM;
m |= KDBUS_ATTACH_EXE;
m |= KDBUS_ATTACH_CMDLINE;
if (mask & (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))
m |= KDBUS_ATTACH_CGROUP;
if (mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS))
m |= KDBUS_ATTACH_CAPS;
m |= KDBUS_ATTACH_SECLABEL;
m |= KDBUS_ATTACH_AUDIT;
m |= KDBUS_ATTACH_NAMES;
m |= KDBUS_ATTACH_AUXGROUPS;
struct kdbus_item *n;
size_t l;
int fd;
assert(s);
if (fd < 0)
return -errno;
sizeof(struct kdbus_bloom_parameter);
n = KDBUS_ITEM_NEXT(n);
n = KDBUS_ITEM_NEXT(n);
return -ESOCKTNOSUPPORT;
return -errno;
return -ENOMEM;
return fd;
int fd;
if (path) {
return -ENOMEM;
if (fd < 0) {
if (path)
free(p);
return -errno;
if (path)
*path = p;
return fd;
struct kdbus_item *n;
const char *name;
int fd;
if (fd < 0)
return fd;
return -errno;
if (ep_path) {
return -ENOMEM;
*ep_path = p;
return fd;
return -errno;
return -errno;
struct kdbus_item *n;
return -errno;
char *n = NULL;
return -errno;
return -EIO;
*name = n;