bus-kernel.c revision 1a29929959fd8f59e19ce60c25d1a1f7d910fac0
796b06c21b62d13c9021e2fbd9c58a5c6edb2764Kay Sievers/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
796b06c21b62d13c9021e2fbd9c58a5c6edb2764Kay Sievers This file is part of systemd.
cf7ebcea78223b95b2676b97e1d2aad16caa3c86Kay Sievers Copyright 2013 Lennart Poettering
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sievers systemd is free software; you can redistribute it and/or modify it
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sievers under the terms of the GNU Lesser General Public License as published by
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sievers the Free Software Foundation; either version 2.1 of the License, or
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sievers (at your option) any later version.
378cf88f72a9cda84baf703ed24f54c8c539fdcfKay Sievers systemd is distributed in the hope that it will be useful, but
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sievers WITHOUT ANY WARRANTY; without even the implied warranty of
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sievers MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sievers Lesser General Public License for more details.
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sievers You should have received a copy of the GNU Lesser General Public License
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sievers along with systemd; If not, see <http://www.gnu.org/licenses/>.
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sievers#define UNIQUE_NAME_MAX (3+DECIMAL_STR_MAX(uint64_t))
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sieversint bus_kernel_parse_unique_name(const char *s, uint64_t *id) {
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sieversstatic void append_payload_vec(struct kdbus_item **d, const void *p, size_t sz) {
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sievers /* Note that p can be NULL, which encodes a region full of
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sievers * zeroes, which is useful to optimize certain padding
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sievers * conditions */
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sievers (*d)->size = offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec);
09d8f5d757515122d7b726218e249621e564157cKay Sievers *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sieversstatic void append_payload_memfd(struct kdbus_item **d, int memfd, size_t sz) {
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sievers (*d)->size = offsetof(struct kdbus_item, memfd) + sizeof(struct kdbus_memfd);
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sievers *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sieversstatic void append_destination(struct kdbus_item **d, const char *s, size_t length) {
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sievers (*d)->size = offsetof(struct kdbus_item, str) + length + 1;
cf7ebcea78223b95b2676b97e1d2aad16caa3c86Kay Sievers *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sieversstatic struct kdbus_bloom_filter *append_bloom(struct kdbus_item **d, size_t length) {
378cf88f72a9cda84baf703ed24f54c8c539fdcfKay Sievers i->size = offsetof(struct kdbus_item, bloom_filter) +
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sievers *d = (struct kdbus_item *) ((uint8_t*) i + i->size);
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sieversstatic void append_fds(struct kdbus_item **d, const int fds[], unsigned n_fds) {
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sievers (*d)->size = offsetof(struct kdbus_item, fds) + sizeof(int) * n_fds;
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sievers *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sieversstatic int bus_message_setup_bloom(sd_bus_message *m, struct kdbus_bloom_filter *bloom) {
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sievers bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "message-type", bus_message_type_to_string(m->header->type));
796b06c21b62d13c9021e2fbd9c58a5c6edb2764Kay Sievers bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "interface", m->interface);
cf7ebcea78223b95b2676b97e1d2aad16caa3c86Kay Sievers bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "member", m->member);
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sievers bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "path", m->path);
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sievers bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "path-slash-prefix", m->path);
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sievers bloom_add_prefixes(data, m->bus->bloom_size, m->bus->bloom_n_hash, "path-slash-prefix", m->path, '/');
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sievers for (i = 0; i < 64; i++) {
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sievers const char *t;
c35ddc5b69ef1911de39933329eda0b569cae4b9Kay Sievers char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sievers *(e++) = '0' + (char) i;
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sievers bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, buf, t);
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sievers bloom_add_prefixes(data, m->bus->bloom_size, m->bus->bloom_n_hash, buf, t, '.');
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sievers bloom_add_prefixes(data, m->bus->bloom_size, m->bus->bloom_n_hash, buf, t, '/');
f9cd22249dbdcebe2ab54eea56c0b32e2a1c2ce5Mantas Mikulėnasstatic int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) {
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sievers /* We put this together only once, if this message is reused
5fe25affc01fb003a3a66937458a25640a6075ceTom Gundersen * we reuse the earlier-built version */
5fe25affc01fb003a3a66937458a25640a6075ceTom Gundersen destination = m->destination ?: m->destination_ptr;
5fe25affc01fb003a3a66937458a25640a6075ceTom Gundersen r = bus_kernel_parse_unique_name(destination, &unique);
5fe25affc01fb003a3a66937458a25640a6075ceTom Gundersen assert_cc(ALIGN8(offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec)) ==
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sievers ALIGN8(offsetof(struct kdbus_item, memfd) + sizeof(struct kdbus_memfd)));
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sievers /* Add in fixed header, fields header and payload */
5fe25affc01fb003a3a66937458a25640a6075ceTom Gundersen ALIGN8(offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec));
5fe25affc01fb003a3a66937458a25640a6075ceTom Gundersen /* Add space for bloom filter */
f2f1861383c5cf4c07a7c6098d7c0b7134f06d51Kay Sievers sz += ALIGN8(offsetof(struct kdbus_item, bloom_filter) +
5fe25affc01fb003a3a66937458a25640a6075ceTom Gundersen /* Add in well-known destination header */
5fe25affc01fb003a3a66937458a25640a6075ceTom Gundersen sz += ALIGN8(offsetof(struct kdbus_item, str) + dl + 1);
5fe25affc01fb003a3a66937458a25640a6075ceTom Gundersen /* Add space for unix fds */
5fe25affc01fb003a3a66937458a25640a6075ceTom Gundersen sz += ALIGN8(offsetof(struct kdbus_item, fds) + sizeof(int)*m->n_fds);
8db6dcfd3c3d19d35767f04884a99368f6c64b36Kay Sievers ((m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) ? 0 : KDBUS_MSG_FLAGS_EXPECT_REPLY) |
cf7ebcea78223b95b2676b97e1d2aad16caa3c86Kay Sievers ((m->header->flags & BUS_MESSAGE_NO_AUTO_START) ? KDBUS_MSG_FLAGS_NO_AUTO_START : 0);
if (well_known)
if (well_known)
goto fail;
goto fail;
if (m->n_fds > 0)
fail:
m->poisoned = true;
assert(m);
assert(m);
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:
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;
if (!(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) != !!(k->flags & KDBUS_MSG_FLAGS_EXPECT_REPLY)) {
r = -EBADMSG;
goto fail;
r = -EBADMSG;
goto fail;
if (!(m->header->flags & BUS_MESSAGE_NO_AUTO_START) != !(k->flags & KDBUS_MSG_FLAGS_NO_AUTO_START)) {
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 -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_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;
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) {
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);
return -errno;
return -ENOMEM;
return fd;
switch (access) {
case BUS_POLICY_ACCESS_SEE:
return KDBUS_POLICY_SEE;
case BUS_POLICY_ACCESS_TALK:
return KDBUS_POLICY_TALK;
case BUS_POLICY_ACCESS_OWN:
return KDBUS_POLICY_OWN;
case BUSNAME_POLICY_TYPE_USER: {
case BUSNAME_POLICY_TYPE_GROUP: {
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;
struct kdbus_item *n;
Iterator i;
n = KDBUS_ITEM_NEXT(n);
n = KDBUS_ITEM_NEXT(n);
return -errno;
int fd,
const char *name,
bool activating,
bool accept_fd,
struct kdbus_item *n;
policy_cnt++;
if (world_policy >= 0)
policy_cnt++;
policy_cnt * ALIGN8(offsetof(struct kdbus_item, policy_access) + sizeof(struct kdbus_policy_access));
n = KDBUS_ITEM_NEXT(n);
n = KDBUS_ITEM_NEXT(n);
if (world_policy >= 0) {
return -errno;
return -ENOTSUP;
return -ENOTSUP;
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;