]> git.ipfire.org Git - thirdparty/systemd.git/blame - 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
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
6629161f 359 b->is_kernel = true;
f08838da 360 b->bus_client = true;
62b3e928 361 b->can_fds = !!(hello.conn_flags & KDBUS_HELLO_ACCEPT_FD);
6629161f 362
c58dea19
DM
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
6629161f
LP
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
f08838da
LP
379 if (b->is_server)
380 return -EINVAL;
381
6629161f 382 b->input_fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC);
c320885c 383 if (b->input_fd < 0)
6629161f
LP
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
5b7d4c1c 398 r = bus_message_setup_kmsg(bus, m);
6629161f
LP
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
51038c03 406 return 1;
6629161f
LP
407}
408
fd8d62d9 409static void close_kdbus_msg(sd_bus *bus, struct kdbus_msg *k) {
62b3e928 410 uint64_t off;
febfd508 411 struct kdbus_item *d;
6629161f 412
fd8d62d9
LP
413 assert(bus);
414 assert(k);
415
62b3e928
KS
416 off = (uint8_t *)k - (uint8_t *)bus->kdbus_buffer;
417 ioctl(bus->input_fd, KDBUS_CMD_MSG_RELEASE, &off);
fd8d62d9 418
9eb34e82 419 KDBUS_PART_FOREACH(d, k, items) {
6629161f 420
ea1edece 421 if (d->type == KDBUS_ITEM_FDS)
1307c3ff 422 close_many(d->fds, (d->size - offsetof(struct kdbus_item, fds)) / sizeof(int));
ea1edece 423 else if (d->type == KDBUS_ITEM_PAYLOAD_MEMFD)
1307c3ff 424 close_nointr_nofail(d->memfd.fd);
6629161f
LP
425 }
426}
427
777d7a61
LP
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
87b522ae
DM
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
6629161f
LP
602static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k, sd_bus_message **ret) {
603 sd_bus_message *m = NULL;
febfd508 604 struct kdbus_item *d;
1307c3ff 605 unsigned n_fds = 0;
6629161f
LP
606 _cleanup_free_ int *fds = NULL;
607 struct bus_header *h = NULL;
608 size_t total, n_bytes = 0, idx = 0;
69aec65c 609 const char *destination = NULL, *seclabel = NULL;
6629161f
LP
610 int r;
611
612 assert(bus);
613 assert(k);
614 assert(ret);
777d7a61 615 assert(k->payload_type == KDBUS_PAYLOAD_DBUS1);
6629161f 616
9eb34e82 617 KDBUS_PART_FOREACH(d, k, items) {
6629161f
LP
618 size_t l;
619
febfd508 620 l = d->size - offsetof(struct kdbus_item, data);
6629161f 621
777d7a61 622 switch (d->type) {
6629161f 623
777d7a61 624 case KDBUS_ITEM_PAYLOAD_OFF:
6629161f 625 if (!h) {
62b3e928 626 h = (struct bus_header *)((uint8_t *)bus->kdbus_buffer + d->vec.offset);
c91cb83c
LP
627
628 if (!bus_header_is_complete(h, d->vec.size))
629 return -EBADMSG;
6629161f
LP
630 }
631
fd8d62d9 632 n_bytes += d->vec.size;
777d7a61 633 break;
6629161f 634
777d7a61 635 case KDBUS_ITEM_PAYLOAD_MEMFD:
1307c3ff
LP
636 if (!h)
637 return -EBADMSG;
638
639 n_bytes += d->memfd.size;
777d7a61 640 break;
1307c3ff 641
777d7a61 642 case KDBUS_ITEM_FDS: {
6629161f
LP
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;
9097fe29 652 memcpy(fds + n_fds, d->fds, sizeof(int) * j);
6629161f 653 n_fds += j;
777d7a61
LP
654 break;
655 }
f9be01f3 656
777d7a61 657 case KDBUS_ITEM_SECLABEL:
69aec65c 658 seclabel = d->str;
777d7a61
LP
659 break;
660 }
6629161f
LP
661 }
662
663 if (!h)
664 return -EBADMSG;
665
c91cb83c 666 r = bus_header_message_size(h, &total);
6629161f
LP
667 if (r < 0)
668 return r;
669
670 if (n_bytes != total)
671 return -EBADMSG;
672
df2d202e 673 r = bus_message_from_header(bus, h, sizeof(struct bus_header), fds, n_fds, NULL, seclabel, 0, &m);
6629161f
LP
674 if (r < 0)
675 return r;
676
9eb34e82 677 KDBUS_PART_FOREACH(d, k, items) {
6629161f
LP
678 size_t l;
679
febfd508 680 l = d->size - offsetof(struct kdbus_item, data);
6629161f 681
777d7a61
LP
682 switch (d->type) {
683
684 case KDBUS_ITEM_PAYLOAD_OFF: {
bc7fd8cd 685 size_t begin_body;
fd8d62d9 686
c91cb83c 687 begin_body = BUS_MESSAGE_BODY_BEGIN(m);
bc7fd8cd
LP
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) {
1307c3ff
LP
696 r = -ENOMEM;
697 goto fail;
bc7fd8cd
LP
698 }
699
62b3e928
KS
700 /* A -1 offset is NUL padding. */
701 part->is_zero = d->vec.offset == ~0ULL;
702
bc7fd8cd 703 if (idx >= begin_body) {
62b3e928
KS
704 if (!part->is_zero)
705 part->data = (uint8_t *)bus->kdbus_buffer + d->vec.offset;
bc7fd8cd
LP
706 part->size = d->vec.size;
707 } else {
62b3e928
KS
708 if (!part->is_zero)
709 part->data = (uint8_t *)bus->kdbus_buffer + d->vec.offset + (begin_body - idx);
bc7fd8cd
LP
710 part->size = d->vec.size - (begin_body - idx);
711 }
712
713 part->sealed = true;
714 }
fd8d62d9
LP
715
716 idx += d->vec.size;
777d7a61
LP
717 break;
718 }
719
720 case KDBUS_ITEM_PAYLOAD_MEMFD: {
1307c3ff
LP
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;
777d7a61
LP
739 break;
740 }
69aec65c 741
777d7a61 742 case KDBUS_ITEM_CREDS:
5b12334d
LP
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;
777d7a61 749 break;
5b12334d 750
777d7a61 751 case KDBUS_ITEM_TIMESTAMP:
69aec65c
LP
752 m->realtime = d->timestamp.realtime_ns / NSEC_PER_USEC;
753 m->monotonic = d->timestamp.monotonic_ns / NSEC_PER_USEC;
777d7a61 754 break;
5b12334d 755
777d7a61 756 case KDBUS_ITEM_PID_COMM:
5b12334d
LP
757 m->creds.comm = d->str;
758 m->creds.mask |= SD_BUS_CREDS_COMM & bus->creds_mask;
777d7a61 759 break;
5b12334d 760
777d7a61 761 case KDBUS_ITEM_TID_COMM:
5b12334d
LP
762 m->creds.tid_comm = d->str;
763 m->creds.mask |= SD_BUS_CREDS_TID_COMM & bus->creds_mask;
777d7a61 764 break;
5b12334d 765
777d7a61 766 case KDBUS_ITEM_EXE:
5b12334d
LP
767 m->creds.exe = d->str;
768 m->creds.mask |= SD_BUS_CREDS_EXE & bus->creds_mask;
777d7a61 769 break;
5b12334d 770
777d7a61 771 case KDBUS_ITEM_CMDLINE:
5b12334d
LP
772 m->creds.cmdline = d->str;
773 m->creds.cmdline_length = l;
774 m->creds.mask |= SD_BUS_CREDS_CMDLINE & bus->creds_mask;
777d7a61 775 break;
5b12334d 776
777d7a61 777 case KDBUS_ITEM_CGROUP:
5b12334d
LP
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;
777d7a61 780 break;
5b12334d 781
777d7a61 782 case KDBUS_ITEM_AUDIT:
5b12334d
LP
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;
777d7a61 786 break;
5b12334d 787
777d7a61 788 case KDBUS_ITEM_CAPS:
5b12334d
LP
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;
777d7a61 792 break;
5b12334d 793
777d7a61 794 case KDBUS_ITEM_DST_NAME:
1307c3ff 795 destination = d->str;
777d7a61
LP
796 break;
797
798 case KDBUS_ITEM_FDS:
799 case KDBUS_ITEM_SECLABEL:
800 case KDBUS_ITEM_NAMES:
801 break;
802
803 default:
77930f11 804 log_debug("Got unknown field from kernel %llu", d->type);
777d7a61 805 }
69aec65c 806 }
acb5a3cb 807
6629161f 808 r = bus_message_parse_fields(m);
1307c3ff
LP
809 if (r < 0)
810 goto fail;
6629161f 811
51038c03
LP
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
6629161f
LP
829 /* We take possession of the kmsg struct now */
830 m->kdbus = k;
fd8d62d9 831 m->release_kdbus = true;
6629161f
LP
832 m->free_fds = true;
833
834 fds = NULL;
835
836 *ret = m;
837 return 1;
1307c3ff
LP
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;
6629161f
LP
853}
854
855int bus_kernel_read_message(sd_bus *bus, sd_bus_message **m) {
62b3e928 856 uint64_t off;
6629161f 857 struct kdbus_msg *k;
6629161f
LP
858 int r;
859
860 assert(bus);
861 assert(m);
862
62b3e928 863 r = ioctl(bus->input_fd, KDBUS_CMD_MSG_RECV, &off);
fd8d62d9 864 if (r < 0) {
6629161f
LP
865 if (errno == EAGAIN)
866 return 0;
867
fd8d62d9 868 return -errno;
6629161f 869 }
62b3e928 870 k = (struct kdbus_msg *)((uint8_t *)bus->kdbus_buffer + off);
6629161f 871
777d7a61
LP
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
fd8d62d9
LP
879 if (r <= 0)
880 close_kdbus_msg(bus, k);
6629161f 881
51038c03 882 return r < 0 ? r : 1;
6629161f
LP
883}
884
885int bus_kernel_create(const char *name, char **s) {
5b7d4c1c 886 struct kdbus_cmd_bus_make *make;
efa3c0af 887 struct kdbus_item *n;
6629161f
LP
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);
a2cef833 900 make = alloca0(offsetof(struct kdbus_cmd_bus_make, items) +
9eb34e82
DM
901 KDBUS_PART_HEADER_SIZE + sizeof(uint64_t) +
902 KDBUS_PART_HEADER_SIZE + DECIMAL_STR_MAX(uid_t) + 1 + l + 1);
a2cef833 903
efa3c0af 904 n = make->items;
799e7ea8 905 n->type = KDBUS_MAKE_NAME;
a2cef833 906 sprintf(n->str, "%lu-%s", (unsigned long) getuid(), name);
9eb34e82 907 n->size = KDBUS_PART_HEADER_SIZE + strlen(n->str) + 1;
a2cef833 908
efa3c0af 909 make->size = offsetof(struct kdbus_cmd_bus_make, items) + n->size;
18cd014f 910 make->flags = KDBUS_MAKE_POLICY_OPEN;
5b7d4c1c 911 make->bus_flags = 0;
a56f19c4 912 make->bloom_size = BLOOM_SIZE;
a56f19c4 913 assert_cc(BLOOM_SIZE % 8 == 0);
5b7d4c1c 914
a2cef833 915 p = strjoin("/dev/kdbus/", n->str, "/bus", NULL);
6629161f
LP
916 if (!p)
917 return -ENOMEM;
918
5b7d4c1c 919 if (ioctl(fd, KDBUS_CMD_BUS_MAKE, make) < 0) {
6629161f
LP
920 close_nointr_nofail(fd);
921 free(p);
922 return -errno;
923 }
924
925 if (s)
926 *s = p;
927
928 return fd;
929}
bc7fd8cd
LP
930
931int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *size) {
932 struct memfd_cache *c;
45fbe937 933 int fd;
bc7fd8cd
LP
934
935 assert(address);
936 assert(size);
937
938 if (!bus || !bus->is_kernel)
939 return -ENOTSUP;
940
76b7742c 941 assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) >= 0);
45fbe937 942
bc7fd8cd 943 if (bus->n_memfd_cache <= 0) {
45fbe937
LP
944 int r;
945
76b7742c 946 assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
bc7fd8cd 947
9b05bc48
LP
948 r = ioctl(bus->input_fd, KDBUS_CMD_MEMFD_NEW, &fd);
949 if (r < 0)
bc7fd8cd
LP
950 return -errno;
951
952 *address = NULL;
953 *size = 0;
954 return fd;
955 }
956
bf30e48f 957 c = &bus->memfd_cache[--bus->n_memfd_cache];
bc7fd8cd
LP
958
959 assert(c->fd >= 0);
960 assert(c->size == 0 || c->address);
961
962 *address = c->address;
963 *size = c->size;
45fbe937
LP
964 fd = c->fd;
965
76b7742c 966 assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
bc7fd8cd 967
45fbe937
LP
968 return fd;
969}
970
971static void close_and_munmap(int fd, void *address, size_t size) {
972 if (size > 0)
76b7742c 973 assert_se(munmap(address, PAGE_ALIGN(size)) >= 0);
45fbe937
LP
974
975 close_nointr_nofail(fd);
bc7fd8cd
LP
976}
977
978void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t size) {
979 struct memfd_cache *c;
76b7742c 980 uint64_t max_sz = PAGE_ALIGN(MEMFD_CACHE_ITEM_SIZE_MAX);
bc7fd8cd
LP
981
982 assert(fd >= 0);
983 assert(size == 0 || address);
984
45fbe937
LP
985 if (!bus || !bus->is_kernel) {
986 close_and_munmap(fd, address, size);
987 return;
988 }
989
76b7742c 990 assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) >= 0);
bc7fd8cd 991
45fbe937 992 if (bus->n_memfd_cache >= ELEMENTSOF(bus->memfd_cache)) {
76b7742c 993 assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
bc7fd8cd 994
45fbe937 995 close_and_munmap(fd, address, size);
bc7fd8cd
LP
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 */
76b7742c
LP
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;
bc7fd8cd
LP
1008 } else
1009 c->size = size;
45fbe937 1010
76b7742c 1011 assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
bc7fd8cd
LP
1012}
1013
1014void bus_kernel_flush_memfd(sd_bus *b) {
1015 unsigned i;
1016
1017 assert(b);
1018
76b7742c
LP
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);
bc7fd8cd 1021}
0253ddcc 1022
98f17eda 1023int kdbus_translate_request_name_flags(uint64_t sd_bus_flags, uint64_t *kdbus_flags) {
0253ddcc
DM
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}