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