1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #ifdef HAVE_VALGRIND_MEMCHECK_H
23 #include <valgrind/memcheck.h>
31 #include "bus-internal.h"
32 #include "bus-message.h"
33 #include "bus-kernel.h"
34 #include "bus-bloom.h"
36 #define KDBUS_ITEM_NEXT(item) \
37 (typeof(item))(((uint8_t *)item) + ALIGN8((item)->size))
38 #define KDBUS_ITEM_FOREACH(item, head) \
39 for (item = (head)->items; \
40 (uint8_t *)(item) < (uint8_t *)(head) + (head)->size; \
41 item = KDBUS_ITEM_NEXT(item))
43 static int parse_unique_name(const char *s, uint64_t *id) {
49 if (!startswith(s, ":1."))
52 r = safe_atou64(s + 3, id);
59 static void append_payload_vec(struct kdbus_msg_item **d, const void *p, size_t sz) {
66 (*d)->size = offsetof(struct kdbus_msg_item, vec) + sizeof(struct kdbus_vec);
67 (*d)->type = KDBUS_MSG_PAYLOAD_VEC;
68 (*d)->vec.address = (uint64_t) p;
71 *d = (struct kdbus_msg_item *) ((uint8_t*) *d + (*d)->size);
74 static void append_destination(struct kdbus_msg_item **d, const char *s, size_t length) {
80 (*d)->size = offsetof(struct kdbus_msg_item, str) + length + 1;
81 (*d)->type = KDBUS_MSG_DST_NAME;
82 memcpy((*d)->str, s, length + 1);
84 *d = (struct kdbus_msg_item *) ((uint8_t*) *d + (*d)->size);
87 static void* append_bloom(struct kdbus_msg_item **d, size_t length) {
94 (*d)->size = offsetof(struct kdbus_msg_item, data) + length;
95 (*d)->type = KDBUS_MSG_BLOOM;
98 *d = (struct kdbus_msg_item *) ((uint8_t*) *d + (*d)->size);
103 static int bus_message_setup_bloom(sd_bus_message *m, void *bloom) {
110 memset(bloom, 0, BLOOM_SIZE);
112 bloom_add_pair(bloom, "message-type", bus_message_type_to_string(m->header->type));
115 bloom_add_pair(bloom, "interface", m->interface);
117 bloom_add_pair(bloom, "member", m->member);
119 bloom_add_pair(bloom, "path", m->path);
120 bloom_add_prefixes(bloom, "path-slash-prefix", m->path, '/');
123 r = sd_bus_message_rewind(m, true);
127 for (i = 0; i < 64; i++) {
130 char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
133 r = sd_bus_message_peek_type(m, &type, NULL);
137 if (type != SD_BUS_TYPE_STRING &&
138 type != SD_BUS_TYPE_OBJECT_PATH &&
139 type != SD_BUS_TYPE_SIGNATURE)
142 r = sd_bus_message_read_basic(m, type, &t);
146 e = stpcpy(buf, "arg");
150 *(e++) = '0' + (i / 10);
151 *(e++) = '0' + (i % 10);
155 bloom_add_pair(bloom, buf, t);
157 strcpy(e, "-dot-prefix");
158 bloom_add_prefixes(bloom, buf, t, '.');
159 strcpy(e, "-slash-prefix");
160 bloom_add_prefixes(bloom, buf, t, '/');
166 static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) {
167 struct kdbus_msg_item *d;
180 if (m->destination) {
181 r = parse_unique_name(m->destination, &unique);
189 sz = offsetof(struct kdbus_msg, items);
191 /* Add in fixed header, fields header and payload */
192 sz += 3 * ALIGN8(offsetof(struct kdbus_msg_item, vec) + sizeof(struct kdbus_vec));
194 /* Add space for bloom filter */
195 sz += ALIGN8(offsetof(struct kdbus_msg_item, data) + BLOOM_SIZE);
197 /* Add in well-known destination header */
199 dl = strlen(m->destination);
200 sz += ALIGN8(offsetof(struct kdbus_msg_item, str) + dl + 1);
203 m->kdbus = memalign(8, sz);
207 memset(m->kdbus, 0, sz);
210 ((m->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED) ? 0 : KDBUS_MSG_FLAGS_EXPECT_REPLY) |
211 ((m->header->flags & SD_BUS_MESSAGE_NO_AUTO_START) ? KDBUS_MSG_FLAGS_NO_AUTO_START : 0);
214 m->destination ? unique : KDBUS_DST_ID_BROADCAST;
215 m->kdbus->payload_type = KDBUS_PAYLOAD_DBUS1;
216 m->kdbus->cookie = m->header->serial;
218 m->kdbus->timeout_ns = m->timeout * NSEC_PER_USEC;
223 append_destination(&d, m->destination, dl);
225 append_payload_vec(&d, m->header, sizeof(*m->header));
228 append_payload_vec(&d, m->fields, ALIGN8(m->header->fields_size));
231 append_payload_vec(&d, m->body, m->header->body_size);
233 if (m->kdbus->dst_id == KDBUS_DST_ID_BROADCAST) {
236 /* For now, let's add a mask all bloom filter */
237 p = append_bloom(&d, BLOOM_SIZE);
238 r = bus_message_setup_bloom(m, p);
246 m->kdbus->size = (uint8_t*) d - (uint8_t*) m->kdbus;
247 assert(m->kdbus->size <= sz);
249 m->free_kdbus = true;
254 int bus_kernel_take_fd(sd_bus *b) {
255 struct kdbus_cmd_hello hello = {
257 KDBUS_CMD_HELLO_ACCEPT_FD|
258 KDBUS_CMD_HELLO_ACCEPT_MMAP|
259 KDBUS_CMD_HELLO_ATTACH_COMM|
260 KDBUS_CMD_HELLO_ATTACH_EXE|
261 KDBUS_CMD_HELLO_ATTACH_CMDLINE|
262 KDBUS_CMD_HELLO_ATTACH_CGROUP|
263 KDBUS_CMD_HELLO_ATTACH_CAPS|
264 KDBUS_CMD_HELLO_ATTACH_SECLABEL|
265 KDBUS_CMD_HELLO_ATTACH_AUDIT
274 r = ioctl(b->input_fd, KDBUS_CMD_HELLO, &hello);
278 /* The higher 32bit of both flags fields are considered
279 * 'incompatible flags'. Refuse them all for now. */
280 if (hello.bus_flags > 0xFFFFFFFFULL ||
281 hello.conn_flags > 0xFFFFFFFFULL)
284 if (hello.bloom_size != BLOOM_SIZE)
287 if (asprintf(&b->unique_name, ":1.%llu", (unsigned long long) hello.id) < 0)
291 b->bus_client = true;
293 r = bus_start_running(b);
300 int bus_kernel_connect(sd_bus *b) {
302 assert(b->input_fd < 0);
303 assert(b->output_fd < 0);
309 b->input_fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC);
313 b->output_fd = b->input_fd;
315 return bus_kernel_take_fd(b);
318 int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m) {
323 assert(bus->state == BUS_RUNNING);
325 r = bus_message_setup_kmsg(bus, m);
329 r = ioctl(bus->output_fd, KDBUS_CMD_MSG_SEND, m->kdbus);
331 return errno == EAGAIN ? 0 : -errno;
336 static void close_kdbus_msg(struct kdbus_msg *k) {
337 struct kdbus_msg_item *d;
339 KDBUS_ITEM_FOREACH(d, k) {
341 if (d->type != KDBUS_MSG_UNIX_FDS)
344 close_many(d->fds, (d->size - offsetof(struct kdbus_msg_item, fds)) / sizeof(int));
348 static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k, sd_bus_message **ret) {
349 sd_bus_message *m = NULL;
350 struct kdbus_msg_item *d;
351 unsigned n_payload = 0, n_fds = 0;
352 _cleanup_free_ int *fds = NULL;
353 struct bus_header *h = NULL;
354 size_t total, n_bytes = 0, idx = 0;
355 const char *destination = NULL, *seclabel = NULL;
362 if (k->payload_type != KDBUS_PAYLOAD_DBUS1)
365 KDBUS_ITEM_FOREACH(d, k) {
368 l = d->size - offsetof(struct kdbus_msg_item, data);
370 if (d->type == KDBUS_MSG_PAYLOAD) {
373 if (l < sizeof(struct bus_header))
376 h = (struct bus_header*) d->data;
382 } else if (d->type == KDBUS_MSG_UNIX_FDS) {
387 f = realloc(fds, sizeof(int) * (n_fds + j));
392 memcpy(fds + n_fds, d->fds, j);
395 } else if (d->type == KDBUS_MSG_DST_NAME)
396 destination = d->str;
397 else if (d->type == KDBUS_MSG_SRC_SECLABEL)
404 r = bus_header_size(h, &total);
408 if (n_bytes != total)
411 r = bus_message_from_header(h, sizeof(struct bus_header), fds, n_fds, NULL, seclabel, 0, &m);
415 KDBUS_ITEM_FOREACH(d, k) {
418 l = d->size - offsetof(struct kdbus_msg_item, data);
420 if (d->type == KDBUS_MSG_PAYLOAD) {
422 if (idx == sizeof(struct bus_header) &&
423 l == ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m)))
425 else if (idx == sizeof(struct bus_header) + ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m)) &&
426 l == BUS_MESSAGE_BODY_SIZE(m))
428 else if (!(idx == 0 && l == sizeof(struct bus_header))) {
429 sd_bus_message_unref(m);
434 } else if (d->type == KDBUS_MSG_SRC_CREDS) {
435 m->pid_starttime = d->creds.starttime / NSEC_PER_USEC;
436 m->uid = d->creds.uid;
437 m->gid = d->creds.gid;
438 m->pid = d->creds.pid;
439 m->tid = d->creds.tid;
440 m->uid_valid = m->gid_valid = true;
441 } else if (d->type == KDBUS_MSG_TIMESTAMP) {
442 m->realtime = d->timestamp.realtime_ns / NSEC_PER_USEC;
443 m->monotonic = d->timestamp.monotonic_ns / NSEC_PER_USEC;
444 } else if (d->type == KDBUS_MSG_SRC_PID_COMM)
446 else if (d->type == KDBUS_MSG_SRC_TID_COMM)
447 m->tid_comm = d->str;
448 else if (d->type == KDBUS_MSG_SRC_EXE)
450 else if (d->type == KDBUS_MSG_SRC_CMDLINE) {
452 m->cmdline_length = l;
453 } else if (d->type == KDBUS_MSG_SRC_CGROUP)
456 log_debug("Got unknown field from kernel %llu", d->type);
459 r = bus_message_parse_fields(m);
461 sd_bus_message_unref(m);
465 if (k->src_id == KDBUS_SRC_ID_KERNEL)
466 m->sender = "org.freedesktop.DBus";
468 snprintf(m->sender_buffer, sizeof(m->sender_buffer), ":1.%llu", (unsigned long long) k->src_id);
469 m->sender = m->sender_buffer;
472 if (!m->destination) {
474 m->destination = destination;
475 else if (k->dst_id != KDBUS_DST_ID_WELL_KNOWN_NAME &&
476 k->dst_id != KDBUS_DST_ID_BROADCAST) {
477 snprintf(m->destination_buffer, sizeof(m->destination_buffer), ":1.%llu", (unsigned long long) k->dst_id);
478 m->destination = m->destination_buffer;
482 /* We take possession of the kmsg struct now */
484 m->free_kdbus = true;
493 int bus_kernel_read_message(sd_bus *bus, sd_bus_message **m) {
509 k = bus->rbuffer = q;
512 /* Let's tell valgrind that there's really no need to
513 * initialize this fully. This should be removed again
514 * when valgrind learned the kdbus ioctls natively. */
515 #ifdef HAVE_VALGRIND_MEMCHECK_H
516 VALGRIND_MAKE_MEM_DEFINED(k, sz);
519 r = ioctl(bus->input_fd, KDBUS_CMD_MSG_RECV, bus->rbuffer);
526 if (errno != ENOBUFS)
532 r = bus_kernel_make_message(bus, k, m);
538 return r < 0 ? r : 1;
541 int bus_kernel_create(const char *name, char **s) {
542 struct kdbus_cmd_bus_make *make;
543 struct kdbus_cmd_make_item *n, *cg;
551 fd = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
556 make = alloca0(offsetof(struct kdbus_cmd_bus_make, items) +
557 sizeof(struct kdbus_cmd_make_item) + sizeof(uint64_t) +
558 sizeof(struct kdbus_cmd_make_item) + DECIMAL_STR_MAX(uid_t) + 1 + l + 1);
561 cg->type = KDBUS_CMD_MAKE_CGROUP;
563 cg->size = sizeof(struct kdbus_cmd_make_item) + sizeof(uint64_t);
565 n = KDBUS_ITEM_NEXT(cg);
566 n->type = KDBUS_CMD_MAKE_NAME;
567 sprintf(n->str, "%lu-%s", (unsigned long) getuid(), name);
568 n->size = sizeof(struct kdbus_cmd_make_item) + strlen(n->str) + 1;
570 make->size = offsetof(struct kdbus_cmd_bus_make, items) + cg->size + n->size;
571 make->flags = KDBUS_ACCESS_WORLD | KDBUS_POLICY_OPEN;
573 make->bloom_size = BLOOM_SIZE;
574 assert_cc(BLOOM_SIZE % 8 == 0);
576 p = strjoin("/dev/kdbus/", n->str, "/bus", NULL);
580 if (ioctl(fd, KDBUS_CMD_BUS_MAKE, make) < 0) {
581 close_nointr_nofail(fd);