bus-kernel.c revision 6517217d49e59938611b6c00965f44d46a255a1d
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering This file is part of systemd.
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering Copyright 2013 Lennart Poettering
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering systemd is free software; you can redistribute it and/or modify it
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering under the terms of the GNU Lesser General Public License as published by
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering (at your option) any later version.
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering systemd is distributed in the hope that it will be useful, but
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering Lesser General Public License for more details.
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering You should have received a copy of the GNU Lesser General Public License
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
b11d6a7bed4d867fb9f6ff4e7eb4ab20fcdc9301Lennart Poettering/* When we include libgen.h because we need dirname() we immediately
b11d6a7bed4d867fb9f6ff4e7eb4ab20fcdc9301Lennart Poettering * undefine basename() since libgen.h defines it as a macro to the XDG
b11d6a7bed4d867fb9f6ff4e7eb4ab20fcdc9301Lennart Poettering * version which is really broken. */
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#define UNIQUE_NAME_MAX (3+DECIMAL_STR_MAX(uint64_t))
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poetteringint bus_kernel_parse_unique_name(const char *s, uint64_t *id) {
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poetteringstatic void append_payload_vec(struct kdbus_item **d, const void *p, size_t sz) {
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering /* Note that p can be NULL, which encodes a region full of
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering * zeroes, which is useful to optimize certain padding
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering * conditions */
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering (*d)->size = offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec);
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poetteringstatic void append_payload_memfd(struct kdbus_item **d, int memfd, size_t start, size_t sz) {
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering (*d)->size = offsetof(struct kdbus_item, memfd) + sizeof(struct kdbus_memfd);
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poetteringstatic void append_destination(struct kdbus_item **d, const char *s, size_t length) {
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering (*d)->size = offsetof(struct kdbus_item, str) + length + 1;
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poetteringstatic struct kdbus_bloom_filter *append_bloom(struct kdbus_item **d, size_t length) {
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering i->size = offsetof(struct kdbus_item, bloom_filter) +
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering offsetof(struct kdbus_bloom_filter, data) +
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering *d = (struct kdbus_item *) ((uint8_t*) i + i->size);
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poetteringstatic void append_fds(struct kdbus_item **d, const int fds[], unsigned n_fds) {
522d85ae0a3dd80ec58033289c4f63ba7dfc63a8Lennart Poettering (*d)->size = offsetof(struct kdbus_item, fds) + sizeof(int) * n_fds;
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering memcpy((*d)->fds, fds, sizeof(int) * n_fds);
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poetteringstatic void add_bloom_arg(void *data, size_t size, unsigned n_hash, unsigned i, const char *t) {
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering *(e++) = '0' + (char) i;
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering bloom_add_pair(data, size, n_hash, buf, t);
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering bloom_add_prefixes(data, size, n_hash, buf, t, '.');
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering bloom_add_prefixes(data, size, n_hash, buf, t, '/');
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poetteringstatic int bus_message_setup_bloom(sd_bus_message *m, struct kdbus_bloom_filter *bloom) {
9fe4ea21bec739bfe0ebac5565f0539b0e25b317Lennart Poettering bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "message-type", bus_message_type_to_string(m->header->type));
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "interface", m->interface);
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "member", m->member);
f3e2e81d5385b9ffd84ed110d00eb347ec0e14f1Lennart Poettering bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "path", 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,
NULL,
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);
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;