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_ITEM_NEXT(item) \
36 (typeof(item))(((uint8_t *)item) + ALIGN8((item)->size))
37 #define KDBUS_ITEM_FOREACH(item, head) \
38 for (item = (head)->items; \
39 (uint8_t *)(item) < (uint8_t *)(head) + (head)->size; \
40 item = KDBUS_ITEM_NEXT(item))
42 static int parse_unique_name(const char *s, uint64_t *id) {
48 if (!startswith(s, ":1."))
51 r = safe_atou64(s + 3, id);
58 static void append_payload_vec(struct kdbus_msg_item **d, const void *p, size_t sz) {
65 (*d)->size = offsetof(struct kdbus_msg_item, vec) + sizeof(struct kdbus_vec);
66 (*d)->type = KDBUS_MSG_PAYLOAD_VEC;
67 (*d)->vec.address = (uint64_t) p;
70 *d = (struct kdbus_msg_item *) ((uint8_t*) *d + (*d)->size);
73 static void append_destination(struct kdbus_msg_item **d, const char *s, size_t length) {
79 (*d)->size = offsetof(struct kdbus_msg_item, str) + length + 1;
80 (*d)->type = KDBUS_MSG_DST_NAME;
81 memcpy((*d)->str, s, length + 1);
83 *d = (struct kdbus_msg_item *) ((uint8_t*) *d + (*d)->size);
86 static void* append_bloom(struct kdbus_msg_item **d, size_t length) {
93 (*d)->size = offsetof(struct kdbus_msg_item, data) + length;
94 (*d)->type = KDBUS_MSG_BLOOM;
97 *d = (struct kdbus_msg_item *) ((uint8_t*) *d + (*d)->size);
102 static int bus_message_setup_bloom(sd_bus_message *m, void *bloom) {
109 memset(bloom, 0, BLOOM_SIZE);
111 bloom_add_pair(bloom, "message-type", bus_message_type_to_string(m->header->type));
114 bloom_add_pair(bloom, "interface", m->interface);
116 bloom_add_pair(bloom, "member", m->member);
118 bloom_add_pair(bloom, "path", m->path);
119 bloom_add_prefixes(bloom, "path-slash-prefix", m->path, '/');
122 r = sd_bus_message_rewind(m, true);
126 for (i = 0; i < 64; i++) {
129 char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
132 r = sd_bus_message_peek_type(m, &type, NULL);
136 if (type != SD_BUS_TYPE_STRING &&
137 type != SD_BUS_TYPE_OBJECT_PATH &&
138 type != SD_BUS_TYPE_SIGNATURE)
141 r = sd_bus_message_read_basic(m, type, &t);
145 e = stpcpy(buf, "arg");
149 *(e++) = '0' + (i / 10);
150 *(e++) = '0' + (i % 10);
154 bloom_add_pair(bloom, buf, t);
156 strcpy(e, "-dot-prefix");
157 bloom_add_prefixes(bloom, buf, t, '.');
158 strcpy(e, "-slash-prefix");
159 bloom_add_prefixes(bloom, buf, t, '/');
165 static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) {
166 struct kdbus_msg_item *d;
179 if (m->destination) {
180 r = parse_unique_name(m->destination, &unique);
188 sz = offsetof(struct kdbus_msg, items);
190 /* Add in fixed header, fields header and payload */
191 sz += 3 * ALIGN8(offsetof(struct kdbus_msg_item, vec) + sizeof(struct kdbus_vec));
193 /* Add space for bloom filter */
194 sz += ALIGN8(offsetof(struct kdbus_msg_item, data) + BLOOM_SIZE);
196 /* Add in well-known destination header */
198 dl = strlen(m->destination);
199 sz += ALIGN8(offsetof(struct kdbus_msg_item, str) + dl + 1);
202 m->kdbus = aligned_alloc(8, sz);
206 memset(m->kdbus, 0, sz);
209 ((m->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED) ? 0 : KDBUS_MSG_FLAGS_EXPECT_REPLY) |
210 ((m->header->flags & SD_BUS_MESSAGE_NO_AUTO_START) ? KDBUS_MSG_FLAGS_NO_AUTO_START : 0);
213 m->destination ? unique : KDBUS_DST_ID_BROADCAST;
214 m->kdbus->payload_type = KDBUS_PAYLOAD_DBUS1;
215 m->kdbus->cookie = m->header->serial;
217 m->kdbus->timeout_ns = m->timeout * NSEC_PER_USEC;
222 append_destination(&d, m->destination, dl);
224 append_payload_vec(&d, m->header, sizeof(*m->header));
227 append_payload_vec(&d, m->fields, ALIGN8(m->header->fields_size));
230 append_payload_vec(&d, m->body, m->header->body_size);
232 if (m->kdbus->dst_id == KDBUS_DST_ID_BROADCAST) {
235 /* For now, let's add a mask all bloom filter */
236 p = append_bloom(&d, BLOOM_SIZE);
237 r = bus_message_setup_bloom(m, p);
245 m->kdbus->size = (uint8_t*) d - (uint8_t*) m->kdbus;
246 assert(m->kdbus->size <= sz);
248 m->free_kdbus = true;
253 int bus_kernel_take_fd(sd_bus *b) {
254 struct kdbus_cmd_hello hello = {
256 KDBUS_CMD_HELLO_ACCEPT_FD|
257 KDBUS_CMD_HELLO_ACCEPT_MMAP|
258 KDBUS_CMD_HELLO_ATTACH_COMM|
259 KDBUS_CMD_HELLO_ATTACH_EXE|
260 KDBUS_CMD_HELLO_ATTACH_CMDLINE|
261 KDBUS_CMD_HELLO_ATTACH_CGROUP|
262 KDBUS_CMD_HELLO_ATTACH_CAPS|
263 KDBUS_CMD_HELLO_ATTACH_SECLABEL|
264 KDBUS_CMD_HELLO_ATTACH_AUDIT
273 r = ioctl(b->input_fd, KDBUS_CMD_HELLO, &hello);
277 /* The higher 32bit of both flags fields are considered
278 * 'incompatible flags'. Refuse them all for now. */
279 if (hello.bus_flags > 0xFFFFFFFFULL ||
280 hello.conn_flags > 0xFFFFFFFFULL)
283 if (hello.bloom_size != BLOOM_SIZE)
286 if (asprintf(&b->unique_name, ":1.%llu", (unsigned long long) hello.id) < 0)
290 b->bus_client = true;
292 r = bus_start_running(b);
299 int bus_kernel_connect(sd_bus *b) {
301 assert(b->input_fd < 0);
302 assert(b->output_fd < 0);
308 b->input_fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC);
312 b->output_fd = b->input_fd;
314 return bus_kernel_take_fd(b);
317 int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m) {
322 assert(bus->state == BUS_RUNNING);
324 r = bus_message_setup_kmsg(bus, m);
328 r = ioctl(bus->output_fd, KDBUS_CMD_MSG_SEND, m->kdbus);
330 return errno == EAGAIN ? 0 : -errno;
335 static void close_kdbus_msg(struct kdbus_msg *k) {
336 struct kdbus_msg_item *d;
338 KDBUS_ITEM_FOREACH(d, k) {
340 if (d->type != KDBUS_MSG_UNIX_FDS)
343 close_many(d->fds, (d->size - offsetof(struct kdbus_msg_item, fds)) / sizeof(int));
347 static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k, sd_bus_message **ret) {
348 sd_bus_message *m = NULL;
349 struct kdbus_msg_item *d;
350 unsigned n_payload = 0, n_fds = 0;
351 _cleanup_free_ int *fds = NULL;
352 struct bus_header *h = NULL;
353 size_t total, n_bytes = 0, idx = 0;
354 const char *destination = NULL, *seclabel = NULL;
361 if (k->payload_type != KDBUS_PAYLOAD_DBUS1)
364 KDBUS_ITEM_FOREACH(d, k) {
367 l = d->size - offsetof(struct kdbus_msg_item, data);
369 if (d->type == KDBUS_MSG_PAYLOAD) {
372 if (l < sizeof(struct bus_header))
375 h = (struct bus_header*) d->data;
381 } else if (d->type == KDBUS_MSG_UNIX_FDS) {
386 f = realloc(fds, sizeof(int) * (n_fds + j));
391 memcpy(fds + n_fds, d->fds, j);
394 } else if (d->type == KDBUS_MSG_DST_NAME)
395 destination = d->str;
396 else if (d->type == KDBUS_MSG_SRC_SECLABEL)
403 r = bus_header_size(h, &total);
407 if (n_bytes != total)
410 r = bus_message_from_header(h, sizeof(struct bus_header), fds, n_fds, NULL, seclabel, 0, &m);
414 KDBUS_ITEM_FOREACH(d, k) {
417 l = d->size - offsetof(struct kdbus_msg_item, data);
419 if (d->type == KDBUS_MSG_PAYLOAD) {
421 if (idx == sizeof(struct bus_header) &&
422 l == ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m)))
424 else if (idx == sizeof(struct bus_header) + ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m)) &&
425 l == BUS_MESSAGE_BODY_SIZE(m))
427 else if (!(idx == 0 && l == sizeof(struct bus_header))) {
428 sd_bus_message_unref(m);
433 } else if (d->type == KDBUS_MSG_SRC_CREDS) {
434 m->pid_starttime = d->creds.starttime / NSEC_PER_USEC;
435 m->uid = d->creds.uid;
436 m->gid = d->creds.gid;
437 m->pid = d->creds.pid;
438 m->tid = d->creds.tid;
439 m->uid_valid = m->gid_valid = true;
440 } else if (d->type == KDBUS_MSG_TIMESTAMP) {
441 m->realtime = d->timestamp.realtime_ns / NSEC_PER_USEC;
442 m->monotonic = d->timestamp.monotonic_ns / NSEC_PER_USEC;
443 } else if (d->type == KDBUS_MSG_SRC_PID_COMM)
445 else if (d->type == KDBUS_MSG_SRC_TID_COMM)
446 m->tid_comm = d->str;
447 else if (d->type == KDBUS_MSG_SRC_EXE)
449 else if (d->type == KDBUS_MSG_SRC_CMDLINE) {
451 m->cmdline_length = l;
452 } else if (d->type == KDBUS_MSG_SRC_CGROUP)
455 log_debug("Got unknown field from kernel %llu", d->type);
458 r = bus_message_parse_fields(m);
460 sd_bus_message_unref(m);
464 if (k->src_id == KDBUS_SRC_ID_KERNEL)
465 m->sender = "org.freedesktop.DBus";
467 snprintf(m->sender_buffer, sizeof(m->sender_buffer), ":1.%llu", (unsigned long long) k->src_id);
468 m->sender = m->sender_buffer;
471 if (!m->destination) {
473 m->destination = destination;
474 else if (k->dst_id != KDBUS_DST_ID_WELL_KNOWN_NAME &&
475 k->dst_id != KDBUS_DST_ID_BROADCAST) {
476 snprintf(m->destination_buffer, sizeof(m->destination_buffer), ":1.%llu", (unsigned long long) k->dst_id);
477 m->destination = m->destination_buffer;
481 /* We take possession of the kmsg struct now */
483 m->free_kdbus = true;
492 int bus_kernel_read_message(sd_bus *bus, sd_bus_message **m) {
503 q = aligned_alloc(8, sz);
508 k = bus->rbuffer = q;
511 /* Let's tell valgrind that there's really no need to
512 * initialize this fully. This should be removed again
513 * when valgrind learned the kdbus ioctls natively. */
514 #ifdef HAVE_VALGRIND_MEMCHECK_H
515 VALGRIND_MAKE_MEM_DEFINED(k, sz);
518 r = ioctl(bus->input_fd, KDBUS_CMD_MSG_RECV, bus->rbuffer);
525 if (errno != ENOBUFS)
531 r = bus_kernel_make_message(bus, k, m);
537 return r < 0 ? r : 1;
540 int bus_kernel_create(const char *name, char **s) {
541 struct kdbus_cmd_bus_make *make;
549 fd = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
554 make = alloca0(offsetof(struct kdbus_cmd_bus_make, name) + DECIMAL_STR_MAX(uid_t) + 1 + l + 1);
555 sprintf(make->name, "%lu-%s", (unsigned long) getuid(), name);
556 make->size = offsetof(struct kdbus_cmd_bus_make, name) + strlen(make->name) + 1;
557 make->flags = KDBUS_ACCESS_WORLD | KDBUS_POLICY_OPEN;
559 make->bloom_size = BLOOM_SIZE;
561 assert_cc(BLOOM_SIZE % 8 == 0);
563 p = strjoin("/dev/kdbus/", make->name, "/bus", NULL);
567 if (ioctl(fd, KDBUS_CMD_BUS_MAKE, make) < 0) {
568 close_nointr_nofail(fd);