bus-kernel.c revision 18a281479dd6ea65d9b7471c5a74b78f23bef307
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack This file is part of systemd.
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack Copyright 2013 Lennart Poettering
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack systemd is free software; you can redistribute it and/or modify it
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack under the terms of the GNU Lesser General Public License as published by
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack the Free Software Foundation; either version 2.1 of the License, or
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack (at your option) any later version.
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack systemd is distributed in the hope that it will be useful, but
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack WITHOUT ANY WARRANTY; without even the implied warranty of
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack Lesser General Public License for more details.
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack You should have received a copy of the GNU Lesser General Public License
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack along with systemd; If not, see <http://www.gnu.org/licenses/>.
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack#define UNIQUE_NAME_MAX (3+DECIMAL_STR_MAX(uint64_t))
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mackint bus_kernel_parse_unique_name(const char *s, uint64_t *id) {
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mackstatic void append_payload_vec(struct kdbus_item **d, const void *p, size_t sz) {
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack /* Note that p can be NULL, which encodes a region full of
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack * zeroes, which is useful to optimize certain padding
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack * conditions */
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack (*d)->size = offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec);
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mackstatic void append_payload_memfd(struct kdbus_item **d, int memfd, size_t sz) {
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack (*d)->size = offsetof(struct kdbus_item, memfd) + sizeof(struct kdbus_memfd);
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mackstatic void append_destination(struct kdbus_item **d, const char *s, size_t length) {
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack (*d)->size = offsetof(struct kdbus_item, str) + length + 1;
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mackstatic struct kdbus_bloom_filter *append_bloom(struct kdbus_item **d, size_t length) {
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack i->size = offsetof(struct kdbus_item, bloom_filter) +
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack *d = (struct kdbus_item *) ((uint8_t*) i + i->size);
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mackstatic void append_fds(struct kdbus_item **d, const int fds[], unsigned n_fds) {
c2a23db0b91faca3795099fd4b41587bac170ff7Daniel Mack (*d)->size = offsetof(struct kdbus_item, fds) + sizeof(int) * n_fds;
c2a23db0b91faca3795099fd4b41587bac170ff7Daniel Mack *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mackstatic int bus_message_setup_bloom(sd_bus_message *m, struct kdbus_bloom_filter *bloom) {
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack bloom_add_pair(data, "message-type", bus_message_type_to_string(m->header->type));
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack bloom_add_pair(data, "interface", m->interface);
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack bloom_add_pair(data, "path-slash-prefix", m->path);
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack bloom_add_prefixes(data, "path-slash-prefix", m->path, '/');
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack for (i = 0; i < 64; i++) {
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack const char *t;
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
e2fa5721c3ee5ea400b99a6463e8c1c257e20415Daniel Mack *(e++) = '0' + (char) i;
struct kdbus_item *d;
bool well_known;
assert(b);
assert(m);
if (m->kdbus)
if (m->destination) {
well_known = r == 0;
well_known = false;
if (well_known) {
if (m->n_fds > 0)
if (!m->kdbus) {
r = -ENOMEM;
goto fail;
m->free_kdbus = true;
well_known ? 0 :
if (well_known)
goto fail;
goto fail;
if (m->n_fds > 0)
fail:
m->poisoned = true;
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_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:
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:
return -EBADMSG;
case KDBUS_ITEM_NAME:
return -EBADMSG;
goto fail;
case KDBUS_ITEM_CONN_NAME:
case KDBUS_ITEM_FDS:
case KDBUS_ITEM_SECLABEL:
r = bus_message_parse_fields(m);
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:
const char *name;
assert(b);
if (b->is_server)
return -EINVAL;
if (b->connection_name) {
return -ENOMEM;
name = g;
return -ENOMEM;
return -ENOMEM;
name = g;
if (!b->connection_name)
return -ENOMEM;
if (b->fake_creds_valid)
if (b->fake_label) {
if (b->fake_creds_valid) {
if (b->fake_label) {
return -errno;
if (!b->kdbus_buffer) {
return -errno;
return -ENOTSUP;
return -ENOTSUP;
return -ENOMEM;
b->is_kernel = true;
b->bus_client = true;
return bus_start_running(b);
assert(b);
if (b->is_server)
return -EINVAL;
if (b->input_fd < 0)
return -errno;
return bus_kernel_take_fd(b);
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(sd_bus *bus, const char *name, const char *old_owner, const char *new_owner) {
bus,
"/org/freedesktop/DBus",
m = NULL;
assert(k);
assert(d);
if (d->type == KDBUS_ITEM_NAME_ADD || (d->name_change.old.flags & (KDBUS_NAME_IN_QUEUE|KDBUS_NAME_ACTIVATOR)))
old_owner[0] = 0;
if (d->type == KDBUS_ITEM_NAME_REMOVE || (d->name_change.new.flags & (KDBUS_NAME_IN_QUEUE|KDBUS_NAME_ACTIVATOR))) {
new_owner[0] = 0;
assert(k);
assert(d);
return push_name_owner_changed(
assert(k);
assert(d);
bus,
k->cookie_reply,
m = NULL;
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) {
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;
return -ENOMEM;
l = strlen(g);
return -errno;
*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;
*kdbus_flags = f;
uint64_t m = 0;
if (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_GID|SD_BUS_CREDS_PID|SD_BUS_CREDS_PID_STARTTIME|SD_BUS_CREDS_TID))
m |= KDBUS_ATTACH_CREDS;
m |= KDBUS_ATTACH_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_CONN_NAME;
*kdbus_mask = m;
struct kdbus_item *n;
int fd;
assert(s);
if (fd < 0)
return -errno;
sizeof(struct kdbus_bloom_parameter);
n = KDBUS_ITEM_NEXT(n);
return -errno;
return -ENOTSUP;
return -ENOMEM;
return fd;
struct kdbus_item *n;
int fd;
if (fd < 0)
return -errno;
return -errno;
return -ENOTSUP;
return -ENOTSUP;
return fd;
struct kdbus_item *n;
int fd;
assert(s);
if (fd < 0)
return -errno;
return -errno;
return -ENOTSUP;
return -ENOMEM;
return fd;
int fd;
if (fd < 0)
return -errno;
return -errno;
return -ENOTSUP;
return fd;
return -errno;