]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-bus/bus-kernel.c
bus: add new sd_bus_creds object to encapsulate process credentials
[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"
6629161f 36
c7819669 37int bus_kernel_parse_unique_name(const char *s, uint64_t *id) {
6629161f
LP
38 int r;
39
40 assert(s);
41 assert(id);
42
43 if (!startswith(s, ":1."))
44 return 0;
45
46 r = safe_atou64(s + 3, id);
47 if (r < 0)
48 return r;
49
50 return 1;
51}
52
febfd508 53static void append_payload_vec(struct kdbus_item **d, const void *p, size_t sz) {
6629161f 54 assert(d);
6629161f
LP
55 assert(sz > 0);
56
e86b80b8
LP
57 *d = ALIGN8_PTR(*d);
58
66b26c5c
LP
59 /* Note that p can be NULL, which encodes a region full of
60 * zeroes, which is useful to optimize certain padding
61 * conditions */
62
febfd508 63 (*d)->size = offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec);
6629161f 64 (*d)->type = KDBUS_MSG_PAYLOAD_VEC;
a392d361 65 (*d)->vec.address = PTR_TO_UINT64(p);
6629161f
LP
66 (*d)->vec.size = sz;
67
febfd508 68 *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
6629161f
LP
69}
70
a392d361
LP
71static void append_payload_memfd(struct kdbus_item **d, int memfd, size_t sz) {
72 assert(d);
73 assert(memfd >= 0);
74 assert(sz > 0);
75
76 *d = ALIGN8_PTR(*d);
77 (*d)->size = offsetof(struct kdbus_item, memfd) + sizeof(struct kdbus_memfd);
78 (*d)->type = KDBUS_MSG_PAYLOAD_MEMFD;
79 (*d)->memfd.fd = memfd;
80 (*d)->memfd.size = sz;
81
82 *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
83}
84
febfd508 85static void append_destination(struct kdbus_item **d, const char *s, size_t length) {
6629161f 86 assert(d);
b5baa8fe 87 assert(s);
6629161f 88
e86b80b8
LP
89 *d = ALIGN8_PTR(*d);
90
febfd508 91 (*d)->size = offsetof(struct kdbus_item, str) + length + 1;
6629161f 92 (*d)->type = KDBUS_MSG_DST_NAME;
51038c03 93 memcpy((*d)->str, s, length + 1);
6629161f 94
febfd508 95 *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
6629161f
LP
96}
97
febfd508 98static void* append_bloom(struct kdbus_item **d, size_t length) {
a56f19c4
LP
99 void *r;
100
b5baa8fe 101 assert(d);
b5baa8fe
LP
102
103 *d = ALIGN8_PTR(*d);
104
febfd508 105 (*d)->size = offsetof(struct kdbus_item, data) + length;
b5baa8fe 106 (*d)->type = KDBUS_MSG_BLOOM;
a56f19c4 107 r = (*d)->data;
b5baa8fe 108
febfd508 109 *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
a56f19c4
LP
110
111 return r;
112}
113
febfd508 114static void append_fds(struct kdbus_item **d, const int fds[], unsigned n_fds) {
9097fe29
LP
115 assert(d);
116 assert(fds);
117 assert(n_fds > 0);
118
119 *d = ALIGN8_PTR(*d);
febfd508 120 (*d)->size = offsetof(struct kdbus_item, fds) + sizeof(int) * n_fds;
fd8d62d9 121 (*d)->type = KDBUS_MSG_FDS;
9097fe29
LP
122 memcpy((*d)->fds, fds, sizeof(int) * n_fds);
123
febfd508 124 *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
9097fe29
LP
125}
126
a56f19c4
LP
127static int bus_message_setup_bloom(sd_bus_message *m, void *bloom) {
128 unsigned i;
129 int r;
130
131 assert(m);
132 assert(bloom);
133
134 memset(bloom, 0, BLOOM_SIZE);
135
136 bloom_add_pair(bloom, "message-type", bus_message_type_to_string(m->header->type));
137
138 if (m->interface)
139 bloom_add_pair(bloom, "interface", m->interface);
140 if (m->member)
141 bloom_add_pair(bloom, "member", m->member);
142 if (m->path) {
143 bloom_add_pair(bloom, "path", m->path);
f11e11e3 144 bloom_add_pair(bloom, "path-slash-prefix", m->path);
a56f19c4
LP
145 bloom_add_prefixes(bloom, "path-slash-prefix", m->path, '/');
146 }
147
148 r = sd_bus_message_rewind(m, true);
149 if (r < 0)
150 return r;
151
152 for (i = 0; i < 64; i++) {
153 char type;
154 const char *t;
155 char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
156 char *e;
157
158 r = sd_bus_message_peek_type(m, &type, NULL);
159 if (r < 0)
160 return r;
161
162 if (type != SD_BUS_TYPE_STRING &&
163 type != SD_BUS_TYPE_OBJECT_PATH &&
164 type != SD_BUS_TYPE_SIGNATURE)
165 break;
166
167 r = sd_bus_message_read_basic(m, type, &t);
168 if (r < 0)
169 return r;
170
171 e = stpcpy(buf, "arg");
172 if (i < 10)
173 *(e++) = '0' + i;
174 else {
175 *(e++) = '0' + (i / 10);
176 *(e++) = '0' + (i % 10);
177 }
178
179 *e = 0;
180 bloom_add_pair(bloom, buf, t);
181
182 strcpy(e, "-dot-prefix");
183 bloom_add_prefixes(bloom, buf, t, '.');
184 strcpy(e, "-slash-prefix");
185 bloom_add_prefixes(bloom, buf, t, '/');
186 }
187
188 return 0;
b5baa8fe
LP
189}
190
5b7d4c1c 191static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) {
9b29bb68 192 struct bus_body_part *part;
febfd508 193 struct kdbus_item *d;
6629161f
LP
194 bool well_known;
195 uint64_t unique;
196 size_t sz, dl;
9b29bb68 197 unsigned i;
6629161f
LP
198 int r;
199
5b7d4c1c 200 assert(b);
6629161f
LP
201 assert(m);
202 assert(m->sealed);
e9a967f9
LP
203
204 if (m->kdbus)
205 return 0;
6629161f
LP
206
207 if (m->destination) {
c7819669 208 r = bus_kernel_parse_unique_name(m->destination, &unique);
6629161f
LP
209 if (r < 0)
210 return r;
211
212 well_known = r == 0;
213 } else
214 well_known = false;
215
b1454bf0 216 sz = offsetof(struct kdbus_msg, items);
6629161f 217
a392d361
LP
218 assert_cc(ALIGN8(offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec)) ==
219 ALIGN8(offsetof(struct kdbus_item, memfd) + sizeof(struct kdbus_memfd)));
220
69aec65c 221 /* Add in fixed header, fields header and payload */
c91cb83c 222 sz += (1 + m->n_body_parts) *
bc7fd8cd 223 ALIGN8(offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec));
6629161f 224
69aec65c 225 /* Add space for bloom filter */
febfd508 226 sz += ALIGN8(offsetof(struct kdbus_item, data) + BLOOM_SIZE);
b5baa8fe 227
6629161f
LP
228 /* Add in well-known destination header */
229 if (well_known) {
230 dl = strlen(m->destination);
febfd508 231 sz += ALIGN8(offsetof(struct kdbus_item, str) + dl + 1);
6629161f
LP
232 }
233
9097fe29
LP
234 /* Add space for unix fds */
235 if (m->n_fds > 0)
febfd508 236 sz += ALIGN8(offsetof(struct kdbus_item, fds) + sizeof(int)*m->n_fds);
9097fe29 237
c556fe79 238 m->kdbus = memalign(8, sz);
66b26c5c
LP
239 if (!m->kdbus) {
240 r = -ENOMEM;
241 goto fail;
242 }
6629161f 243
66b26c5c 244 m->free_kdbus = true;
d9115e18
LP
245 memset(m->kdbus, 0, sz);
246
6629161f
LP
247 m->kdbus->flags =
248 ((m->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED) ? 0 : KDBUS_MSG_FLAGS_EXPECT_REPLY) |
249 ((m->header->flags & SD_BUS_MESSAGE_NO_AUTO_START) ? KDBUS_MSG_FLAGS_NO_AUTO_START : 0);
250 m->kdbus->dst_id =
251 well_known ? 0 :
b5baa8fe 252 m->destination ? unique : KDBUS_DST_ID_BROADCAST;
6629161f
LP
253 m->kdbus->payload_type = KDBUS_PAYLOAD_DBUS1;
254 m->kdbus->cookie = m->header->serial;
255
256 m->kdbus->timeout_ns = m->timeout * NSEC_PER_USEC;
257
b1454bf0 258 d = m->kdbus->items;
6629161f
LP
259
260 if (well_known)
261 append_destination(&d, m->destination, dl);
262
c91cb83c 263 append_payload_vec(&d, m->header, BUS_MESSAGE_BODY_BEGIN(m));
a392d361
LP
264
265 MESSAGE_FOREACH_PART(part, i, m) {
266 if (part->is_zero) {
66b26c5c
LP
267 /* If this is padding then simply send a
268 * vector with a NULL data pointer which the
269 * kernel will just pass through. This is the
270 * most efficient way to encode zeroes */
271
a392d361
LP
272 append_payload_vec(&d, NULL, part->size);
273 continue;
274 }
275
66b26c5c
LP
276 if (part->memfd >= 0 && part->sealed && m->destination) {
277 /* Try to send a memfd, if the part is
278 * sealed and this is not a broadcast. Since we can only */
a392d361 279
66b26c5c
LP
280 append_payload_memfd(&d, part->memfd, part->size);
281 continue;
a392d361
LP
282 }
283
66b26c5c
LP
284 /* Otherwise let's send a vector to the actual data,
285 * for that we need to map it first. */
286 r = bus_body_part_map(part);
287 if (r < 0)
288 goto fail;
a392d361 289
bc7fd8cd 290 append_payload_vec(&d, part->data, part->size);
a392d361 291 }
6629161f 292
5b7d4c1c
LP
293 if (m->kdbus->dst_id == KDBUS_DST_ID_BROADCAST) {
294 void *p;
295
a56f19c4
LP
296 p = append_bloom(&d, BLOOM_SIZE);
297 r = bus_message_setup_bloom(m, p);
a392d361
LP
298 if (r < 0)
299 goto fail;
5b7d4c1c 300 }
b5baa8fe 301
9097fe29
LP
302 if (m->n_fds > 0)
303 append_fds(&d, m->fds, m->n_fds);
304
e9a967f9 305 m->kdbus->size = (uint8_t*) d - (uint8_t*) m->kdbus;
6629161f
LP
306 assert(m->kdbus->size <= sz);
307
308 return 0;
a392d361
LP
309
310fail:
66b26c5c 311 m->poisoned = true;
a392d361 312 return r;
6629161f
LP
313}
314
315int bus_kernel_take_fd(sd_bus *b) {
62b3e928 316 struct kdbus_cmd_hello hello;
6629161f
LP
317 int r;
318
319 assert(b);
320
f08838da
LP
321 if (b->is_server)
322 return -EINVAL;
323
8f155917
LP
324 b->use_memfd = 1;
325
62b3e928
KS
326 zero(hello);
327 hello.size = sizeof(hello);
328 hello.conn_flags = b->hello_flags;
329 hello.pool_size = KDBUS_POOL_SIZE;
330
331 r = ioctl(b->input_fd, KDBUS_CMD_HELLO, &hello);
332 if (r < 0)
333 return -errno;
334
fd8d62d9 335 if (!b->kdbus_buffer) {
62b3e928 336 b->kdbus_buffer = mmap(NULL, KDBUS_POOL_SIZE, PROT_READ, MAP_SHARED, b->input_fd, 0);
fd8d62d9
LP
337 if (b->kdbus_buffer == MAP_FAILED) {
338 b->kdbus_buffer = NULL;
339 return -errno;
340 }
341 }
342
5b7d4c1c
LP
343 /* The higher 32bit of both flags fields are considered
344 * 'incompatible flags'. Refuse them all for now. */
62b3e928
KS
345 if (hello.bus_flags > 0xFFFFFFFFULL ||
346 hello.conn_flags > 0xFFFFFFFFULL)
5b7d4c1c
LP
347 return -ENOTSUP;
348
62b3e928 349 if (hello.bloom_size != BLOOM_SIZE)
a56f19c4
LP
350 return -ENOTSUP;
351
62b3e928 352 if (asprintf(&b->unique_name, ":1.%llu", (unsigned long long) hello.id) < 0)
de297575
LP
353 return -ENOMEM;
354
6629161f 355 b->is_kernel = true;
f08838da 356 b->bus_client = true;
62b3e928 357 b->can_fds = !!(hello.conn_flags & KDBUS_HELLO_ACCEPT_FD);
6629161f
LP
358
359 r = bus_start_running(b);
360 if (r < 0)
361 return r;
362
363 return 1;
364}
365
366int bus_kernel_connect(sd_bus *b) {
367 assert(b);
368 assert(b->input_fd < 0);
369 assert(b->output_fd < 0);
370 assert(b->kernel);
371
f08838da
LP
372 if (b->is_server)
373 return -EINVAL;
374
6629161f 375 b->input_fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC);
c320885c 376 if (b->input_fd < 0)
6629161f
LP
377 return -errno;
378
379 b->output_fd = b->input_fd;
380
381 return bus_kernel_take_fd(b);
382}
383
384int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m) {
385 int r;
386
387 assert(bus);
388 assert(m);
389 assert(bus->state == BUS_RUNNING);
390
5b7d4c1c 391 r = bus_message_setup_kmsg(bus, m);
6629161f
LP
392 if (r < 0)
393 return r;
394
395 r = ioctl(bus->output_fd, KDBUS_CMD_MSG_SEND, m->kdbus);
396 if (r < 0)
397 return errno == EAGAIN ? 0 : -errno;
398
51038c03 399 return 1;
6629161f
LP
400}
401
fd8d62d9 402static void close_kdbus_msg(sd_bus *bus, struct kdbus_msg *k) {
62b3e928 403 uint64_t off;
febfd508 404 struct kdbus_item *d;
6629161f 405
fd8d62d9
LP
406 assert(bus);
407 assert(k);
408
62b3e928
KS
409 off = (uint8_t *)k - (uint8_t *)bus->kdbus_buffer;
410 ioctl(bus->input_fd, KDBUS_CMD_MSG_RELEASE, &off);
fd8d62d9 411
6133cee2 412 KDBUS_ITEM_FOREACH(d, k) {
6629161f 413
1307c3ff
LP
414 if (d->type == KDBUS_MSG_FDS)
415 close_many(d->fds, (d->size - offsetof(struct kdbus_item, fds)) / sizeof(int));
416 else if (d->type == KDBUS_MSG_PAYLOAD_MEMFD)
417 close_nointr_nofail(d->memfd.fd);
6629161f
LP
418 }
419}
420
421static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k, sd_bus_message **ret) {
422 sd_bus_message *m = NULL;
febfd508 423 struct kdbus_item *d;
1307c3ff 424 unsigned n_fds = 0;
6629161f
LP
425 _cleanup_free_ int *fds = NULL;
426 struct bus_header *h = NULL;
427 size_t total, n_bytes = 0, idx = 0;
69aec65c 428 const char *destination = NULL, *seclabel = NULL;
6629161f
LP
429 int r;
430
431 assert(bus);
432 assert(k);
433 assert(ret);
434
435 if (k->payload_type != KDBUS_PAYLOAD_DBUS1)
436 return 0;
437
6133cee2 438 KDBUS_ITEM_FOREACH(d, k) {
6629161f
LP
439 size_t l;
440
febfd508 441 l = d->size - offsetof(struct kdbus_item, data);
6629161f 442
62b3e928 443 if (d->type == KDBUS_MSG_PAYLOAD_OFF) {
6629161f
LP
444
445 if (!h) {
62b3e928 446 h = (struct bus_header *)((uint8_t *)bus->kdbus_buffer + d->vec.offset);
c91cb83c
LP
447
448 if (!bus_header_is_complete(h, d->vec.size))
449 return -EBADMSG;
6629161f
LP
450 }
451
fd8d62d9 452 n_bytes += d->vec.size;
6629161f 453
1307c3ff
LP
454 } else if (d->type == KDBUS_MSG_PAYLOAD_MEMFD) {
455
456 if (!h)
457 return -EBADMSG;
458
459 n_bytes += d->memfd.size;
460
fd8d62d9 461 } else if (d->type == KDBUS_MSG_FDS) {
6629161f
LP
462 int *f;
463 unsigned j;
464
465 j = l / sizeof(int);
466 f = realloc(fds, sizeof(int) * (n_fds + j));
467 if (!f)
468 return -ENOMEM;
469
470 fds = f;
9097fe29 471 memcpy(fds + n_fds, d->fds, sizeof(int) * j);
6629161f 472 n_fds += j;
f9be01f3 473
1307c3ff 474 } else if (d->type == KDBUS_MSG_SRC_SECLABEL)
69aec65c 475 seclabel = d->str;
6629161f
LP
476 }
477
478 if (!h)
479 return -EBADMSG;
480
c91cb83c 481 r = bus_header_message_size(h, &total);
6629161f
LP
482 if (r < 0)
483 return r;
484
485 if (n_bytes != total)
486 return -EBADMSG;
487
df2d202e 488 r = bus_message_from_header(bus, h, sizeof(struct bus_header), fds, n_fds, NULL, seclabel, 0, &m);
6629161f
LP
489 if (r < 0)
490 return r;
491
6133cee2 492 KDBUS_ITEM_FOREACH(d, k) {
6629161f
LP
493 size_t l;
494
febfd508 495 l = d->size - offsetof(struct kdbus_item, data);
6629161f 496
62b3e928 497 if (d->type == KDBUS_MSG_PAYLOAD_OFF) {
bc7fd8cd 498 size_t begin_body;
fd8d62d9 499
c91cb83c 500 begin_body = BUS_MESSAGE_BODY_BEGIN(m);
bc7fd8cd
LP
501
502 if (idx + d->vec.size > begin_body) {
503 struct bus_body_part *part;
504
505 /* Contains body material */
506
507 part = message_append_part(m);
508 if (!part) {
1307c3ff
LP
509 r = -ENOMEM;
510 goto fail;
bc7fd8cd
LP
511 }
512
62b3e928
KS
513 /* A -1 offset is NUL padding. */
514 part->is_zero = d->vec.offset == ~0ULL;
515
bc7fd8cd 516 if (idx >= begin_body) {
62b3e928
KS
517 if (!part->is_zero)
518 part->data = (uint8_t *)bus->kdbus_buffer + d->vec.offset;
bc7fd8cd
LP
519 part->size = d->vec.size;
520 } else {
62b3e928
KS
521 if (!part->is_zero)
522 part->data = (uint8_t *)bus->kdbus_buffer + d->vec.offset + (begin_body - idx);
bc7fd8cd
LP
523 part->size = d->vec.size - (begin_body - idx);
524 }
525
526 part->sealed = true;
527 }
fd8d62d9
LP
528
529 idx += d->vec.size;
1307c3ff
LP
530 } else if (d->type == KDBUS_MSG_PAYLOAD_MEMFD) {
531 struct bus_body_part *part;
532
533 if (idx < BUS_MESSAGE_BODY_BEGIN(m)) {
534 r = -EBADMSG;
535 goto fail;
536 }
537
538 part = message_append_part(m);
539 if (!part) {
540 r = -ENOMEM;
541 goto fail;
542 }
543
544 part->memfd = d->memfd.fd;
545 part->size = d->memfd.size;
546 part->sealed = true;
547
548 idx += d->memfd.size;
69aec65c 549
69aec65c 550 } else if (d->type == KDBUS_MSG_SRC_CREDS) {
5b12334d
LP
551 m->creds.pid_starttime = d->creds.starttime / NSEC_PER_USEC;
552 m->creds.uid = d->creds.uid;
553 m->creds.gid = d->creds.gid;
554 m->creds.pid = d->creds.pid;
555 m->creds.tid = d->creds.tid;
556 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;
557
69aec65c
LP
558 } else if (d->type == KDBUS_MSG_TIMESTAMP) {
559 m->realtime = d->timestamp.realtime_ns / NSEC_PER_USEC;
560 m->monotonic = d->timestamp.monotonic_ns / NSEC_PER_USEC;
5b12334d
LP
561
562 } else if (d->type == KDBUS_MSG_SRC_PID_COMM) {
563 m->creds.comm = d->str;
564 m->creds.mask |= SD_BUS_CREDS_COMM & bus->creds_mask;
565
566 } else if (d->type == KDBUS_MSG_SRC_TID_COMM) {
567 m->creds.tid_comm = d->str;
568 m->creds.mask |= SD_BUS_CREDS_TID_COMM & bus->creds_mask;
569
570 } else if (d->type == KDBUS_MSG_SRC_EXE) {
571 m->creds.exe = d->str;
572 m->creds.mask |= SD_BUS_CREDS_EXE & bus->creds_mask;
573
574 } else if (d->type == KDBUS_MSG_SRC_CMDLINE) {
575 m->creds.cmdline = d->str;
576 m->creds.cmdline_length = l;
577 m->creds.mask |= SD_BUS_CREDS_CMDLINE & bus->creds_mask;
578
579 } else if (d->type == KDBUS_MSG_SRC_CGROUP) {
580 m->creds.cgroup = d->str;
581 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;
582
583 } else if (d->type == KDBUS_MSG_SRC_AUDIT) {
584 m->creds.audit_session_id = d->audit.sessionid;
585 m->creds.audit_login_uid = d->audit.loginuid;
586 m->creds.mask |= (SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID) & bus->creds_mask;
587
588 } else if (d->type == KDBUS_MSG_SRC_CAPS) {
589 m->creds.capability = d->data;
590 m->creds.capability_size = l;
591 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;
592
1307c3ff
LP
593 } else if (d->type == KDBUS_MSG_DST_NAME)
594 destination = d->str;
595 else if (d->type != KDBUS_MSG_FDS &&
fd8d62d9 596 d->type != KDBUS_MSG_SRC_SECLABEL)
77930f11 597 log_debug("Got unknown field from kernel %llu", d->type);
69aec65c 598 }
acb5a3cb 599
6629161f 600 r = bus_message_parse_fields(m);
1307c3ff
LP
601 if (r < 0)
602 goto fail;
6629161f 603
51038c03
LP
604 if (k->src_id == KDBUS_SRC_ID_KERNEL)
605 m->sender = "org.freedesktop.DBus";
606 else {
607 snprintf(m->sender_buffer, sizeof(m->sender_buffer), ":1.%llu", (unsigned long long) k->src_id);
608 m->sender = m->sender_buffer;
609 }
610
611 if (!m->destination) {
612 if (destination)
613 m->destination = destination;
614 else if (k->dst_id != KDBUS_DST_ID_WELL_KNOWN_NAME &&
615 k->dst_id != KDBUS_DST_ID_BROADCAST) {
616 snprintf(m->destination_buffer, sizeof(m->destination_buffer), ":1.%llu", (unsigned long long) k->dst_id);
617 m->destination = m->destination_buffer;
618 }
619 }
620
6629161f
LP
621 /* We take possession of the kmsg struct now */
622 m->kdbus = k;
fd8d62d9 623 m->release_kdbus = true;
6629161f
LP
624 m->free_fds = true;
625
626 fds = NULL;
627
628 *ret = m;
629 return 1;
1307c3ff
LP
630
631fail:
632 if (m) {
633 struct bus_body_part *part;
634 unsigned i;
635
636 /* Make sure the memfds are not freed twice */
637 MESSAGE_FOREACH_PART(part, i, m)
638 if (part->memfd >= 0)
639 part->memfd = -1;
640
641 sd_bus_message_unref(m);
642 }
643
644 return r;
6629161f
LP
645}
646
647int bus_kernel_read_message(sd_bus *bus, sd_bus_message **m) {
62b3e928 648 uint64_t off;
6629161f 649 struct kdbus_msg *k;
6629161f
LP
650 int r;
651
652 assert(bus);
653 assert(m);
654
62b3e928 655 r = ioctl(bus->input_fd, KDBUS_CMD_MSG_RECV, &off);
fd8d62d9 656 if (r < 0) {
6629161f
LP
657 if (errno == EAGAIN)
658 return 0;
659
fd8d62d9 660 return -errno;
6629161f 661 }
62b3e928 662 k = (struct kdbus_msg *)((uint8_t *)bus->kdbus_buffer + off);
6629161f
LP
663
664 r = bus_kernel_make_message(bus, k, m);
fd8d62d9
LP
665 if (r <= 0)
666 close_kdbus_msg(bus, k);
6629161f 667
51038c03 668 return r < 0 ? r : 1;
6629161f
LP
669}
670
671int bus_kernel_create(const char *name, char **s) {
5b7d4c1c 672 struct kdbus_cmd_bus_make *make;
efa3c0af 673 struct kdbus_item *n;
6629161f
LP
674 size_t l;
675 int fd;
676 char *p;
677
678 assert(name);
679 assert(s);
680
681 fd = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
682 if (fd < 0)
683 return -errno;
684
685 l = strlen(name);
a2cef833 686 make = alloca0(offsetof(struct kdbus_cmd_bus_make, items) +
febfd508
KS
687 KDBUS_ITEM_HEADER_SIZE + sizeof(uint64_t) +
688 KDBUS_ITEM_HEADER_SIZE + DECIMAL_STR_MAX(uid_t) + 1 + l + 1);
a2cef833 689
efa3c0af 690 n = make->items;
799e7ea8 691 n->type = KDBUS_MAKE_NAME;
a2cef833 692 sprintf(n->str, "%lu-%s", (unsigned long) getuid(), name);
febfd508 693 n->size = KDBUS_ITEM_HEADER_SIZE + strlen(n->str) + 1;
a2cef833 694
efa3c0af 695 make->size = offsetof(struct kdbus_cmd_bus_make, items) + n->size;
18cd014f 696 make->flags = KDBUS_MAKE_POLICY_OPEN;
5b7d4c1c 697 make->bus_flags = 0;
a56f19c4 698 make->bloom_size = BLOOM_SIZE;
a56f19c4 699 assert_cc(BLOOM_SIZE % 8 == 0);
5b7d4c1c 700
a2cef833 701 p = strjoin("/dev/kdbus/", n->str, "/bus", NULL);
6629161f
LP
702 if (!p)
703 return -ENOMEM;
704
5b7d4c1c 705 if (ioctl(fd, KDBUS_CMD_BUS_MAKE, make) < 0) {
6629161f
LP
706 close_nointr_nofail(fd);
707 free(p);
708 return -errno;
709 }
710
711 if (s)
712 *s = p;
713
714 return fd;
715}
bc7fd8cd
LP
716
717int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *size) {
718 struct memfd_cache *c;
45fbe937 719 int fd;
bc7fd8cd
LP
720
721 assert(address);
722 assert(size);
723
724 if (!bus || !bus->is_kernel)
725 return -ENOTSUP;
726
76b7742c 727 assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) >= 0);
45fbe937 728
bc7fd8cd 729 if (bus->n_memfd_cache <= 0) {
45fbe937
LP
730 int r;
731
76b7742c 732 assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
bc7fd8cd 733
9b05bc48
LP
734 r = ioctl(bus->input_fd, KDBUS_CMD_MEMFD_NEW, &fd);
735 if (r < 0)
bc7fd8cd
LP
736 return -errno;
737
738 *address = NULL;
739 *size = 0;
740 return fd;
741 }
742
bf30e48f 743 c = &bus->memfd_cache[--bus->n_memfd_cache];
bc7fd8cd
LP
744
745 assert(c->fd >= 0);
746 assert(c->size == 0 || c->address);
747
748 *address = c->address;
749 *size = c->size;
45fbe937
LP
750 fd = c->fd;
751
76b7742c 752 assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
bc7fd8cd 753
45fbe937
LP
754 return fd;
755}
756
757static void close_and_munmap(int fd, void *address, size_t size) {
758 if (size > 0)
76b7742c 759 assert_se(munmap(address, PAGE_ALIGN(size)) >= 0);
45fbe937
LP
760
761 close_nointr_nofail(fd);
bc7fd8cd
LP
762}
763
764void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t size) {
765 struct memfd_cache *c;
76b7742c 766 uint64_t max_sz = PAGE_ALIGN(MEMFD_CACHE_ITEM_SIZE_MAX);
bc7fd8cd
LP
767
768 assert(fd >= 0);
769 assert(size == 0 || address);
770
45fbe937
LP
771 if (!bus || !bus->is_kernel) {
772 close_and_munmap(fd, address, size);
773 return;
774 }
775
76b7742c 776 assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) >= 0);
bc7fd8cd 777
45fbe937 778 if (bus->n_memfd_cache >= ELEMENTSOF(bus->memfd_cache)) {
76b7742c 779 assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
bc7fd8cd 780
45fbe937 781 close_and_munmap(fd, address, size);
bc7fd8cd
LP
782 return;
783 }
784
785 c = &bus->memfd_cache[bus->n_memfd_cache++];
786 c->fd = fd;
787 c->address = address;
788
789 /* If overly long, let's return a bit to the OS */
76b7742c
LP
790 if (size > max_sz) {
791 assert_se(ioctl(fd, KDBUS_CMD_MEMFD_SIZE_SET, &max_sz) >= 0);
792 assert_se(munmap((uint8_t*) address + max_sz, PAGE_ALIGN(size - max_sz)) >= 0);
793 c->size = max_sz;
bc7fd8cd
LP
794 } else
795 c->size = size;
45fbe937 796
76b7742c 797 assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
bc7fd8cd
LP
798}
799
800void bus_kernel_flush_memfd(sd_bus *b) {
801 unsigned i;
802
803 assert(b);
804
76b7742c
LP
805 for (i = 0; i < b->n_memfd_cache; i++)
806 close_and_munmap(b->memfd_cache[i].fd, b->memfd_cache[i].address, b->memfd_cache[i].size);
bc7fd8cd 807}