bus-kernel.c revision 7ce9812173bd32dd46f2804b50815abf3fc18f11
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering This file is part of systemd.
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering Copyright 2013 Lennart Poettering
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering systemd is free software; you can redistribute it and/or modify it
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering under the terms of the GNU Lesser General Public License as published by
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering the Free Software Foundation; either version 2.1 of the License, or
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering (at your option) any later version.
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering systemd is distributed in the hope that it will be useful, but
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering Lesser General Public License for more details.
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering You should have received a copy of the GNU Lesser General Public License
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering#define UNIQUE_NAME_MAX (3+DECIMAL_STR_MAX(uint64_t))
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poetteringint bus_kernel_parse_unique_name(const char *s, uint64_t *id) {
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poetteringstatic void append_payload_vec(struct kdbus_item **d, const void *p, size_t sz) {
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering /* Note that p can be NULL, which encodes a region full of
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering * zeroes, which is useful to optimize certain padding
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering * conditions */
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering (*d)->size = offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec);
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
aaf7eb81be912e7bed939f31e3bc4c631b2552b3Lennart Poetteringstatic void append_payload_memfd(struct kdbus_item **d, int memfd, size_t start, size_t sz) {
aaf7eb81be912e7bed939f31e3bc4c631b2552b3Lennart Poettering (*d)->size = offsetof(struct kdbus_item, memfd) + sizeof(struct kdbus_memfd);
aaf7eb81be912e7bed939f31e3bc4c631b2552b3Lennart Poettering *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poetteringstatic void append_destination(struct kdbus_item **d, const char *s, size_t length) {
aaf7eb81be912e7bed939f31e3bc4c631b2552b3Lennart Poettering (*d)->size = offsetof(struct kdbus_item, str) + length + 1;
aaf7eb81be912e7bed939f31e3bc4c631b2552b3Lennart Poettering *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
aaf7eb81be912e7bed939f31e3bc4c631b2552b3Lennart Poetteringstatic struct kdbus_bloom_filter *append_bloom(struct kdbus_item **d, size_t length) {
aaf7eb81be912e7bed939f31e3bc4c631b2552b3Lennart Poettering i->size = offsetof(struct kdbus_item, bloom_filter) +
aaf7eb81be912e7bed939f31e3bc4c631b2552b3Lennart Poettering offsetof(struct kdbus_bloom_filter, data) +
aaf7eb81be912e7bed939f31e3bc4c631b2552b3Lennart Poettering *d = (struct kdbus_item *) ((uint8_t*) i + i->size);
aaf7eb81be912e7bed939f31e3bc4c631b2552b3Lennart Poetteringstatic void append_fds(struct kdbus_item **d, const int fds[], unsigned n_fds) {
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering (*d)->size = offsetof(struct kdbus_item, fds) + sizeof(int) * n_fds;
aaf7eb81be912e7bed939f31e3bc4c631b2552b3Lennart Poettering memcpy((*d)->fds, fds, sizeof(int) * n_fds);
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poetteringstatic void add_bloom_arg(void *data, size_t size, unsigned n_hash, unsigned i, const char *t) {
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering *(e++) = '0' + (char) i;
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering bloom_add_pair(data, size, n_hash, buf, t);
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering bloom_add_prefixes(data, size, n_hash, buf, t, '.');
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering bloom_add_prefixes(data, size, n_hash, buf, t, '/');
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poetteringstatic int bus_message_setup_bloom(sd_bus_message *m, struct kdbus_bloom_filter *bloom) {
aaf7eb81be912e7bed939f31e3bc4c631b2552b3Lennart Poettering bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "message-type", bus_message_type_to_string(m->header->type));
56f64d95763a799ba4475daf44d8e9f72a1bd474Michal Schmidt bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "interface", m->interface);
0bee65f0622c4faa8ac8ae771cc0c8a936dfa284Lennart Poettering bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "member", m->member);
0bee65f0622c4faa8ac8ae771cc0c8a936dfa284Lennart Poettering bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "path", m->path);
0bee65f0622c4faa8ac8ae771cc0c8a936dfa284Lennart Poettering bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "path-slash-prefix", m->path);
0bee65f0622c4faa8ac8ae771cc0c8a936dfa284Lennart Poettering bloom_add_prefixes(data, m->bus->bloom_size, m->bus->bloom_n_hash, "path-slash-prefix", m->path, '/');
0bee65f0622c4faa8ac8ae771cc0c8a936dfa284Lennart Poettering for (i = 0; i < 64; i++) {
0bee65f0622c4faa8ac8ae771cc0c8a936dfa284Lennart Poettering const char *t, *contents;
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering r = sd_bus_message_peek_type(m, &type, &contents);
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering if (IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH, SD_BUS_TYPE_SIGNATURE)) {
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering /* The bloom filter includes simple strings of any kind */
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering add_bloom_arg(data, m->bus->bloom_size, m->bus->bloom_n_hash, i, t);
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering } if (type == SD_BUS_TYPE_ARRAY && STR_IN_SET(contents, "s", "o", "g")) {
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering /* As well as array of simple strings of any kinds */
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering r = sd_bus_message_enter_container(m, type, contents);
0bee65f0622c4faa8ac8ae771cc0c8a936dfa284Lennart Poettering while ((r = sd_bus_message_read_basic(m, contents[0], &t)) > 0)
bd3fa1d2434aa28564251ac4da34d01537de8c4bLennart Poettering add_bloom_arg(data, m->bus->bloom_size, m->bus->bloom_n_hash, i, t);
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;
assert(k);
size_t l;
switch (d->type) {
case KDBUS_ITEM_PAYLOAD_OFF:
return -EBADMSG;
case KDBUS_ITEM_PAYLOAD_MEMFD:
return -EBADMSG;
case KDBUS_ITEM_FDS: {
return -ENOMEM;
fds = f;
n_fds += j;
case KDBUS_ITEM_SECLABEL:
return -EBADMSG;
return -EBADMSG;
return -EPROTOTYPE;
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:
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);
.flags = 0,
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 -errno;
if (!b->kdbus_buffer) {
r = -errno;
goto fail;
r = -ENOTSUP;
goto fail;
r = -ENOTSUP;
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);
.flags = 0,
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 -ENOTSUP;
*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 -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;
int bus_kernel_fix_attach_mask(void) {
if (mask) {
const char *p = mask;
return log_full_errno(
char *n = NULL;
return -errno;
return -EIO;
*name = n;