]> git.ipfire.org Git - thirdparty/systemd.git/blame_incremental - src/libsystemd-bus/bus-kernel.c
libsystemd-bus: sd_bus_request_name: use kdbus_translate_request_name_flags()
[thirdparty/systemd.git] / src / libsystemd-bus / bus-kernel.c
... / ...
CommitLineData
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2013 Lennart Poettering
7
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.
12
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.
17
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/>.
20***/
21
22#ifdef HAVE_VALGRIND_MEMCHECK_H
23#include <valgrind/memcheck.h>
24#endif
25
26#include <fcntl.h>
27#include <malloc.h>
28#include <sys/mman.h>
29
30#include "util.h"
31
32#include "bus-internal.h"
33#include "bus-message.h"
34#include "bus-kernel.h"
35#include "bus-bloom.h"
36#include "bus-util.h"
37
38#define UNIQUE_NAME_MAX (3+DECIMAL_STR_MAX(uint64_t))
39
40int bus_kernel_parse_unique_name(const char *s, uint64_t *id) {
41 int r;
42
43 assert(s);
44 assert(id);
45
46 if (!startswith(s, ":1."))
47 return 0;
48
49 r = safe_atou64(s + 3, id);
50 if (r < 0)
51 return r;
52
53 return 1;
54}
55
56static void append_payload_vec(struct kdbus_item **d, const void *p, size_t sz) {
57 assert(d);
58 assert(sz > 0);
59
60 *d = ALIGN8_PTR(*d);
61
62 /* Note that p can be NULL, which encodes a region full of
63 * zeroes, which is useful to optimize certain padding
64 * conditions */
65
66 (*d)->size = offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec);
67 (*d)->type = KDBUS_ITEM_PAYLOAD_VEC;
68 (*d)->vec.address = PTR_TO_UINT64(p);
69 (*d)->vec.size = sz;
70
71 *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
72}
73
74static void append_payload_memfd(struct kdbus_item **d, int memfd, size_t sz) {
75 assert(d);
76 assert(memfd >= 0);
77 assert(sz > 0);
78
79 *d = ALIGN8_PTR(*d);
80 (*d)->size = offsetof(struct kdbus_item, memfd) + sizeof(struct kdbus_memfd);
81 (*d)->type = KDBUS_ITEM_PAYLOAD_MEMFD;
82 (*d)->memfd.fd = memfd;
83 (*d)->memfd.size = sz;
84
85 *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
86}
87
88static void append_destination(struct kdbus_item **d, const char *s, size_t length) {
89 assert(d);
90 assert(s);
91
92 *d = ALIGN8_PTR(*d);
93
94 (*d)->size = offsetof(struct kdbus_item, str) + length + 1;
95 (*d)->type = KDBUS_ITEM_DST_NAME;
96 memcpy((*d)->str, s, length + 1);
97
98 *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
99}
100
101static void* append_bloom(struct kdbus_item **d, size_t length) {
102 void *r;
103
104 assert(d);
105
106 *d = ALIGN8_PTR(*d);
107
108 (*d)->size = offsetof(struct kdbus_item, data) + length;
109 (*d)->type = KDBUS_ITEM_BLOOM;
110 r = (*d)->data;
111
112 *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
113
114 return r;
115}
116
117static void append_fds(struct kdbus_item **d, const int fds[], unsigned n_fds) {
118 assert(d);
119 assert(fds);
120 assert(n_fds > 0);
121
122 *d = ALIGN8_PTR(*d);
123 (*d)->size = offsetof(struct kdbus_item, fds) + sizeof(int) * n_fds;
124 (*d)->type = KDBUS_ITEM_FDS;
125 memcpy((*d)->fds, fds, sizeof(int) * n_fds);
126
127 *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
128}
129
130static int bus_message_setup_bloom(sd_bus_message *m, void *bloom) {
131 unsigned i;
132 int r;
133
134 assert(m);
135 assert(bloom);
136
137 memset(bloom, 0, BLOOM_SIZE);
138
139 bloom_add_pair(bloom, "message-type", bus_message_type_to_string(m->header->type));
140
141 if (m->interface)
142 bloom_add_pair(bloom, "interface", m->interface);
143 if (m->member)
144 bloom_add_pair(bloom, "member", m->member);
145 if (m->path) {
146 bloom_add_pair(bloom, "path", m->path);
147 bloom_add_pair(bloom, "path-slash-prefix", m->path);
148 bloom_add_prefixes(bloom, "path-slash-prefix", m->path, '/');
149 }
150
151 r = sd_bus_message_rewind(m, true);
152 if (r < 0)
153 return r;
154
155 for (i = 0; i < 64; i++) {
156 char type;
157 const char *t;
158 char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
159 char *e;
160
161 r = sd_bus_message_peek_type(m, &type, NULL);
162 if (r < 0)
163 return r;
164
165 if (type != SD_BUS_TYPE_STRING &&
166 type != SD_BUS_TYPE_OBJECT_PATH &&
167 type != SD_BUS_TYPE_SIGNATURE)
168 break;
169
170 r = sd_bus_message_read_basic(m, type, &t);
171 if (r < 0)
172 return r;
173
174 e = stpcpy(buf, "arg");
175 if (i < 10)
176 *(e++) = '0' + i;
177 else {
178 *(e++) = '0' + (i / 10);
179 *(e++) = '0' + (i % 10);
180 }
181
182 *e = 0;
183 bloom_add_pair(bloom, buf, t);
184
185 strcpy(e, "-dot-prefix");
186 bloom_add_prefixes(bloom, buf, t, '.');
187 strcpy(e, "-slash-prefix");
188 bloom_add_prefixes(bloom, buf, t, '/');
189 }
190
191 return 0;
192}
193
194static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) {
195 struct bus_body_part *part;
196 struct kdbus_item *d;
197 bool well_known;
198 uint64_t unique;
199 size_t sz, dl;
200 unsigned i;
201 int r;
202
203 assert(b);
204 assert(m);
205 assert(m->sealed);
206
207 if (m->kdbus)
208 return 0;
209
210 if (m->destination) {
211 r = bus_kernel_parse_unique_name(m->destination, &unique);
212 if (r < 0)
213 return r;
214
215 well_known = r == 0;
216 } else
217 well_known = false;
218
219 sz = offsetof(struct kdbus_msg, items);
220
221 assert_cc(ALIGN8(offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec)) ==
222 ALIGN8(offsetof(struct kdbus_item, memfd) + sizeof(struct kdbus_memfd)));
223
224 /* Add in fixed header, fields header and payload */
225 sz += (1 + m->n_body_parts) *
226 ALIGN8(offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec));
227
228 /* Add space for bloom filter */
229 sz += ALIGN8(offsetof(struct kdbus_item, data) + BLOOM_SIZE);
230
231 /* Add in well-known destination header */
232 if (well_known) {
233 dl = strlen(m->destination);
234 sz += ALIGN8(offsetof(struct kdbus_item, str) + dl + 1);
235 }
236
237 /* Add space for unix fds */
238 if (m->n_fds > 0)
239 sz += ALIGN8(offsetof(struct kdbus_item, fds) + sizeof(int)*m->n_fds);
240
241 m->kdbus = memalign(8, sz);
242 if (!m->kdbus) {
243 r = -ENOMEM;
244 goto fail;
245 }
246
247 m->free_kdbus = true;
248 memset(m->kdbus, 0, sz);
249
250 m->kdbus->flags =
251 ((m->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED) ? 0 : KDBUS_MSG_FLAGS_EXPECT_REPLY) |
252 ((m->header->flags & SD_BUS_MESSAGE_NO_AUTO_START) ? KDBUS_MSG_FLAGS_NO_AUTO_START : 0);
253 m->kdbus->dst_id =
254 well_known ? 0 :
255 m->destination ? unique : KDBUS_DST_ID_BROADCAST;
256 m->kdbus->payload_type = KDBUS_PAYLOAD_DBUS1;
257 m->kdbus->cookie = m->header->serial;
258
259 m->kdbus->timeout_ns = m->timeout * NSEC_PER_USEC;
260
261 d = m->kdbus->items;
262
263 if (well_known)
264 append_destination(&d, m->destination, dl);
265
266 append_payload_vec(&d, m->header, BUS_MESSAGE_BODY_BEGIN(m));
267
268 MESSAGE_FOREACH_PART(part, i, m) {
269 if (part->is_zero) {
270 /* If this is padding then simply send a
271 * vector with a NULL data pointer which the
272 * kernel will just pass through. This is the
273 * most efficient way to encode zeroes */
274
275 append_payload_vec(&d, NULL, part->size);
276 continue;
277 }
278
279 if (part->memfd >= 0 && part->sealed && m->destination) {
280 /* Try to send a memfd, if the part is
281 * sealed and this is not a broadcast. Since we can only */
282
283 append_payload_memfd(&d, part->memfd, part->size);
284 continue;
285 }
286
287 /* Otherwise let's send a vector to the actual data,
288 * for that we need to map it first. */
289 r = bus_body_part_map(part);
290 if (r < 0)
291 goto fail;
292
293 append_payload_vec(&d, part->data, part->size);
294 }
295
296 if (m->kdbus->dst_id == KDBUS_DST_ID_BROADCAST) {
297 void *p;
298
299 p = append_bloom(&d, BLOOM_SIZE);
300 r = bus_message_setup_bloom(m, p);
301 if (r < 0)
302 goto fail;
303 }
304
305 if (m->n_fds > 0)
306 append_fds(&d, m->fds, m->n_fds);
307
308 m->kdbus->size = (uint8_t*) d - (uint8_t*) m->kdbus;
309 assert(m->kdbus->size <= sz);
310
311 return 0;
312
313fail:
314 m->poisoned = true;
315 return r;
316}
317
318int bus_kernel_take_fd(sd_bus *b) {
319 struct kdbus_cmd_hello hello;
320 int r;
321
322 assert(b);
323
324 if (b->is_server)
325 return -EINVAL;
326
327 b->use_memfd = 1;
328
329 zero(hello);
330 hello.size = sizeof(hello);
331 hello.conn_flags = b->hello_flags;
332 hello.attach_flags = b->attach_flags;
333 hello.pool_size = KDBUS_POOL_SIZE;
334
335 r = ioctl(b->input_fd, KDBUS_CMD_HELLO, &hello);
336 if (r < 0)
337 return -errno;
338
339 if (!b->kdbus_buffer) {
340 b->kdbus_buffer = mmap(NULL, KDBUS_POOL_SIZE, PROT_READ, MAP_SHARED, b->input_fd, 0);
341 if (b->kdbus_buffer == MAP_FAILED) {
342 b->kdbus_buffer = NULL;
343 return -errno;
344 }
345 }
346
347 /* The higher 32bit of both flags fields are considered
348 * 'incompatible flags'. Refuse them all for now. */
349 if (hello.bus_flags > 0xFFFFFFFFULL ||
350 hello.conn_flags > 0xFFFFFFFFULL)
351 return -ENOTSUP;
352
353 if (hello.bloom_size != BLOOM_SIZE)
354 return -ENOTSUP;
355
356 if (asprintf(&b->unique_name, ":1.%llu", (unsigned long long) hello.id) < 0)
357 return -ENOMEM;
358
359 b->is_kernel = true;
360 b->bus_client = true;
361 b->can_fds = !!(hello.conn_flags & KDBUS_HELLO_ACCEPT_FD);
362
363 /* the kernel told us the UUID of the underlying bus */
364 memcpy(b->server_id.bytes, hello.id128, sizeof(b->server_id.bytes));
365
366 r = bus_start_running(b);
367 if (r < 0)
368 return r;
369
370 return 1;
371}
372
373int bus_kernel_connect(sd_bus *b) {
374 assert(b);
375 assert(b->input_fd < 0);
376 assert(b->output_fd < 0);
377 assert(b->kernel);
378
379 if (b->is_server)
380 return -EINVAL;
381
382 b->input_fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC);
383 if (b->input_fd < 0)
384 return -errno;
385
386 b->output_fd = b->input_fd;
387
388 return bus_kernel_take_fd(b);
389}
390
391int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m) {
392 int r;
393
394 assert(bus);
395 assert(m);
396 assert(bus->state == BUS_RUNNING);
397
398 r = bus_message_setup_kmsg(bus, m);
399 if (r < 0)
400 return r;
401
402 r = ioctl(bus->output_fd, KDBUS_CMD_MSG_SEND, m->kdbus);
403 if (r < 0)
404 return errno == EAGAIN ? 0 : -errno;
405
406 return 1;
407}
408
409static void close_kdbus_msg(sd_bus *bus, struct kdbus_msg *k) {
410 uint64_t off;
411 struct kdbus_item *d;
412
413 assert(bus);
414 assert(k);
415
416 off = (uint8_t *)k - (uint8_t *)bus->kdbus_buffer;
417 ioctl(bus->input_fd, KDBUS_CMD_MSG_RELEASE, &off);
418
419 KDBUS_PART_FOREACH(d, k, items) {
420
421 if (d->type == KDBUS_ITEM_FDS)
422 close_many(d->fds, (d->size - offsetof(struct kdbus_item, fds)) / sizeof(int));
423 else if (d->type == KDBUS_ITEM_PAYLOAD_MEMFD)
424 close_nointr_nofail(d->memfd.fd);
425 }
426}
427
428static int return_name_owner_changed(sd_bus *bus, const char *name, const char *old_owner, const char *new_owner, sd_bus_message **ret) {
429 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
430 int r;
431
432 assert(bus);
433 assert(ret);
434
435 r = sd_bus_message_new_signal(
436 bus,
437 "/org/freedesktop/DBus",
438 "org.freedesktop.DBus",
439 "NameOwnerChanged",
440 &m);
441 if (r < 0)
442 return r;
443
444 r = sd_bus_message_append(m, "sss", name, old_owner, new_owner);
445 if (r < 0)
446 return r;
447
448 m->sender = "org.freedesktop.DBus";
449
450 r = bus_seal_message(bus, m);
451 if (r < 0)
452 return r;
453
454 *ret = m;
455 m = NULL;
456
457 return 1;
458}
459
460static int translate_name_change(sd_bus *bus, struct kdbus_msg *k, struct kdbus_item *d, sd_bus_message **ret) {
461 char new_owner[UNIQUE_NAME_MAX], old_owner[UNIQUE_NAME_MAX];
462
463 assert(bus);
464 assert(k);
465 assert(d);
466 assert(ret);
467
468 if (d->name_change.flags != 0)
469 return 0;
470
471 if (d->type == KDBUS_ITEM_NAME_ADD)
472 old_owner[0] = 0;
473 else
474 sprintf(old_owner, ":1.%llu", (unsigned long long) d->name_change.old_id);
475
476 if (d->type == KDBUS_ITEM_NAME_REMOVE)
477 new_owner[0] = 0;
478 else
479 sprintf(new_owner, ":1.%llu", (unsigned long long) d->name_change.new_id);
480
481 return return_name_owner_changed(bus, d->name_change.name, old_owner, new_owner, ret);
482}
483
484static int translate_id_change(sd_bus *bus, struct kdbus_msg *k, struct kdbus_item *d, sd_bus_message **ret) {
485 char owner[UNIQUE_NAME_MAX];
486
487 assert(bus);
488 assert(k);
489 assert(d);
490 assert(ret);
491
492 sprintf(owner, ":1.%llu", d->id_change.id);
493
494 return return_name_owner_changed(
495 bus, owner,
496 d->type == KDBUS_ITEM_ID_ADD ? NULL : owner,
497 d->type == KDBUS_ITEM_ID_ADD ? owner : NULL,
498 ret);
499}
500
501static int translate_reply(sd_bus *bus, struct kdbus_msg *k, struct kdbus_item *d, sd_bus_message **ret) {
502 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
503 int r;
504
505 assert(bus);
506 assert(k);
507 assert(d);
508 assert(ret);
509
510 r = bus_message_new_synthetic_error(
511 bus,
512 k->cookie_reply,
513 d->type == KDBUS_ITEM_REPLY_TIMEOUT ?
514 &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Method call timed out") :
515 &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Method call peer died"),
516 &m);
517 if (r < 0)
518 return r;
519
520 m->sender = "org.freedesktop.DBus";
521
522 r = bus_seal_message(bus, m);
523 if (r < 0)
524 return r;
525
526 *ret = m;
527 m = NULL;
528
529 return 1;
530}
531
532static int bus_kernel_translate_message(sd_bus *bus, struct kdbus_msg *k, sd_bus_message **ret) {
533 struct kdbus_item *d, *found = NULL;
534
535 static int (* const translate[])(sd_bus *bus, struct kdbus_msg *k, struct kdbus_item *d, sd_bus_message **ret) = {
536 [KDBUS_ITEM_NAME_ADD - _KDBUS_ITEM_KERNEL_BASE] = translate_name_change,
537 [KDBUS_ITEM_NAME_REMOVE - _KDBUS_ITEM_KERNEL_BASE] = translate_name_change,
538 [KDBUS_ITEM_NAME_CHANGE - _KDBUS_ITEM_KERNEL_BASE] = translate_name_change,
539
540 [KDBUS_ITEM_ID_ADD - _KDBUS_ITEM_KERNEL_BASE] = translate_id_change,
541 [KDBUS_ITEM_ID_REMOVE - _KDBUS_ITEM_KERNEL_BASE] = translate_id_change,
542
543 [KDBUS_ITEM_REPLY_TIMEOUT - _KDBUS_ITEM_KERNEL_BASE] = translate_reply,
544 [KDBUS_ITEM_REPLY_DEAD - _KDBUS_ITEM_KERNEL_BASE] = translate_reply,
545 };
546
547 assert(bus);
548 assert(k);
549 assert(ret);
550 assert(k->payload_type == KDBUS_PAYLOAD_KERNEL);
551
552 KDBUS_PART_FOREACH(d, k, items) {
553 if (d->type >= _KDBUS_ITEM_KERNEL_BASE && d->type < _KDBUS_ITEM_KERNEL_BASE + ELEMENTSOF(translate)) {
554 if (found)
555 return -EBADMSG;
556 found = d;
557 } else
558 log_debug("Got unknown field from kernel %llu", d->type);
559 }
560
561 if (!found) {
562 log_debug("Didn't find a kernel message to translate.");
563 return 0;
564 }
565
566 return translate[found->type](bus, k, d, ret);
567}
568
569int kdbus_translate_attach_flags(uint64_t mask, uint64_t *kdbus_mask) {
570
571 uint64_t m = 0;
572
573 SET_FLAG(m, KDBUS_ATTACH_CREDS,
574 !!(mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_GID|SD_BUS_CREDS_PID|SD_BUS_CREDS_PID_STARTTIME|SD_BUS_CREDS_TID)));
575
576 SET_FLAG(m, KDBUS_ATTACH_COMM,
577 !!(mask & (SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM)));
578
579 SET_FLAG(m, KDBUS_ATTACH_EXE,
580 !!(mask & SD_BUS_CREDS_EXE));
581
582 SET_FLAG(m, KDBUS_ATTACH_CMDLINE,
583 !!(mask & SD_BUS_CREDS_CMDLINE));
584
585 SET_FLAG(m, KDBUS_ATTACH_CGROUP,
586 !!(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)));
587
588 SET_FLAG(m, KDBUS_ATTACH_CAPS,
589 !!(mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS)));
590
591 SET_FLAG(m, KDBUS_ATTACH_SECLABEL,
592 !!(mask & SD_BUS_CREDS_SELINUX_CONTEXT));
593
594 SET_FLAG(m, KDBUS_ATTACH_AUDIT,
595 !!(mask & (SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID)));
596
597 *kdbus_mask = m;
598
599 return 0;
600}
601
602static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k, sd_bus_message **ret) {
603 sd_bus_message *m = NULL;
604 struct kdbus_item *d;
605 unsigned n_fds = 0;
606 _cleanup_free_ int *fds = NULL;
607 struct bus_header *h = NULL;
608 size_t total, n_bytes = 0, idx = 0;
609 const char *destination = NULL, *seclabel = NULL;
610 int r;
611
612 assert(bus);
613 assert(k);
614 assert(ret);
615 assert(k->payload_type == KDBUS_PAYLOAD_DBUS1);
616
617 KDBUS_PART_FOREACH(d, k, items) {
618 size_t l;
619
620 l = d->size - offsetof(struct kdbus_item, data);
621
622 switch (d->type) {
623
624 case KDBUS_ITEM_PAYLOAD_OFF:
625 if (!h) {
626 h = (struct bus_header *)((uint8_t *)bus->kdbus_buffer + d->vec.offset);
627
628 if (!bus_header_is_complete(h, d->vec.size))
629 return -EBADMSG;
630 }
631
632 n_bytes += d->vec.size;
633 break;
634
635 case KDBUS_ITEM_PAYLOAD_MEMFD:
636 if (!h)
637 return -EBADMSG;
638
639 n_bytes += d->memfd.size;
640 break;
641
642 case KDBUS_ITEM_FDS: {
643 int *f;
644 unsigned j;
645
646 j = l / sizeof(int);
647 f = realloc(fds, sizeof(int) * (n_fds + j));
648 if (!f)
649 return -ENOMEM;
650
651 fds = f;
652 memcpy(fds + n_fds, d->fds, sizeof(int) * j);
653 n_fds += j;
654 break;
655 }
656
657 case KDBUS_ITEM_SECLABEL:
658 seclabel = d->str;
659 break;
660 }
661 }
662
663 if (!h)
664 return -EBADMSG;
665
666 r = bus_header_message_size(h, &total);
667 if (r < 0)
668 return r;
669
670 if (n_bytes != total)
671 return -EBADMSG;
672
673 r = bus_message_from_header(bus, h, sizeof(struct bus_header), fds, n_fds, NULL, seclabel, 0, &m);
674 if (r < 0)
675 return r;
676
677 KDBUS_PART_FOREACH(d, k, items) {
678 size_t l;
679
680 l = d->size - offsetof(struct kdbus_item, data);
681
682 switch (d->type) {
683
684 case KDBUS_ITEM_PAYLOAD_OFF: {
685 size_t begin_body;
686
687 begin_body = BUS_MESSAGE_BODY_BEGIN(m);
688
689 if (idx + d->vec.size > begin_body) {
690 struct bus_body_part *part;
691
692 /* Contains body material */
693
694 part = message_append_part(m);
695 if (!part) {
696 r = -ENOMEM;
697 goto fail;
698 }
699
700 /* A -1 offset is NUL padding. */
701 part->is_zero = d->vec.offset == ~0ULL;
702
703 if (idx >= begin_body) {
704 if (!part->is_zero)
705 part->data = (uint8_t *)bus->kdbus_buffer + d->vec.offset;
706 part->size = d->vec.size;
707 } else {
708 if (!part->is_zero)
709 part->data = (uint8_t *)bus->kdbus_buffer + d->vec.offset + (begin_body - idx);
710 part->size = d->vec.size - (begin_body - idx);
711 }
712
713 part->sealed = true;
714 }
715
716 idx += d->vec.size;
717 break;
718 }
719
720 case KDBUS_ITEM_PAYLOAD_MEMFD: {
721 struct bus_body_part *part;
722
723 if (idx < BUS_MESSAGE_BODY_BEGIN(m)) {
724 r = -EBADMSG;
725 goto fail;
726 }
727
728 part = message_append_part(m);
729 if (!part) {
730 r = -ENOMEM;
731 goto fail;
732 }
733
734 part->memfd = d->memfd.fd;
735 part->size = d->memfd.size;
736 part->sealed = true;
737
738 idx += d->memfd.size;
739 break;
740 }
741
742 case KDBUS_ITEM_CREDS:
743 m->creds.pid_starttime = d->creds.starttime / NSEC_PER_USEC;
744 m->creds.uid = d->creds.uid;
745 m->creds.gid = d->creds.gid;
746 m->creds.pid = d->creds.pid;
747 m->creds.tid = d->creds.tid;
748 m->creds.mask |= (SD_BUS_CREDS_UID|SD_BUS_CREDS_GID|SD_BUS_CREDS_PID|SD_BUS_CREDS_PID_STARTTIME|SD_BUS_CREDS_TID) & bus->creds_mask;
749 break;
750
751 case KDBUS_ITEM_TIMESTAMP:
752 m->realtime = d->timestamp.realtime_ns / NSEC_PER_USEC;
753 m->monotonic = d->timestamp.monotonic_ns / NSEC_PER_USEC;
754 break;
755
756 case KDBUS_ITEM_PID_COMM:
757 m->creds.comm = d->str;
758 m->creds.mask |= SD_BUS_CREDS_COMM & bus->creds_mask;
759 break;
760
761 case KDBUS_ITEM_TID_COMM:
762 m->creds.tid_comm = d->str;
763 m->creds.mask |= SD_BUS_CREDS_TID_COMM & bus->creds_mask;
764 break;
765
766 case KDBUS_ITEM_EXE:
767 m->creds.exe = d->str;
768 m->creds.mask |= SD_BUS_CREDS_EXE & bus->creds_mask;
769 break;
770
771 case KDBUS_ITEM_CMDLINE:
772 m->creds.cmdline = d->str;
773 m->creds.cmdline_length = l;
774 m->creds.mask |= SD_BUS_CREDS_CMDLINE & bus->creds_mask;
775 break;
776
777 case KDBUS_ITEM_CGROUP:
778 m->creds.cgroup = d->str;
779 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;
780 break;
781
782 case KDBUS_ITEM_AUDIT:
783 m->creds.audit_session_id = d->audit.sessionid;
784 m->creds.audit_login_uid = d->audit.loginuid;
785 m->creds.mask |= (SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID) & bus->creds_mask;
786 break;
787
788 case KDBUS_ITEM_CAPS:
789 m->creds.capability = d->data;
790 m->creds.capability_size = l;
791 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;
792 break;
793
794 case KDBUS_ITEM_DST_NAME:
795 destination = d->str;
796 break;
797
798 case KDBUS_ITEM_FDS:
799 case KDBUS_ITEM_SECLABEL:
800 case KDBUS_ITEM_NAMES:
801 break;
802
803 default:
804 log_debug("Got unknown field from kernel %llu", d->type);
805 }
806 }
807
808 r = bus_message_parse_fields(m);
809 if (r < 0)
810 goto fail;
811
812 if (k->src_id == KDBUS_SRC_ID_KERNEL)
813 m->sender = "org.freedesktop.DBus";
814 else {
815 snprintf(m->sender_buffer, sizeof(m->sender_buffer), ":1.%llu", (unsigned long long) k->src_id);
816 m->sender = m->sender_buffer;
817 }
818
819 if (!m->destination) {
820 if (destination)
821 m->destination = destination;
822 else if (k->dst_id != KDBUS_DST_ID_WELL_KNOWN_NAME &&
823 k->dst_id != KDBUS_DST_ID_BROADCAST) {
824 snprintf(m->destination_buffer, sizeof(m->destination_buffer), ":1.%llu", (unsigned long long) k->dst_id);
825 m->destination = m->destination_buffer;
826 }
827 }
828
829 /* We take possession of the kmsg struct now */
830 m->kdbus = k;
831 m->release_kdbus = true;
832 m->free_fds = true;
833
834 fds = NULL;
835
836 *ret = m;
837 return 1;
838
839fail:
840 if (m) {
841 struct bus_body_part *part;
842 unsigned i;
843
844 /* Make sure the memfds are not freed twice */
845 MESSAGE_FOREACH_PART(part, i, m)
846 if (part->memfd >= 0)
847 part->memfd = -1;
848
849 sd_bus_message_unref(m);
850 }
851
852 return r;
853}
854
855int bus_kernel_read_message(sd_bus *bus, sd_bus_message **m) {
856 uint64_t off;
857 struct kdbus_msg *k;
858 int r;
859
860 assert(bus);
861 assert(m);
862
863 r = ioctl(bus->input_fd, KDBUS_CMD_MSG_RECV, &off);
864 if (r < 0) {
865 if (errno == EAGAIN)
866 return 0;
867
868 return -errno;
869 }
870 k = (struct kdbus_msg *)((uint8_t *)bus->kdbus_buffer + off);
871
872 if (k->payload_type == KDBUS_PAYLOAD_DBUS1)
873 r = bus_kernel_make_message(bus, k, m);
874 else if (k->payload_type == KDBUS_PAYLOAD_KERNEL)
875 r = bus_kernel_translate_message(bus, k, m);
876 else
877 r = 0;
878
879 if (r <= 0)
880 close_kdbus_msg(bus, k);
881
882 return r < 0 ? r : 1;
883}
884
885int bus_kernel_create(const char *name, char **s) {
886 struct kdbus_cmd_bus_make *make;
887 struct kdbus_item *n;
888 size_t l;
889 int fd;
890 char *p;
891
892 assert(name);
893 assert(s);
894
895 fd = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
896 if (fd < 0)
897 return -errno;
898
899 l = strlen(name);
900 make = alloca0(offsetof(struct kdbus_cmd_bus_make, items) +
901 KDBUS_PART_HEADER_SIZE + sizeof(uint64_t) +
902 KDBUS_PART_HEADER_SIZE + DECIMAL_STR_MAX(uid_t) + 1 + l + 1);
903
904 n = make->items;
905 n->type = KDBUS_MAKE_NAME;
906 sprintf(n->str, "%lu-%s", (unsigned long) getuid(), name);
907 n->size = KDBUS_PART_HEADER_SIZE + strlen(n->str) + 1;
908
909 make->size = offsetof(struct kdbus_cmd_bus_make, items) + n->size;
910 make->flags = KDBUS_MAKE_POLICY_OPEN;
911 make->bus_flags = 0;
912 make->bloom_size = BLOOM_SIZE;
913 assert_cc(BLOOM_SIZE % 8 == 0);
914
915 p = strjoin("/dev/kdbus/", n->str, "/bus", NULL);
916 if (!p)
917 return -ENOMEM;
918
919 if (ioctl(fd, KDBUS_CMD_BUS_MAKE, make) < 0) {
920 close_nointr_nofail(fd);
921 free(p);
922 return -errno;
923 }
924
925 if (s)
926 *s = p;
927
928 return fd;
929}
930
931int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *size) {
932 struct memfd_cache *c;
933 int fd;
934
935 assert(address);
936 assert(size);
937
938 if (!bus || !bus->is_kernel)
939 return -ENOTSUP;
940
941 assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) >= 0);
942
943 if (bus->n_memfd_cache <= 0) {
944 int r;
945
946 assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
947
948 r = ioctl(bus->input_fd, KDBUS_CMD_MEMFD_NEW, &fd);
949 if (r < 0)
950 return -errno;
951
952 *address = NULL;
953 *size = 0;
954 return fd;
955 }
956
957 c = &bus->memfd_cache[--bus->n_memfd_cache];
958
959 assert(c->fd >= 0);
960 assert(c->size == 0 || c->address);
961
962 *address = c->address;
963 *size = c->size;
964 fd = c->fd;
965
966 assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
967
968 return fd;
969}
970
971static void close_and_munmap(int fd, void *address, size_t size) {
972 if (size > 0)
973 assert_se(munmap(address, PAGE_ALIGN(size)) >= 0);
974
975 close_nointr_nofail(fd);
976}
977
978void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t size) {
979 struct memfd_cache *c;
980 uint64_t max_sz = PAGE_ALIGN(MEMFD_CACHE_ITEM_SIZE_MAX);
981
982 assert(fd >= 0);
983 assert(size == 0 || address);
984
985 if (!bus || !bus->is_kernel) {
986 close_and_munmap(fd, address, size);
987 return;
988 }
989
990 assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) >= 0);
991
992 if (bus->n_memfd_cache >= ELEMENTSOF(bus->memfd_cache)) {
993 assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
994
995 close_and_munmap(fd, address, size);
996 return;
997 }
998
999 c = &bus->memfd_cache[bus->n_memfd_cache++];
1000 c->fd = fd;
1001 c->address = address;
1002
1003 /* If overly long, let's return a bit to the OS */
1004 if (size > max_sz) {
1005 assert_se(ioctl(fd, KDBUS_CMD_MEMFD_SIZE_SET, &max_sz) >= 0);
1006 assert_se(munmap((uint8_t*) address + max_sz, PAGE_ALIGN(size - max_sz)) >= 0);
1007 c->size = max_sz;
1008 } else
1009 c->size = size;
1010
1011 assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
1012}
1013
1014void bus_kernel_flush_memfd(sd_bus *b) {
1015 unsigned i;
1016
1017 assert(b);
1018
1019 for (i = 0; i < b->n_memfd_cache; i++)
1020 close_and_munmap(b->memfd_cache[i].fd, b->memfd_cache[i].address, b->memfd_cache[i].size);
1021}
1022
1023int kdbus_translate_request_name_flags(uint64_t sd_bus_flags, uint64_t *kdbus_flags) {
1024
1025 assert_return(kdbus_flags != NULL, -EINVAL);
1026
1027 *kdbus_flags = 0;
1028
1029 if (sd_bus_flags & SD_BUS_NAME_ALLOW_REPLACEMENT)
1030 *kdbus_flags |= KDBUS_NAME_ALLOW_REPLACEMENT;
1031
1032 if (sd_bus_flags & SD_BUS_NAME_REPLACE_EXISTING)
1033 *kdbus_flags |= KDBUS_NAME_REPLACE_EXISTING;
1034
1035 if (!(sd_bus_flags & SD_BUS_NAME_DO_NOT_QUEUE))
1036 *kdbus_flags |= KDBUS_NAME_QUEUE;
1037
1038 return 0;
1039}