]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-bus/bus-kernel.c
bf8de04ab6e326e13ae48ddbf92a4dc71e3080ad
[thirdparty/systemd.git] / src / libsystemd-bus / bus-kernel.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2013 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #ifdef HAVE_VALGRIND_MEMCHECK_H
23 #include <valgrind/memcheck.h>
24 #endif
25
26 #include <fcntl.h>
27 #include <malloc.h>
28 #include <sys/mman.h>
29
30 #include "util.h"
31
32 #include "bus-internal.h"
33 #include "bus-message.h"
34 #include "bus-kernel.h"
35 #include "bus-bloom.h"
36
37 int bus_kernel_parse_unique_name(const char *s, uint64_t *id) {
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
53 static void append_payload_vec(struct kdbus_item **d, const void *p, size_t sz) {
54 assert(d);
55 assert(sz > 0);
56
57 *d = ALIGN8_PTR(*d);
58
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
63 (*d)->size = offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec);
64 (*d)->type = KDBUS_MSG_PAYLOAD_VEC;
65 (*d)->vec.address = PTR_TO_UINT64(p);
66 (*d)->vec.size = sz;
67
68 *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
69 }
70
71 static 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
85 static void append_destination(struct kdbus_item **d, const char *s, size_t length) {
86 assert(d);
87 assert(s);
88
89 *d = ALIGN8_PTR(*d);
90
91 (*d)->size = offsetof(struct kdbus_item, str) + length + 1;
92 (*d)->type = KDBUS_MSG_DST_NAME;
93 memcpy((*d)->str, s, length + 1);
94
95 *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
96 }
97
98 static void* append_bloom(struct kdbus_item **d, size_t length) {
99 void *r;
100
101 assert(d);
102
103 *d = ALIGN8_PTR(*d);
104
105 (*d)->size = offsetof(struct kdbus_item, data) + length;
106 (*d)->type = KDBUS_MSG_BLOOM;
107 r = (*d)->data;
108
109 *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
110
111 return r;
112 }
113
114 static void append_fds(struct kdbus_item **d, const int fds[], unsigned n_fds) {
115 assert(d);
116 assert(fds);
117 assert(n_fds > 0);
118
119 *d = ALIGN8_PTR(*d);
120 (*d)->size = offsetof(struct kdbus_item, fds) + sizeof(int) * n_fds;
121 (*d)->type = KDBUS_MSG_FDS;
122 memcpy((*d)->fds, fds, sizeof(int) * n_fds);
123
124 *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
125 }
126
127 static 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);
144 bloom_add_pair(bloom, "path-slash-prefix", m->path);
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;
189 }
190
191 static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) {
192 struct bus_body_part *part;
193 struct kdbus_item *d;
194 bool well_known;
195 uint64_t unique;
196 size_t sz, dl;
197 unsigned i;
198 int r;
199
200 assert(b);
201 assert(m);
202 assert(m->sealed);
203
204 if (m->kdbus)
205 return 0;
206
207 if (m->destination) {
208 r = bus_kernel_parse_unique_name(m->destination, &unique);
209 if (r < 0)
210 return r;
211
212 well_known = r == 0;
213 } else
214 well_known = false;
215
216 sz = offsetof(struct kdbus_msg, items);
217
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
221 /* Add in fixed header, fields header and payload */
222 sz += (1 + m->n_body_parts) *
223 ALIGN8(offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec));
224
225 /* Add space for bloom filter */
226 sz += ALIGN8(offsetof(struct kdbus_item, data) + BLOOM_SIZE);
227
228 /* Add in well-known destination header */
229 if (well_known) {
230 dl = strlen(m->destination);
231 sz += ALIGN8(offsetof(struct kdbus_item, str) + dl + 1);
232 }
233
234 /* Add space for unix fds */
235 if (m->n_fds > 0)
236 sz += ALIGN8(offsetof(struct kdbus_item, fds) + sizeof(int)*m->n_fds);
237
238 m->kdbus = memalign(8, sz);
239 if (!m->kdbus) {
240 r = -ENOMEM;
241 goto fail;
242 }
243
244 m->free_kdbus = true;
245 memset(m->kdbus, 0, sz);
246
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 :
252 m->destination ? unique : KDBUS_DST_ID_BROADCAST;
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
258 d = m->kdbus->items;
259
260 if (well_known)
261 append_destination(&d, m->destination, dl);
262
263 append_payload_vec(&d, m->header, BUS_MESSAGE_BODY_BEGIN(m));
264
265 MESSAGE_FOREACH_PART(part, i, m) {
266 if (part->is_zero) {
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
272 append_payload_vec(&d, NULL, part->size);
273 continue;
274 }
275
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 */
279
280 append_payload_memfd(&d, part->memfd, part->size);
281 continue;
282 }
283
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;
289
290 append_payload_vec(&d, part->data, part->size);
291 }
292
293 if (m->kdbus->dst_id == KDBUS_DST_ID_BROADCAST) {
294 void *p;
295
296 p = append_bloom(&d, BLOOM_SIZE);
297 r = bus_message_setup_bloom(m, p);
298 if (r < 0)
299 goto fail;
300 }
301
302 if (m->n_fds > 0)
303 append_fds(&d, m->fds, m->n_fds);
304
305 m->kdbus->size = (uint8_t*) d - (uint8_t*) m->kdbus;
306 assert(m->kdbus->size <= sz);
307
308 return 0;
309
310 fail:
311 m->poisoned = true;
312 return r;
313 }
314
315 int bus_kernel_take_fd(sd_bus *b) {
316 struct kdbus_cmd_hello hello;
317 int r;
318
319 assert(b);
320
321 if (b->is_server)
322 return -EINVAL;
323
324 b->use_memfd = 1;
325
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
335 if (!b->kdbus_buffer) {
336 b->kdbus_buffer = mmap(NULL, KDBUS_POOL_SIZE, PROT_READ, MAP_SHARED, b->input_fd, 0);
337 if (b->kdbus_buffer == MAP_FAILED) {
338 b->kdbus_buffer = NULL;
339 return -errno;
340 }
341 }
342
343 /* The higher 32bit of both flags fields are considered
344 * 'incompatible flags'. Refuse them all for now. */
345 if (hello.bus_flags > 0xFFFFFFFFULL ||
346 hello.conn_flags > 0xFFFFFFFFULL)
347 return -ENOTSUP;
348
349 if (hello.bloom_size != BLOOM_SIZE)
350 return -ENOTSUP;
351
352 if (asprintf(&b->unique_name, ":1.%llu", (unsigned long long) hello.id) < 0)
353 return -ENOMEM;
354
355 b->is_kernel = true;
356 b->bus_client = true;
357 b->can_fds = !!(hello.conn_flags & KDBUS_HELLO_ACCEPT_FD);
358
359 r = bus_start_running(b);
360 if (r < 0)
361 return r;
362
363 return 1;
364 }
365
366 int 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
372 if (b->is_server)
373 return -EINVAL;
374
375 b->input_fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC);
376 if (b->input_fd < 0)
377 return -errno;
378
379 b->output_fd = b->input_fd;
380
381 return bus_kernel_take_fd(b);
382 }
383
384 int 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
391 r = bus_message_setup_kmsg(bus, m);
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
399 return 1;
400 }
401
402 static void close_kdbus_msg(sd_bus *bus, struct kdbus_msg *k) {
403 uint64_t off;
404 struct kdbus_item *d;
405
406 assert(bus);
407 assert(k);
408
409 off = (uint8_t *)k - (uint8_t *)bus->kdbus_buffer;
410 ioctl(bus->input_fd, KDBUS_CMD_MSG_RELEASE, &off);
411
412 KDBUS_ITEM_FOREACH(d, k) {
413
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);
418 }
419 }
420
421 static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k, sd_bus_message **ret) {
422 sd_bus_message *m = NULL;
423 struct kdbus_item *d;
424 unsigned n_fds = 0;
425 _cleanup_free_ int *fds = NULL;
426 struct bus_header *h = NULL;
427 size_t total, n_bytes = 0, idx = 0;
428 const char *destination = NULL, *seclabel = NULL;
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
438 KDBUS_ITEM_FOREACH(d, k) {
439 size_t l;
440
441 l = d->size - offsetof(struct kdbus_item, data);
442
443 if (d->type == KDBUS_MSG_PAYLOAD_OFF) {
444
445 if (!h) {
446 h = (struct bus_header *)((uint8_t *)bus->kdbus_buffer + d->vec.offset);
447
448 if (!bus_header_is_complete(h, d->vec.size))
449 return -EBADMSG;
450 }
451
452 n_bytes += d->vec.size;
453
454 } else if (d->type == KDBUS_MSG_PAYLOAD_MEMFD) {
455
456 if (!h)
457 return -EBADMSG;
458
459 n_bytes += d->memfd.size;
460
461 } else if (d->type == KDBUS_MSG_FDS) {
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;
471 memcpy(fds + n_fds, d->fds, sizeof(int) * j);
472 n_fds += j;
473
474 } else if (d->type == KDBUS_MSG_SRC_SECLABEL)
475 seclabel = d->str;
476 }
477
478 if (!h)
479 return -EBADMSG;
480
481 r = bus_header_message_size(h, &total);
482 if (r < 0)
483 return r;
484
485 if (n_bytes != total)
486 return -EBADMSG;
487
488 r = bus_message_from_header(h, sizeof(struct bus_header), fds, n_fds, NULL, seclabel, 0, &m);
489 if (r < 0)
490 return r;
491
492 KDBUS_ITEM_FOREACH(d, k) {
493 size_t l;
494
495 l = d->size - offsetof(struct kdbus_item, data);
496
497 if (d->type == KDBUS_MSG_PAYLOAD_OFF) {
498 size_t begin_body;
499
500 begin_body = BUS_MESSAGE_BODY_BEGIN(m);
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) {
509 r = -ENOMEM;
510 goto fail;
511 }
512
513 /* A -1 offset is NUL padding. */
514 part->is_zero = d->vec.offset == ~0ULL;
515
516 if (idx >= begin_body) {
517 if (!part->is_zero)
518 part->data = (uint8_t *)bus->kdbus_buffer + d->vec.offset;
519 part->size = d->vec.size;
520 } else {
521 if (!part->is_zero)
522 part->data = (uint8_t *)bus->kdbus_buffer + d->vec.offset + (begin_body - idx);
523 part->size = d->vec.size - (begin_body - idx);
524 }
525
526 part->sealed = true;
527 }
528
529 idx += d->vec.size;
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;
549
550 } else if (d->type == KDBUS_MSG_SRC_CREDS) {
551 m->pid_starttime = d->creds.starttime / NSEC_PER_USEC;
552 m->uid = d->creds.uid;
553 m->gid = d->creds.gid;
554 m->pid = d->creds.pid;
555 m->tid = d->creds.tid;
556 m->uid_valid = m->gid_valid = true;
557 } else if (d->type == KDBUS_MSG_TIMESTAMP) {
558 m->realtime = d->timestamp.realtime_ns / NSEC_PER_USEC;
559 m->monotonic = d->timestamp.monotonic_ns / NSEC_PER_USEC;
560 } else if (d->type == KDBUS_MSG_SRC_PID_COMM)
561 m->comm = d->str;
562 else if (d->type == KDBUS_MSG_SRC_TID_COMM)
563 m->tid_comm = d->str;
564 else if (d->type == KDBUS_MSG_SRC_EXE)
565 m->exe = d->str;
566 else if (d->type == KDBUS_MSG_SRC_CMDLINE) {
567 m->cmdline = d->str;
568 m->cmdline_length = l;
569 } else if (d->type == KDBUS_MSG_SRC_CGROUP)
570 m->cgroup = d->str;
571 else if (d->type == KDBUS_MSG_SRC_AUDIT)
572 m->audit = &d->audit;
573 else if (d->type == KDBUS_MSG_SRC_CAPS) {
574 m->capability = d->data;
575 m->capability_size = l;
576 } else if (d->type == KDBUS_MSG_DST_NAME)
577 destination = d->str;
578 else if (d->type != KDBUS_MSG_FDS &&
579 d->type != KDBUS_MSG_SRC_SECLABEL)
580 log_debug("Got unknown field from kernel %llu", d->type);
581 }
582
583 r = bus_message_parse_fields(m);
584 if (r < 0)
585 goto fail;
586
587 if (k->src_id == KDBUS_SRC_ID_KERNEL)
588 m->sender = "org.freedesktop.DBus";
589 else {
590 snprintf(m->sender_buffer, sizeof(m->sender_buffer), ":1.%llu", (unsigned long long) k->src_id);
591 m->sender = m->sender_buffer;
592 }
593
594 if (!m->destination) {
595 if (destination)
596 m->destination = destination;
597 else if (k->dst_id != KDBUS_DST_ID_WELL_KNOWN_NAME &&
598 k->dst_id != KDBUS_DST_ID_BROADCAST) {
599 snprintf(m->destination_buffer, sizeof(m->destination_buffer), ":1.%llu", (unsigned long long) k->dst_id);
600 m->destination = m->destination_buffer;
601 }
602 }
603
604 /* We take possession of the kmsg struct now */
605 m->kdbus = k;
606 m->bus = sd_bus_ref(bus);
607 m->release_kdbus = true;
608 m->free_fds = true;
609
610 fds = NULL;
611
612 *ret = m;
613 return 1;
614
615 fail:
616 if (m) {
617 struct bus_body_part *part;
618 unsigned i;
619
620 /* Make sure the memfds are not freed twice */
621 MESSAGE_FOREACH_PART(part, i, m)
622 if (part->memfd >= 0)
623 part->memfd = -1;
624
625 sd_bus_message_unref(m);
626 }
627
628 return r;
629 }
630
631 int bus_kernel_read_message(sd_bus *bus, sd_bus_message **m) {
632 uint64_t off;
633 struct kdbus_msg *k;
634 int r;
635
636 assert(bus);
637 assert(m);
638
639 r = ioctl(bus->input_fd, KDBUS_CMD_MSG_RECV, &off);
640 if (r < 0) {
641 if (errno == EAGAIN)
642 return 0;
643
644 return -errno;
645 }
646 k = (struct kdbus_msg *)((uint8_t *)bus->kdbus_buffer + off);
647
648 r = bus_kernel_make_message(bus, k, m);
649 if (r <= 0)
650 close_kdbus_msg(bus, k);
651
652 return r < 0 ? r : 1;
653 }
654
655 int bus_kernel_create(const char *name, char **s) {
656 struct kdbus_cmd_bus_make *make;
657 struct kdbus_item *n;
658 size_t l;
659 int fd;
660 char *p;
661
662 assert(name);
663 assert(s);
664
665 fd = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
666 if (fd < 0)
667 return -errno;
668
669 l = strlen(name);
670 make = alloca0(offsetof(struct kdbus_cmd_bus_make, items) +
671 KDBUS_ITEM_HEADER_SIZE + sizeof(uint64_t) +
672 KDBUS_ITEM_HEADER_SIZE + DECIMAL_STR_MAX(uid_t) + 1 + l + 1);
673
674 n = make->items;
675 n->type = KDBUS_MAKE_NAME;
676 sprintf(n->str, "%lu-%s", (unsigned long) getuid(), name);
677 n->size = KDBUS_ITEM_HEADER_SIZE + strlen(n->str) + 1;
678
679 make->size = offsetof(struct kdbus_cmd_bus_make, items) + n->size;
680 make->flags = KDBUS_MAKE_POLICY_OPEN;
681 make->bus_flags = 0;
682 make->bloom_size = BLOOM_SIZE;
683 assert_cc(BLOOM_SIZE % 8 == 0);
684
685 p = strjoin("/dev/kdbus/", n->str, "/bus", NULL);
686 if (!p)
687 return -ENOMEM;
688
689 if (ioctl(fd, KDBUS_CMD_BUS_MAKE, make) < 0) {
690 close_nointr_nofail(fd);
691 free(p);
692 return -errno;
693 }
694
695 if (s)
696 *s = p;
697
698 return fd;
699 }
700
701 int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *size) {
702 struct memfd_cache *c;
703 int fd;
704
705 assert(address);
706 assert(size);
707
708 if (!bus || !bus->is_kernel)
709 return -ENOTSUP;
710
711 assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) >= 0);
712
713 if (bus->n_memfd_cache <= 0) {
714 int r;
715
716 assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
717
718 r = ioctl(bus->input_fd, KDBUS_CMD_MEMFD_NEW, &fd);
719 if (r < 0)
720 return -errno;
721
722 *address = NULL;
723 *size = 0;
724 return fd;
725 }
726
727 c = &bus->memfd_cache[--bus->n_memfd_cache];
728
729 assert(c->fd >= 0);
730 assert(c->size == 0 || c->address);
731
732 *address = c->address;
733 *size = c->size;
734 fd = c->fd;
735
736 assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
737
738 return fd;
739 }
740
741 static void close_and_munmap(int fd, void *address, size_t size) {
742 if (size > 0)
743 assert_se(munmap(address, PAGE_ALIGN(size)) >= 0);
744
745 close_nointr_nofail(fd);
746 }
747
748 void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t size) {
749 struct memfd_cache *c;
750 uint64_t max_sz = PAGE_ALIGN(MEMFD_CACHE_ITEM_SIZE_MAX);
751
752 assert(fd >= 0);
753 assert(size == 0 || address);
754
755 if (!bus || !bus->is_kernel) {
756 close_and_munmap(fd, address, size);
757 return;
758 }
759
760 assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) >= 0);
761
762 if (bus->n_memfd_cache >= ELEMENTSOF(bus->memfd_cache)) {
763 assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
764
765 close_and_munmap(fd, address, size);
766 return;
767 }
768
769 c = &bus->memfd_cache[bus->n_memfd_cache++];
770 c->fd = fd;
771 c->address = address;
772
773 /* If overly long, let's return a bit to the OS */
774 if (size > max_sz) {
775 assert_se(ioctl(fd, KDBUS_CMD_MEMFD_SIZE_SET, &max_sz) >= 0);
776 assert_se(munmap((uint8_t*) address + max_sz, PAGE_ALIGN(size - max_sz)) >= 0);
777 c->size = max_sz;
778 } else
779 c->size = size;
780
781 assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
782 }
783
784 void bus_kernel_flush_memfd(sd_bus *b) {
785 unsigned i;
786
787 assert(b);
788
789 for (i = 0; i < b->n_memfd_cache; i++)
790 close_and_munmap(b->memfd_cache[i].fd, b->memfd_cache[i].address, b->memfd_cache[i].size);
791 }