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