]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-bus/bus-kernel.c
bus: make sure we check for "incompatible" flags negotiated with kernel kdbus
[thirdparty/systemd.git] / src / libsystemd-bus / bus-kernel.c
CommitLineData
6629161f
LP
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
7211f918
LP
22#ifdef HAVE_VALGRIND_MEMCHECK_H
23#include <valgrind/memcheck.h>
24#endif
25
6629161f 26#include <fcntl.h>
c556fe79 27#include <malloc.h>
fd8d62d9 28#include <sys/mman.h>
6629161f
LP
29
30#include "util.h"
31
32#include "bus-internal.h"
33#include "bus-message.h"
34#include "bus-kernel.h"
a56f19c4 35#include "bus-bloom.h"
777d7a61
LP
36#include "bus-util.h"
37
38#define UNIQUE_NAME_MAX (3+DECIMAL_STR_MAX(uint64_t))
6629161f 39
c7819669 40int bus_kernel_parse_unique_name(const char *s, uint64_t *id) {
6629161f
LP
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
febfd508 56static void append_payload_vec(struct kdbus_item **d, const void *p, size_t sz) {
6629161f 57 assert(d);
6629161f
LP
58 assert(sz > 0);
59
e86b80b8
LP
60 *d = ALIGN8_PTR(*d);
61
66b26c5c
LP
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
febfd508 66 (*d)->size = offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec);
ea1edece 67 (*d)->type = KDBUS_ITEM_PAYLOAD_VEC;
a392d361 68 (*d)->vec.address = PTR_TO_UINT64(p);
6629161f
LP
69 (*d)->vec.size = sz;
70
febfd508 71 *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
6629161f
LP
72}
73
a392d361
LP
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);
ea1edece 81 (*d)->type = KDBUS_ITEM_PAYLOAD_MEMFD;
a392d361
LP
82 (*d)->memfd.fd = memfd;
83 (*d)->memfd.size = sz;
84
85 *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
86}
87
febfd508 88static void append_destination(struct kdbus_item **d, const char *s, size_t length) {
6629161f 89 assert(d);
b5baa8fe 90 assert(s);
6629161f 91
e86b80b8
LP
92 *d = ALIGN8_PTR(*d);
93
febfd508 94 (*d)->size = offsetof(struct kdbus_item, str) + length + 1;
ea1edece 95 (*d)->type = KDBUS_ITEM_DST_NAME;
51038c03 96 memcpy((*d)->str, s, length + 1);
6629161f 97
febfd508 98 *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
6629161f
LP
99}
100
febfd508 101static void* append_bloom(struct kdbus_item **d, size_t length) {
a56f19c4
LP
102 void *r;
103
b5baa8fe 104 assert(d);
b5baa8fe
LP
105
106 *d = ALIGN8_PTR(*d);
107
febfd508 108 (*d)->size = offsetof(struct kdbus_item, data) + length;
ea1edece 109 (*d)->type = KDBUS_ITEM_BLOOM;
a56f19c4 110 r = (*d)->data;
b5baa8fe 111
febfd508 112 *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
a56f19c4
LP
113
114 return r;
115}
116
febfd508 117static void append_fds(struct kdbus_item **d, const int fds[], unsigned n_fds) {
9097fe29
LP
118 assert(d);
119 assert(fds);
120 assert(n_fds > 0);
121
122 *d = ALIGN8_PTR(*d);
febfd508 123 (*d)->size = offsetof(struct kdbus_item, fds) + sizeof(int) * n_fds;
ea1edece 124 (*d)->type = KDBUS_ITEM_FDS;
9097fe29
LP
125 memcpy((*d)->fds, fds, sizeof(int) * n_fds);
126
febfd508 127 *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
9097fe29
LP
128}
129
a56f19c4
LP
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);
f11e11e3 147 bloom_add_pair(bloom, "path-slash-prefix", m->path);
a56f19c4
LP
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;
b5baa8fe
LP
192}
193
5b7d4c1c 194static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) {
9b29bb68 195 struct bus_body_part *part;
febfd508 196 struct kdbus_item *d;
6629161f
LP
197 bool well_known;
198 uint64_t unique;
199 size_t sz, dl;
9b29bb68 200 unsigned i;
6629161f
LP
201 int r;
202
5b7d4c1c 203 assert(b);
6629161f
LP
204 assert(m);
205 assert(m->sealed);
e9a967f9
LP
206
207 if (m->kdbus)
208 return 0;
6629161f
LP
209
210 if (m->destination) {
c7819669 211 r = bus_kernel_parse_unique_name(m->destination, &unique);
6629161f
LP
212 if (r < 0)
213 return r;
214
215 well_known = r == 0;
216 } else
217 well_known = false;
218
b1454bf0 219 sz = offsetof(struct kdbus_msg, items);
6629161f 220
a392d361
LP
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
69aec65c 224 /* Add in fixed header, fields header and payload */
c91cb83c 225 sz += (1 + m->n_body_parts) *
bc7fd8cd 226 ALIGN8(offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec));
6629161f 227
69aec65c 228 /* Add space for bloom filter */
febfd508 229 sz += ALIGN8(offsetof(struct kdbus_item, data) + BLOOM_SIZE);
b5baa8fe 230
6629161f
LP
231 /* Add in well-known destination header */
232 if (well_known) {
233 dl = strlen(m->destination);
febfd508 234 sz += ALIGN8(offsetof(struct kdbus_item, str) + dl + 1);
6629161f
LP
235 }
236
9097fe29
LP
237 /* Add space for unix fds */
238 if (m->n_fds > 0)
febfd508 239 sz += ALIGN8(offsetof(struct kdbus_item, fds) + sizeof(int)*m->n_fds);
9097fe29 240
c556fe79 241 m->kdbus = memalign(8, sz);
66b26c5c
LP
242 if (!m->kdbus) {
243 r = -ENOMEM;
244 goto fail;
245 }
6629161f 246
66b26c5c 247 m->free_kdbus = true;
d9115e18
LP
248 memset(m->kdbus, 0, sz);
249
6629161f
LP
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 :
b5baa8fe 255 m->destination ? unique : KDBUS_DST_ID_BROADCAST;
6629161f
LP
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
b1454bf0 261 d = m->kdbus->items;
6629161f
LP
262
263 if (well_known)
264 append_destination(&d, m->destination, dl);
265
c91cb83c 266 append_payload_vec(&d, m->header, BUS_MESSAGE_BODY_BEGIN(m));
a392d361
LP
267
268 MESSAGE_FOREACH_PART(part, i, m) {
269 if (part->is_zero) {
66b26c5c
LP
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
a392d361
LP
275 append_payload_vec(&d, NULL, part->size);
276 continue;
277 }
278
66b26c5c
LP
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 */
a392d361 282
66b26c5c
LP
283 append_payload_memfd(&d, part->memfd, part->size);
284 continue;
a392d361
LP
285 }
286
66b26c5c
LP
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;
a392d361 292
bc7fd8cd 293 append_payload_vec(&d, part->data, part->size);
a392d361 294 }
6629161f 295
5b7d4c1c
LP
296 if (m->kdbus->dst_id == KDBUS_DST_ID_BROADCAST) {
297 void *p;
298
a56f19c4
LP
299 p = append_bloom(&d, BLOOM_SIZE);
300 r = bus_message_setup_bloom(m, p);
a392d361
LP
301 if (r < 0)
302 goto fail;
5b7d4c1c 303 }
b5baa8fe 304
9097fe29
LP
305 if (m->n_fds > 0)
306 append_fds(&d, m->fds, m->n_fds);
307
e9a967f9 308 m->kdbus->size = (uint8_t*) d - (uint8_t*) m->kdbus;
6629161f
LP
309 assert(m->kdbus->size <= sz);
310
311 return 0;
a392d361
LP
312
313fail:
66b26c5c 314 m->poisoned = true;
a392d361 315 return r;
6629161f
LP
316}
317
318int bus_kernel_take_fd(sd_bus *b) {
62b3e928 319 struct kdbus_cmd_hello hello;
6629161f
LP
320 int r;
321
322 assert(b);
323
f08838da
LP
324 if (b->is_server)
325 return -EINVAL;
326
8f155917
LP
327 b->use_memfd = 1;
328
62b3e928
KS
329 zero(hello);
330 hello.size = sizeof(hello);
331 hello.conn_flags = b->hello_flags;
d21a7bb1 332 hello.attach_flags = b->attach_flags;
62b3e928
KS
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
fd8d62d9 339 if (!b->kdbus_buffer) {
62b3e928 340 b->kdbus_buffer = mmap(NULL, KDBUS_POOL_SIZE, PROT_READ, MAP_SHARED, b->input_fd, 0);
fd8d62d9
LP
341 if (b->kdbus_buffer == MAP_FAILED) {
342 b->kdbus_buffer = NULL;
343 return -errno;
344 }
345 }
346
5b7d4c1c
LP
347 /* The higher 32bit of both flags fields are considered
348 * 'incompatible flags'. Refuse them all for now. */
62b3e928
KS
349 if (hello.bus_flags > 0xFFFFFFFFULL ||
350 hello.conn_flags > 0xFFFFFFFFULL)
5b7d4c1c
LP
351 return -ENOTSUP;
352
62b3e928 353 if (hello.bloom_size != BLOOM_SIZE)
a56f19c4
LP
354 return -ENOTSUP;
355
62b3e928 356 if (asprintf(&b->unique_name, ":1.%llu", (unsigned long long) hello.id) < 0)
de297575
LP
357 return -ENOMEM;
358
219728b3
LP
359 b->unique_id = hello.id;
360
6629161f 361 b->is_kernel = true;
f08838da 362 b->bus_client = true;
62b3e928 363 b->can_fds = !!(hello.conn_flags & KDBUS_HELLO_ACCEPT_FD);
6629161f 364
c58dea19
DM
365 /* the kernel told us the UUID of the underlying bus */
366 memcpy(b->server_id.bytes, hello.id128, sizeof(b->server_id.bytes));
367
7adc46fc 368 return bus_start_running(b);
6629161f
LP
369}
370
371int bus_kernel_connect(sd_bus *b) {
372 assert(b);
373 assert(b->input_fd < 0);
374 assert(b->output_fd < 0);
375 assert(b->kernel);
376
f08838da
LP
377 if (b->is_server)
378 return -EINVAL;
379
6629161f 380 b->input_fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC);
c320885c 381 if (b->input_fd < 0)
6629161f
LP
382 return -errno;
383
384 b->output_fd = b->input_fd;
385
386 return bus_kernel_take_fd(b);
387}
388
389int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m) {
390 int r;
391
392 assert(bus);
393 assert(m);
394 assert(bus->state == BUS_RUNNING);
395
a43b9ca3
LP
396 /* If we can't deliver, we want room for the error message */
397 r = bus_rqueue_make_room(bus);
398 if (r < 0)
399 return r;
400
5b7d4c1c 401 r = bus_message_setup_kmsg(bus, m);
6629161f
LP
402 if (r < 0)
403 return r;
404
405 r = ioctl(bus->output_fd, KDBUS_CMD_MSG_SEND, m->kdbus);
a43b9ca3
LP
406 if (r < 0) {
407 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
408 sd_bus_message *reply;
409
410 if (errno == EAGAIN || errno == EINTR)
411 return 0;
412 else if (errno == ENXIO || errno == ESRCH) {
413
414 /* ENXIO: unique name not known
415 * ESRCH: well-known name not known */
416
417 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
418 sd_bus_error_setf(&error, SD_BUS_ERROR_SERVICE_UNKNOWN, "Destination %s not known", m->destination);
419 else
420 return 0;
421
422 } else if (errno == EADDRNOTAVAIL) {
423
424 /* EADDRNOTAVAIL: activation is possible, but turned off in request flags */
425
426 if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
427 sd_bus_error_setf(&error, SD_BUS_ERROR_SERVICE_UNKNOWN, "Activation of %s not requested", m->destination);
428 else
429 return 0;
430 } else
431 return -errno;
432
433 r = bus_message_new_synthetic_error(
434 bus,
435 BUS_MESSAGE_SERIAL(m),
436 &error,
437 &reply);
438
439 if (r < 0)
440 return r;
441
442 r = bus_seal_synthetic_message(bus, reply);
443 if (r < 0)
444 return r;
445
446 bus->rqueue[bus->rqueue_size++] = reply;
447
448 return 0;
449 }
6629161f 450
51038c03 451 return 1;
6629161f
LP
452}
453
fd8d62d9 454static void close_kdbus_msg(sd_bus *bus, struct kdbus_msg *k) {
62b3e928 455 uint64_t off;
febfd508 456 struct kdbus_item *d;
6629161f 457
fd8d62d9
LP
458 assert(bus);
459 assert(k);
460
62b3e928 461 off = (uint8_t *)k - (uint8_t *)bus->kdbus_buffer;
1d0e3c98 462 ioctl(bus->input_fd, KDBUS_CMD_FREE, &off);
fd8d62d9 463
9eb34e82 464 KDBUS_PART_FOREACH(d, k, items) {
6629161f 465
ea1edece 466 if (d->type == KDBUS_ITEM_FDS)
1307c3ff 467 close_many(d->fds, (d->size - offsetof(struct kdbus_item, fds)) / sizeof(int));
ea1edece 468 else if (d->type == KDBUS_ITEM_PAYLOAD_MEMFD)
1307c3ff 469 close_nointr_nofail(d->memfd.fd);
6629161f
LP
470 }
471}
472
7d22c717 473static int push_name_owner_changed(sd_bus *bus, const char *name, const char *old_owner, const char *new_owner) {
777d7a61
LP
474 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
475 int r;
476
477 assert(bus);
777d7a61
LP
478
479 r = sd_bus_message_new_signal(
480 bus,
481 "/org/freedesktop/DBus",
482 "org.freedesktop.DBus",
483 "NameOwnerChanged",
484 &m);
485 if (r < 0)
486 return r;
487
488 r = sd_bus_message_append(m, "sss", name, old_owner, new_owner);
489 if (r < 0)
490 return r;
491
492 m->sender = "org.freedesktop.DBus";
493
7adc46fc 494 r = bus_seal_synthetic_message(bus, m);
7d22c717
LP
495 if (r < 0)
496 return r;
777d7a61 497
7adc46fc 498 bus->rqueue[bus->rqueue_size++] = m;
7d22c717 499 m = NULL;
219728b3 500
219728b3
LP
501 return 1;
502}
503
7d22c717 504static int translate_name_change(sd_bus *bus, struct kdbus_msg *k, struct kdbus_item *d) {
777d7a61
LP
505 char new_owner[UNIQUE_NAME_MAX], old_owner[UNIQUE_NAME_MAX];
506
507 assert(bus);
508 assert(k);
509 assert(d);
777d7a61
LP
510
511 if (d->name_change.flags != 0)
512 return 0;
513
514 if (d->type == KDBUS_ITEM_NAME_ADD)
515 old_owner[0] = 0;
516 else
517 sprintf(old_owner, ":1.%llu", (unsigned long long) d->name_change.old_id);
518
519 if (d->type == KDBUS_ITEM_NAME_REMOVE)
520 new_owner[0] = 0;
521 else
522 sprintf(new_owner, ":1.%llu", (unsigned long long) d->name_change.new_id);
523
7d22c717 524 return push_name_owner_changed(bus, d->name_change.name, old_owner, new_owner);
777d7a61
LP
525}
526
7d22c717 527static int translate_id_change(sd_bus *bus, struct kdbus_msg *k, struct kdbus_item *d) {
777d7a61
LP
528 char owner[UNIQUE_NAME_MAX];
529
530 assert(bus);
531 assert(k);
532 assert(d);
777d7a61
LP
533
534 sprintf(owner, ":1.%llu", d->id_change.id);
535
7d22c717 536 return push_name_owner_changed(
777d7a61
LP
537 bus, owner,
538 d->type == KDBUS_ITEM_ID_ADD ? NULL : owner,
7d22c717 539 d->type == KDBUS_ITEM_ID_ADD ? owner : NULL);
777d7a61
LP
540}
541
7d22c717 542static int translate_reply(sd_bus *bus, struct kdbus_msg *k, struct kdbus_item *d) {
777d7a61
LP
543 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
544 int r;
545
546 assert(bus);
547 assert(k);
548 assert(d);
777d7a61
LP
549
550 r = bus_message_new_synthetic_error(
551 bus,
552 k->cookie_reply,
553 d->type == KDBUS_ITEM_REPLY_TIMEOUT ?
554 &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Method call timed out") :
555 &SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Method call peer died"),
556 &m);
557 if (r < 0)
558 return r;
559
560 m->sender = "org.freedesktop.DBus";
561
7adc46fc 562 r = bus_seal_synthetic_message(bus, m);
7d22c717
LP
563 if (r < 0)
564 return r;
777d7a61 565
7adc46fc 566 bus->rqueue[bus->rqueue_size++] = m;
7d22c717 567 m = NULL;
7adc46fc 568
777d7a61
LP
569 return 1;
570}
571
7d22c717 572static int bus_kernel_translate_message(sd_bus *bus, struct kdbus_msg *k) {
777d7a61
LP
573 struct kdbus_item *d, *found = NULL;
574
7d22c717 575 static int (* const translate[])(sd_bus *bus, struct kdbus_msg *k, struct kdbus_item *d) = {
777d7a61
LP
576 [KDBUS_ITEM_NAME_ADD - _KDBUS_ITEM_KERNEL_BASE] = translate_name_change,
577 [KDBUS_ITEM_NAME_REMOVE - _KDBUS_ITEM_KERNEL_BASE] = translate_name_change,
578 [KDBUS_ITEM_NAME_CHANGE - _KDBUS_ITEM_KERNEL_BASE] = translate_name_change,
579
580 [KDBUS_ITEM_ID_ADD - _KDBUS_ITEM_KERNEL_BASE] = translate_id_change,
581 [KDBUS_ITEM_ID_REMOVE - _KDBUS_ITEM_KERNEL_BASE] = translate_id_change,
582
583 [KDBUS_ITEM_REPLY_TIMEOUT - _KDBUS_ITEM_KERNEL_BASE] = translate_reply,
584 [KDBUS_ITEM_REPLY_DEAD - _KDBUS_ITEM_KERNEL_BASE] = translate_reply,
585 };
586
587 assert(bus);
588 assert(k);
777d7a61
LP
589 assert(k->payload_type == KDBUS_PAYLOAD_KERNEL);
590
591 KDBUS_PART_FOREACH(d, k, items) {
592 if (d->type >= _KDBUS_ITEM_KERNEL_BASE && d->type < _KDBUS_ITEM_KERNEL_BASE + ELEMENTSOF(translate)) {
593 if (found)
594 return -EBADMSG;
595 found = d;
596 } else
597 log_debug("Got unknown field from kernel %llu", d->type);
598 }
599
600 if (!found) {
601 log_debug("Didn't find a kernel message to translate.");
602 return 0;
603 }
604
51502af3 605 return translate[found->type - _KDBUS_ITEM_KERNEL_BASE](bus, k, found);
777d7a61
LP
606}
607
7d22c717 608static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) {
6629161f 609 sd_bus_message *m = NULL;
febfd508 610 struct kdbus_item *d;
1307c3ff 611 unsigned n_fds = 0;
6629161f
LP
612 _cleanup_free_ int *fds = NULL;
613 struct bus_header *h = NULL;
614 size_t total, n_bytes = 0, idx = 0;
69aec65c 615 const char *destination = NULL, *seclabel = NULL;
6629161f
LP
616 int r;
617
618 assert(bus);
619 assert(k);
777d7a61 620 assert(k->payload_type == KDBUS_PAYLOAD_DBUS1);
6629161f 621
9eb34e82 622 KDBUS_PART_FOREACH(d, k, items) {
6629161f
LP
623 size_t l;
624
febfd508 625 l = d->size - offsetof(struct kdbus_item, data);
6629161f 626
777d7a61 627 switch (d->type) {
6629161f 628
777d7a61 629 case KDBUS_ITEM_PAYLOAD_OFF:
6629161f 630 if (!h) {
62b3e928 631 h = (struct bus_header *)((uint8_t *)bus->kdbus_buffer + d->vec.offset);
c91cb83c
LP
632
633 if (!bus_header_is_complete(h, d->vec.size))
634 return -EBADMSG;
6629161f
LP
635 }
636
fd8d62d9 637 n_bytes += d->vec.size;
777d7a61 638 break;
6629161f 639
777d7a61 640 case KDBUS_ITEM_PAYLOAD_MEMFD:
1307c3ff
LP
641 if (!h)
642 return -EBADMSG;
643
644 n_bytes += d->memfd.size;
777d7a61 645 break;
1307c3ff 646
777d7a61 647 case KDBUS_ITEM_FDS: {
6629161f
LP
648 int *f;
649 unsigned j;
650
651 j = l / sizeof(int);
652 f = realloc(fds, sizeof(int) * (n_fds + j));
653 if (!f)
654 return -ENOMEM;
655
656 fds = f;
9097fe29 657 memcpy(fds + n_fds, d->fds, sizeof(int) * j);
6629161f 658 n_fds += j;
777d7a61
LP
659 break;
660 }
f9be01f3 661
777d7a61 662 case KDBUS_ITEM_SECLABEL:
69aec65c 663 seclabel = d->str;
777d7a61
LP
664 break;
665 }
6629161f
LP
666 }
667
668 if (!h)
669 return -EBADMSG;
670
c91cb83c 671 r = bus_header_message_size(h, &total);
6629161f
LP
672 if (r < 0)
673 return r;
674
675 if (n_bytes != total)
676 return -EBADMSG;
677
df2d202e 678 r = bus_message_from_header(bus, h, sizeof(struct bus_header), fds, n_fds, NULL, seclabel, 0, &m);
6629161f
LP
679 if (r < 0)
680 return r;
681
9eb34e82 682 KDBUS_PART_FOREACH(d, k, items) {
6629161f
LP
683 size_t l;
684
febfd508 685 l = d->size - offsetof(struct kdbus_item, data);
6629161f 686
777d7a61
LP
687 switch (d->type) {
688
689 case KDBUS_ITEM_PAYLOAD_OFF: {
bc7fd8cd 690 size_t begin_body;
fd8d62d9 691
c91cb83c 692 begin_body = BUS_MESSAGE_BODY_BEGIN(m);
bc7fd8cd
LP
693
694 if (idx + d->vec.size > begin_body) {
695 struct bus_body_part *part;
696
697 /* Contains body material */
698
699 part = message_append_part(m);
700 if (!part) {
1307c3ff
LP
701 r = -ENOMEM;
702 goto fail;
bc7fd8cd
LP
703 }
704
62b3e928
KS
705 /* A -1 offset is NUL padding. */
706 part->is_zero = d->vec.offset == ~0ULL;
707
bc7fd8cd 708 if (idx >= begin_body) {
62b3e928
KS
709 if (!part->is_zero)
710 part->data = (uint8_t *)bus->kdbus_buffer + d->vec.offset;
bc7fd8cd
LP
711 part->size = d->vec.size;
712 } else {
62b3e928
KS
713 if (!part->is_zero)
714 part->data = (uint8_t *)bus->kdbus_buffer + d->vec.offset + (begin_body - idx);
bc7fd8cd
LP
715 part->size = d->vec.size - (begin_body - idx);
716 }
717
718 part->sealed = true;
719 }
fd8d62d9
LP
720
721 idx += d->vec.size;
777d7a61
LP
722 break;
723 }
724
725 case KDBUS_ITEM_PAYLOAD_MEMFD: {
1307c3ff
LP
726 struct bus_body_part *part;
727
728 if (idx < BUS_MESSAGE_BODY_BEGIN(m)) {
729 r = -EBADMSG;
730 goto fail;
731 }
732
733 part = message_append_part(m);
734 if (!part) {
735 r = -ENOMEM;
736 goto fail;
737 }
738
739 part->memfd = d->memfd.fd;
740 part->size = d->memfd.size;
741 part->sealed = true;
742
743 idx += d->memfd.size;
777d7a61
LP
744 break;
745 }
69aec65c 746
777d7a61 747 case KDBUS_ITEM_CREDS:
5b12334d
LP
748 m->creds.pid_starttime = d->creds.starttime / NSEC_PER_USEC;
749 m->creds.uid = d->creds.uid;
750 m->creds.gid = d->creds.gid;
751 m->creds.pid = d->creds.pid;
752 m->creds.tid = d->creds.tid;
753 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;
777d7a61 754 break;
5b12334d 755
777d7a61 756 case KDBUS_ITEM_TIMESTAMP:
69aec65c
LP
757 m->realtime = d->timestamp.realtime_ns / NSEC_PER_USEC;
758 m->monotonic = d->timestamp.monotonic_ns / NSEC_PER_USEC;
777d7a61 759 break;
5b12334d 760
777d7a61 761 case KDBUS_ITEM_PID_COMM:
5b12334d
LP
762 m->creds.comm = d->str;
763 m->creds.mask |= SD_BUS_CREDS_COMM & bus->creds_mask;
777d7a61 764 break;
5b12334d 765
777d7a61 766 case KDBUS_ITEM_TID_COMM:
5b12334d
LP
767 m->creds.tid_comm = d->str;
768 m->creds.mask |= SD_BUS_CREDS_TID_COMM & bus->creds_mask;
777d7a61 769 break;
5b12334d 770
777d7a61 771 case KDBUS_ITEM_EXE:
5b12334d
LP
772 m->creds.exe = d->str;
773 m->creds.mask |= SD_BUS_CREDS_EXE & bus->creds_mask;
777d7a61 774 break;
5b12334d 775
777d7a61 776 case KDBUS_ITEM_CMDLINE:
5b12334d 777 m->creds.cmdline = d->str;
49b832c5 778 m->creds.cmdline_size = l;
5b12334d 779 m->creds.mask |= SD_BUS_CREDS_CMDLINE & bus->creds_mask;
777d7a61 780 break;
5b12334d 781
777d7a61 782 case KDBUS_ITEM_CGROUP:
5b12334d
LP
783 m->creds.cgroup = d->str;
784 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;
777d7a61 785 break;
5b12334d 786
777d7a61 787 case KDBUS_ITEM_AUDIT:
5b12334d
LP
788 m->creds.audit_session_id = d->audit.sessionid;
789 m->creds.audit_login_uid = d->audit.loginuid;
790 m->creds.mask |= (SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID) & bus->creds_mask;
777d7a61 791 break;
5b12334d 792
777d7a61 793 case KDBUS_ITEM_CAPS:
5b12334d
LP
794 m->creds.capability = d->data;
795 m->creds.capability_size = l;
796 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;
777d7a61 797 break;
5b12334d 798
777d7a61 799 case KDBUS_ITEM_DST_NAME:
1307c3ff 800 destination = d->str;
777d7a61
LP
801 break;
802
49b832c5
LP
803 case KDBUS_ITEM_NAMES:
804 m->creds.well_known_names = d->str;
805 m->creds.well_known_names_size = l;
806 m->creds.mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES & bus->creds_mask;
807 break;
808
777d7a61
LP
809 case KDBUS_ITEM_FDS:
810 case KDBUS_ITEM_SECLABEL:
777d7a61
LP
811 break;
812
813 default:
77930f11 814 log_debug("Got unknown field from kernel %llu", d->type);
777d7a61 815 }
69aec65c 816 }
acb5a3cb 817
6629161f 818 r = bus_message_parse_fields(m);
1307c3ff
LP
819 if (r < 0)
820 goto fail;
6629161f 821
51038c03
LP
822 if (k->src_id == KDBUS_SRC_ID_KERNEL)
823 m->sender = "org.freedesktop.DBus";
824 else {
825 snprintf(m->sender_buffer, sizeof(m->sender_buffer), ":1.%llu", (unsigned long long) k->src_id);
49b832c5
LP
826 m->sender = m->creds.unique_name = m->sender_buffer;
827 m->creds.mask |= SD_BUS_CREDS_UNIQUE_NAME & bus->creds_mask;
51038c03
LP
828 }
829
830 if (!m->destination) {
831 if (destination)
832 m->destination = destination;
833 else if (k->dst_id != KDBUS_DST_ID_WELL_KNOWN_NAME &&
834 k->dst_id != KDBUS_DST_ID_BROADCAST) {
835 snprintf(m->destination_buffer, sizeof(m->destination_buffer), ":1.%llu", (unsigned long long) k->dst_id);
836 m->destination = m->destination_buffer;
837 }
838 }
839
6629161f
LP
840 /* We take possession of the kmsg struct now */
841 m->kdbus = k;
fd8d62d9 842 m->release_kdbus = true;
6629161f 843 m->free_fds = true;
6629161f
LP
844 fds = NULL;
845
7adc46fc 846 bus->rqueue[bus->rqueue_size++] = m;
7d22c717 847
6629161f 848 return 1;
1307c3ff
LP
849
850fail:
851 if (m) {
852 struct bus_body_part *part;
853 unsigned i;
854
855 /* Make sure the memfds are not freed twice */
856 MESSAGE_FOREACH_PART(part, i, m)
857 if (part->memfd >= 0)
858 part->memfd = -1;
859
860 sd_bus_message_unref(m);
861 }
862
863 return r;
6629161f
LP
864}
865
7d22c717 866int bus_kernel_read_message(sd_bus *bus) {
6629161f 867 struct kdbus_msg *k;
7d22c717 868 uint64_t off;
6629161f
LP
869 int r;
870
871 assert(bus);
7d22c717 872
7adc46fc 873 r = bus_rqueue_make_room(bus);
7d22c717
LP
874 if (r < 0)
875 return r;
6629161f 876
62b3e928 877 r = ioctl(bus->input_fd, KDBUS_CMD_MSG_RECV, &off);
fd8d62d9 878 if (r < 0) {
6629161f
LP
879 if (errno == EAGAIN)
880 return 0;
881
fd8d62d9 882 return -errno;
6629161f 883 }
62b3e928 884 k = (struct kdbus_msg *)((uint8_t *)bus->kdbus_buffer + off);
6629161f 885
777d7a61 886 if (k->payload_type == KDBUS_PAYLOAD_DBUS1)
7d22c717 887 r = bus_kernel_make_message(bus, k);
777d7a61 888 else if (k->payload_type == KDBUS_PAYLOAD_KERNEL)
7d22c717 889 r = bus_kernel_translate_message(bus, k);
777d7a61
LP
890 else
891 r = 0;
892
fd8d62d9
LP
893 if (r <= 0)
894 close_kdbus_msg(bus, k);
6629161f 895
51038c03 896 return r < 0 ? r : 1;
6629161f
LP
897}
898
bc7fd8cd
LP
899int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *size) {
900 struct memfd_cache *c;
45fbe937 901 int fd;
bc7fd8cd
LP
902
903 assert(address);
904 assert(size);
905
906 if (!bus || !bus->is_kernel)
907 return -ENOTSUP;
908
76b7742c 909 assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) >= 0);
45fbe937 910
bc7fd8cd 911 if (bus->n_memfd_cache <= 0) {
45fbe937
LP
912 int r;
913
76b7742c 914 assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
bc7fd8cd 915
9b05bc48
LP
916 r = ioctl(bus->input_fd, KDBUS_CMD_MEMFD_NEW, &fd);
917 if (r < 0)
bc7fd8cd
LP
918 return -errno;
919
920 *address = NULL;
921 *size = 0;
922 return fd;
923 }
924
bf30e48f 925 c = &bus->memfd_cache[--bus->n_memfd_cache];
bc7fd8cd
LP
926
927 assert(c->fd >= 0);
928 assert(c->size == 0 || c->address);
929
930 *address = c->address;
931 *size = c->size;
45fbe937
LP
932 fd = c->fd;
933
76b7742c 934 assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
bc7fd8cd 935
45fbe937
LP
936 return fd;
937}
938
939static void close_and_munmap(int fd, void *address, size_t size) {
940 if (size > 0)
76b7742c 941 assert_se(munmap(address, PAGE_ALIGN(size)) >= 0);
45fbe937
LP
942
943 close_nointr_nofail(fd);
bc7fd8cd
LP
944}
945
946void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t size) {
947 struct memfd_cache *c;
76b7742c 948 uint64_t max_sz = PAGE_ALIGN(MEMFD_CACHE_ITEM_SIZE_MAX);
bc7fd8cd
LP
949
950 assert(fd >= 0);
951 assert(size == 0 || address);
952
45fbe937
LP
953 if (!bus || !bus->is_kernel) {
954 close_and_munmap(fd, address, size);
955 return;
956 }
957
76b7742c 958 assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) >= 0);
bc7fd8cd 959
45fbe937 960 if (bus->n_memfd_cache >= ELEMENTSOF(bus->memfd_cache)) {
76b7742c 961 assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
bc7fd8cd 962
45fbe937 963 close_and_munmap(fd, address, size);
bc7fd8cd
LP
964 return;
965 }
966
967 c = &bus->memfd_cache[bus->n_memfd_cache++];
968 c->fd = fd;
969 c->address = address;
970
971 /* If overly long, let's return a bit to the OS */
76b7742c
LP
972 if (size > max_sz) {
973 assert_se(ioctl(fd, KDBUS_CMD_MEMFD_SIZE_SET, &max_sz) >= 0);
974 assert_se(munmap((uint8_t*) address + max_sz, PAGE_ALIGN(size - max_sz)) >= 0);
975 c->size = max_sz;
bc7fd8cd
LP
976 } else
977 c->size = size;
45fbe937 978
76b7742c 979 assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
bc7fd8cd
LP
980}
981
982void bus_kernel_flush_memfd(sd_bus *b) {
983 unsigned i;
984
985 assert(b);
986
76b7742c
LP
987 for (i = 0; i < b->n_memfd_cache; i++)
988 close_and_munmap(b->memfd_cache[i].fd, b->memfd_cache[i].address, b->memfd_cache[i].size);
bc7fd8cd 989}
0253ddcc 990
e3dd987c
LP
991int kdbus_translate_request_name_flags(uint64_t flags, uint64_t *kdbus_flags) {
992 uint64_t f = 0;
0253ddcc 993
e3dd987c 994 assert(kdbus_flags);
0253ddcc 995
e3dd987c
LP
996 if (flags & SD_BUS_NAME_ALLOW_REPLACEMENT)
997 f |= KDBUS_NAME_ALLOW_REPLACEMENT;
0253ddcc 998
e3dd987c
LP
999 if (flags & SD_BUS_NAME_REPLACE_EXISTING)
1000 f |= KDBUS_NAME_REPLACE_EXISTING;
0253ddcc 1001
e3dd987c
LP
1002 if (!(flags & SD_BUS_NAME_DO_NOT_QUEUE))
1003 f |= KDBUS_NAME_QUEUE;
0253ddcc 1004
e3dd987c
LP
1005 *kdbus_flags = f;
1006 return 0;
1007}
1008
1009int kdbus_translate_attach_flags(uint64_t mask, uint64_t *kdbus_mask) {
1010 uint64_t m = 0;
1011
1012 assert(kdbus_mask);
1013
1014 if (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_GID|SD_BUS_CREDS_PID|SD_BUS_CREDS_PID_STARTTIME|SD_BUS_CREDS_TID))
1015 m |= KDBUS_ATTACH_CREDS;
1016
1017 if (mask & (SD_BUS_CREDS_COMM|SD_BUS_CREDS_TID_COMM))
1018 m |= KDBUS_ATTACH_COMM;
1019
1020 if (mask & SD_BUS_CREDS_EXE)
1021 m |= KDBUS_ATTACH_EXE;
1022
1023 if (mask & SD_BUS_CREDS_CMDLINE)
1024 m |= KDBUS_ATTACH_CMDLINE;
1025
1026 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))
1027 m |= KDBUS_ATTACH_CGROUP;
1028
1029 if (mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS))
1030 m |= KDBUS_ATTACH_CAPS;
1031
1032 if (mask & SD_BUS_CREDS_SELINUX_CONTEXT)
1033 m |= KDBUS_ATTACH_SECLABEL;
0253ddcc 1034
e3dd987c
LP
1035 if (mask & (SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID))
1036 m |= KDBUS_ATTACH_AUDIT;
1037
49b832c5
LP
1038 if (mask & SD_BUS_CREDS_WELL_KNOWN_NAMES)
1039 m |= KDBUS_ATTACH_NAMES;
1040
e3dd987c 1041 *kdbus_mask = m;
0253ddcc
DM
1042 return 0;
1043}
e3dd987c 1044
9bd37b40 1045int bus_kernel_create_bus(const char *name, char **s) {
e3dd987c
LP
1046 struct kdbus_cmd_bus_make *make;
1047 struct kdbus_item *n;
1048 int fd;
1049
1050 assert(name);
1051 assert(s);
1052
1053 fd = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
1054 if (fd < 0)
1055 return -errno;
1056
1057 make = alloca0(ALIGN8(offsetof(struct kdbus_cmd_bus_make, items) +
1058 offsetof(struct kdbus_item, str) +
1059 DECIMAL_STR_MAX(uid_t) + 1 + strlen(name) + 1));
1060
1061 n = make->items;
1062 sprintf(n->str, "%lu-%s", (unsigned long) getuid(), name);
1063 n->size = offsetof(struct kdbus_item, str) + strlen(n->str) + 1;
1064 n->type = KDBUS_MAKE_NAME;
1065
1066 make->size = ALIGN8(offsetof(struct kdbus_cmd_bus_make, items) + n->size);
1067 make->flags = KDBUS_MAKE_POLICY_OPEN;
1068 make->bus_flags = 0;
1069 make->bloom_size = BLOOM_SIZE;
1070 assert_cc(BLOOM_SIZE % 8 == 0);
1071
1072 if (ioctl(fd, KDBUS_CMD_BUS_MAKE, make) < 0) {
1073 close_nointr_nofail(fd);
1074 return -errno;
1075 }
1076
f9638db8
LP
1077 /* The higher 32bit of the flags field are considered
1078 * 'incompatible flags'. Refuse them all for now. */
1079 if (make->flags > 0xFFFFFFFFULL) {
1080 close_nointr_nofail(fd);
1081 return -ENOTSUP;
1082 }
1083
e3dd987c
LP
1084 if (s) {
1085 char *p;
1086
1087 p = strjoin("/dev/kdbus/", n->str, "/bus", NULL);
1088 if (!p) {
1089 close_nointr_nofail(fd);
1090 return -ENOMEM;
1091 }
1092
1093 *s = p;
1094 }
1095
1096 return fd;
1097}
9bd37b40
LP
1098
1099int bus_kernel_create_namespace(const char *name, char **s) {
1100 struct kdbus_cmd_ns_make *make;
1101 struct kdbus_item *n;
1102 int fd;
1103
1104 assert(name);
1105 assert(s);
1106
1107 fd = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
1108 if (fd < 0)
1109 return -errno;
1110
1111 make = alloca0(ALIGN8(offsetof(struct kdbus_cmd_ns_make, items) +
1112 offsetof(struct kdbus_item, str) +
1113 strlen(name) + 1));
1114
1115 n = make->items;
1116 strcpy(n->str, name);
1117 n->size = offsetof(struct kdbus_item, str) + strlen(n->str) + 1;
1118 n->type = KDBUS_MAKE_NAME;
1119
1120 make->size = ALIGN8(offsetof(struct kdbus_cmd_ns_make, items) + n->size);
fd5b0b91 1121 make->flags = KDBUS_MAKE_POLICY_OPEN | KDBUS_MAKE_ACCESS_WORLD;
9bd37b40
LP
1122
1123 if (ioctl(fd, KDBUS_CMD_NS_MAKE, make) < 0) {
1124 close_nointr_nofail(fd);
1125 return -errno;
1126 }
1127
f9638db8
LP
1128 /* The higher 32bit of the flags field are considered
1129 * 'incompatible flags'. Refuse them all for now. */
1130 if (make->flags > 0xFFFFFFFFULL) {
1131 close_nointr_nofail(fd);
1132 return -ENOTSUP;
1133 }
1134
9bd37b40
LP
1135 if (s) {
1136 char *p;
1137
f8a2d1c9 1138 p = strappend("/dev/kdbus/ns/", name);
9bd37b40
LP
1139 if (!p) {
1140 close_nointr_nofail(fd);
1141 return -ENOMEM;
1142 }
1143
1144 *s = p;
1145 }
1146
1147 return fd;
1148}