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>
30 #include "bus-internal.h"
31 #include "bus-message.h"
32 #include "bus-kernel.h"
33 #include "bus-bloom.h"
35 #define KDBUS_FOREACH_ITEM(i, k) \
36 for ((i) = (k)->items; \
37 (uint8_t*) (i) < (uint8_t*) (k) + (k)->size; \
38 (i) = (struct kdbus_msg_item *) ((uint8_t*) (i) + ALIGN8((i)->size)))
40 static int parse_unique_name(const char *s, uint64_t *id) {
46 if (!startswith(s, ":1."))
49 r = safe_atou64(s + 3, id);
56 static void append_payload_vec(struct kdbus_msg_item **d, const void *p, size_t sz) {
63 (*d)->size = offsetof(struct kdbus_msg_item, vec) + sizeof(struct kdbus_vec);
64 (*d)->type = KDBUS_MSG_PAYLOAD_VEC;
65 (*d)->vec.address = (uint64_t) p;
68 *d = (struct kdbus_msg_item *) ((uint8_t*) *d + (*d)->size);
71 static void append_destination(struct kdbus_msg_item **d, const char *s, size_t length) {
77 (*d)->size = offsetof(struct kdbus_msg_item, str) + length + 1;
78 (*d)->type = KDBUS_MSG_DST_NAME;
79 memcpy((*d)->str, s, length + 1);
81 *d = (struct kdbus_msg_item *) ((uint8_t*) *d + (*d)->size);
84 static void* append_bloom(struct kdbus_msg_item **d, size_t length) {
91 (*d)->size = offsetof(struct kdbus_msg_item, data) + length;
92 (*d)->type = KDBUS_MSG_BLOOM;
95 *d = (struct kdbus_msg_item *) ((uint8_t*) *d + (*d)->size);
100 static int bus_message_setup_bloom(sd_bus_message *m, void *bloom) {
107 memset(bloom, 0, BLOOM_SIZE);
109 bloom_add_pair(bloom, "message-type", bus_message_type_to_string(m->header->type));
112 bloom_add_pair(bloom, "interface", m->interface);
114 bloom_add_pair(bloom, "member", m->member);
116 bloom_add_pair(bloom, "path", m->path);
117 bloom_add_prefixes(bloom, "path-slash-prefix", m->path, '/');
120 r = sd_bus_message_rewind(m, true);
124 for (i = 0; i < 64; i++) {
127 char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
130 r = sd_bus_message_peek_type(m, &type, NULL);
134 if (type != SD_BUS_TYPE_STRING &&
135 type != SD_BUS_TYPE_OBJECT_PATH &&
136 type != SD_BUS_TYPE_SIGNATURE)
139 r = sd_bus_message_read_basic(m, type, &t);
143 e = stpcpy(buf, "arg");
147 *(e++) = '0' + (i / 10);
148 *(e++) = '0' + (i % 10);
152 bloom_add_pair(bloom, buf, t);
154 strcpy(e, "-dot-prefix");
155 bloom_add_prefixes(bloom, buf, t, '.');
156 strcpy(e, "-slash-prefix");
157 bloom_add_prefixes(bloom, buf, t, '/');
163 static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) {
164 struct kdbus_msg_item *d;
177 if (m->destination) {
178 r = parse_unique_name(m->destination, &unique);
186 sz = offsetof(struct kdbus_msg, items);
188 /* Add in fixed header, fields header and payload */
189 sz += 3 * ALIGN8(offsetof(struct kdbus_msg_item, vec) + sizeof(struct kdbus_vec));
191 /* Add space for bloom filter */
192 sz += ALIGN8(offsetof(struct kdbus_msg_item, data) + BLOOM_SIZE);
194 /* Add in well-known destination header */
196 dl = strlen(m->destination);
197 sz += ALIGN8(offsetof(struct kdbus_msg_item, str) + dl + 1);
200 m->kdbus = aligned_alloc(8, sz);
204 memset(m->kdbus, 0, sz);
207 ((m->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED) ? 0 : KDBUS_MSG_FLAGS_EXPECT_REPLY) |
208 ((m->header->flags & SD_BUS_MESSAGE_NO_AUTO_START) ? KDBUS_MSG_FLAGS_NO_AUTO_START : 0);
211 m->destination ? unique : KDBUS_DST_ID_BROADCAST;
212 m->kdbus->payload_type = KDBUS_PAYLOAD_DBUS1;
213 m->kdbus->cookie = m->header->serial;
215 m->kdbus->timeout_ns = m->timeout * NSEC_PER_USEC;
220 append_destination(&d, m->destination, dl);
222 append_payload_vec(&d, m->header, sizeof(*m->header));
225 append_payload_vec(&d, m->fields, ALIGN8(m->header->fields_size));
228 append_payload_vec(&d, m->body, m->header->body_size);
230 if (m->kdbus->dst_id == KDBUS_DST_ID_BROADCAST) {
233 /* For now, let's add a mask all bloom filter */
234 p = append_bloom(&d, BLOOM_SIZE);
235 r = bus_message_setup_bloom(m, p);
243 m->kdbus->size = (uint8_t*) d - (uint8_t*) m->kdbus;
244 assert(m->kdbus->size <= sz);
246 m->free_kdbus = true;
251 int bus_kernel_take_fd(sd_bus *b) {
252 struct kdbus_cmd_hello hello = {
254 KDBUS_CMD_HELLO_ACCEPT_FD|
255 KDBUS_CMD_HELLO_ACCEPT_MMAP|
256 KDBUS_CMD_HELLO_ATTACH_COMM|
257 KDBUS_CMD_HELLO_ATTACH_EXE|
258 KDBUS_CMD_HELLO_ATTACH_CMDLINE|
259 KDBUS_CMD_HELLO_ATTACH_CGROUP|
260 KDBUS_CMD_HELLO_ATTACH_CAPS|
261 KDBUS_CMD_HELLO_ATTACH_SECLABEL|
262 KDBUS_CMD_HELLO_ATTACH_AUDIT
271 r = ioctl(b->input_fd, KDBUS_CMD_HELLO, &hello);
275 /* The higher 32bit of both flags fields are considered
276 * 'incompatible flags'. Refuse them all for now. */
277 if (hello.bus_flags > 0xFFFFFFFFULL ||
278 hello.conn_flags > 0xFFFFFFFFULL)
281 if (hello.bloom_size != BLOOM_SIZE)
284 if (asprintf(&b->unique_name, ":1.%llu", (unsigned long long) hello.id) < 0)
288 b->bus_client = true;
290 r = bus_start_running(b);
297 int bus_kernel_connect(sd_bus *b) {
299 assert(b->input_fd < 0);
300 assert(b->output_fd < 0);
306 b->input_fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC);
310 b->output_fd = b->input_fd;
312 return bus_kernel_take_fd(b);
315 int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m) {
320 assert(bus->state == BUS_RUNNING);
322 r = bus_message_setup_kmsg(bus, m);
326 r = ioctl(bus->output_fd, KDBUS_CMD_MSG_SEND, m->kdbus);
328 return errno == EAGAIN ? 0 : -errno;
333 static void close_kdbus_msg(struct kdbus_msg *k) {
334 struct kdbus_msg_item *d;
336 KDBUS_FOREACH_ITEM(d, k) {
338 if (d->type != KDBUS_MSG_UNIX_FDS)
341 close_many(d->fds, (d->size - offsetof(struct kdbus_msg_item, fds)) / sizeof(int));
345 static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k, sd_bus_message **ret) {
346 sd_bus_message *m = NULL;
347 struct kdbus_msg_item *d;
348 unsigned n_payload = 0, n_fds = 0;
349 _cleanup_free_ int *fds = NULL;
350 struct bus_header *h = NULL;
351 size_t total, n_bytes = 0, idx = 0;
352 const char *destination = NULL, *seclabel = NULL;
359 if (k->payload_type != KDBUS_PAYLOAD_DBUS1)
362 KDBUS_FOREACH_ITEM(d, k) {
365 l = d->size - offsetof(struct kdbus_msg_item, data);
367 if (d->type == KDBUS_MSG_PAYLOAD) {
370 if (l < sizeof(struct bus_header))
373 h = (struct bus_header*) d->data;
379 } else if (d->type == KDBUS_MSG_UNIX_FDS) {
384 f = realloc(fds, sizeof(int) * (n_fds + j));
389 memcpy(fds + n_fds, d->fds, j);
392 } else if (d->type == KDBUS_MSG_DST_NAME)
393 destination = d->str;
394 else if (d->type == KDBUS_MSG_SRC_SECLABEL)
401 r = bus_header_size(h, &total);
405 if (n_bytes != total)
408 r = bus_message_from_header(h, sizeof(struct bus_header), fds, n_fds, NULL, seclabel, 0, &m);
412 KDBUS_FOREACH_ITEM(d, k) {
415 l = d->size - offsetof(struct kdbus_msg_item, data);
417 if (d->type == KDBUS_MSG_PAYLOAD) {
419 if (idx == sizeof(struct bus_header) &&
420 l == ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m)))
422 else if (idx == sizeof(struct bus_header) + ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m)) &&
423 l == BUS_MESSAGE_BODY_SIZE(m))
425 else if (!(idx == 0 && l == sizeof(struct bus_header))) {
426 sd_bus_message_unref(m);
431 } else if (d->type == KDBUS_MSG_SRC_CREDS) {
432 m->pid_starttime = d->creds.starttime / NSEC_PER_USEC;
433 m->uid = d->creds.uid;
434 m->gid = d->creds.gid;
435 m->pid = d->creds.pid;
436 m->tid = d->creds.tid;
437 m->uid_valid = m->gid_valid = true;
438 } else if (d->type == KDBUS_MSG_TIMESTAMP) {
439 m->realtime = d->timestamp.realtime_ns / NSEC_PER_USEC;
440 m->monotonic = d->timestamp.monotonic_ns / NSEC_PER_USEC;
441 } else if (d->type == KDBUS_MSG_SRC_PID_COMM)
443 else if (d->type == KDBUS_MSG_SRC_TID_COMM)
444 m->tid_comm = d->str;
445 else if (d->type == KDBUS_MSG_SRC_EXE)
447 else if (d->type == KDBUS_MSG_SRC_CMDLINE) {
449 m->cmdline_length = l;
450 } else if (d->type == KDBUS_MSG_SRC_CGROUP)
453 log_debug("Got unknown field from kernel %llu", d->type);
456 r = bus_message_parse_fields(m);
458 sd_bus_message_unref(m);
462 if (k->src_id == KDBUS_SRC_ID_KERNEL)
463 m->sender = "org.freedesktop.DBus";
465 snprintf(m->sender_buffer, sizeof(m->sender_buffer), ":1.%llu", (unsigned long long) k->src_id);
466 m->sender = m->sender_buffer;
469 if (!m->destination) {
471 m->destination = destination;
472 else if (k->dst_id != KDBUS_DST_ID_WELL_KNOWN_NAME &&
473 k->dst_id != KDBUS_DST_ID_BROADCAST) {
474 snprintf(m->destination_buffer, sizeof(m->destination_buffer), ":1.%llu", (unsigned long long) k->dst_id);
475 m->destination = m->destination_buffer;
479 /* We take possession of the kmsg struct now */
481 m->free_kdbus = true;
490 int bus_kernel_read_message(sd_bus *bus, sd_bus_message **m) {
501 q = aligned_alloc(8, sz);
506 k = bus->rbuffer = q;
509 /* Let's tell valgrind that there's really no need to
510 * initialize this fully. This should be removed again
511 * when valgrind learned the kdbus ioctls natively. */
512 #ifdef HAVE_VALGRIND_MEMCHECK_H
513 VALGRIND_MAKE_MEM_DEFINED(k, sz);
516 r = ioctl(bus->input_fd, KDBUS_CMD_MSG_RECV, bus->rbuffer);
523 if (errno != ENOBUFS)
529 r = bus_kernel_make_message(bus, k, m);
535 return r < 0 ? r : 1;
538 int bus_kernel_create(const char *name, char **s) {
539 struct kdbus_cmd_bus_make *make;
547 fd = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
552 make = alloca0(offsetof(struct kdbus_cmd_bus_make, name) + DECIMAL_STR_MAX(uid_t) + 1 + l + 1);
553 sprintf(make->name, "%lu-%s", (unsigned long) getuid(), name);
554 make->size = offsetof(struct kdbus_cmd_bus_make, name) + strlen(make->name) + 1;
555 make->flags = KDBUS_ACCESS_WORLD | KDBUS_POLICY_OPEN;
557 make->bloom_size = BLOOM_SIZE;
559 assert_cc(BLOOM_SIZE % 8 == 0);
561 p = strjoin("/dev/kdbus/", make->name, "/bus", NULL);
565 if (ioctl(fd, KDBUS_CMD_BUS_MAKE, make) < 0) {
566 close_nointr_nofail(fd);