]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-bus/bus-kernel.c
bus: add test for bloom filter prefix match
[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 uint8_t h[ALIGN8(sizeof(struct kdbus_cmd_hello)) +
317 ALIGN8(KDBUS_ITEM_HEADER_SIZE) +
318 ALIGN8(sizeof(struct kdbus_vec))] = {};
319
320 struct kdbus_cmd_hello *hello = (struct kdbus_cmd_hello*) h;
321
322 int r;
323
324 assert(b);
325
326 if (b->is_server)
327 return -EINVAL;
328
329 if (!b->kdbus_buffer) {
330 b->kdbus_buffer = mmap(NULL, KDBUS_POOL_SIZE, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
331 if (b->kdbus_buffer == MAP_FAILED) {
332 b->kdbus_buffer = NULL;
333 return -errno;
334 }
335 }
336
337 hello->size = sizeof(h);
338 hello->conn_flags = b->hello_flags;
339
340 hello->items[0].type = KDBUS_HELLO_POOL;
341 hello->items[0].size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_vec);
342 hello->items[0].vec.address = (uint64_t) b->kdbus_buffer;
343 hello->items[0].vec.size = KDBUS_POOL_SIZE;
344
345 r = ioctl(b->input_fd, KDBUS_CMD_HELLO, hello);
346 if (r < 0)
347 return -errno;
348
349 /* The higher 32bit of both flags fields are considered
350 * 'incompatible flags'. Refuse them all for now. */
351 if (hello->bus_flags > 0xFFFFFFFFULL ||
352 hello->conn_flags > 0xFFFFFFFFULL)
353 return -ENOTSUP;
354
355 if (hello->bloom_size != BLOOM_SIZE)
356 return -ENOTSUP;
357
358 if (asprintf(&b->unique_name, ":1.%llu", (unsigned long long) hello->id) < 0)
359 return -ENOMEM;
360
361 b->is_kernel = true;
362 b->bus_client = true;
363 b->can_fds = !!(hello->conn_flags & KDBUS_HELLO_ACCEPT_FD);
364
365 r = bus_start_running(b);
366 if (r < 0)
367 return r;
368
369 return 1;
370 }
371
372 int bus_kernel_connect(sd_bus *b) {
373 assert(b);
374 assert(b->input_fd < 0);
375 assert(b->output_fd < 0);
376 assert(b->kernel);
377
378 if (b->is_server)
379 return -EINVAL;
380
381 b->input_fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC);
382 if (b->input_fd < 0)
383 return -errno;
384
385 b->output_fd = b->input_fd;
386
387 return bus_kernel_take_fd(b);
388 }
389
390 int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m) {
391 int r;
392
393 assert(bus);
394 assert(m);
395 assert(bus->state == BUS_RUNNING);
396
397 r = bus_message_setup_kmsg(bus, m);
398 if (r < 0)
399 return r;
400
401 r = ioctl(bus->output_fd, KDBUS_CMD_MSG_SEND, m->kdbus);
402 if (r < 0)
403 return errno == EAGAIN ? 0 : -errno;
404
405 return 1;
406 }
407
408 static void close_kdbus_msg(sd_bus *bus, struct kdbus_msg *k) {
409 struct kdbus_item *d;
410
411 assert(bus);
412 assert(k);
413
414 ioctl(bus->input_fd, KDBUS_CMD_MSG_RELEASE, k);
415
416 KDBUS_ITEM_FOREACH(d, k) {
417
418 if (d->type == KDBUS_MSG_FDS)
419 close_many(d->fds, (d->size - offsetof(struct kdbus_item, fds)) / sizeof(int));
420 else if (d->type == KDBUS_MSG_PAYLOAD_MEMFD)
421 close_nointr_nofail(d->memfd.fd);
422 }
423 }
424
425 static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k, sd_bus_message **ret) {
426 sd_bus_message *m = NULL;
427 struct kdbus_item *d;
428 unsigned n_fds = 0;
429 _cleanup_free_ int *fds = NULL;
430 struct bus_header *h = NULL;
431 size_t total, n_bytes = 0, idx = 0;
432 const char *destination = NULL, *seclabel = NULL;
433 int r;
434
435 assert(bus);
436 assert(k);
437 assert(ret);
438
439 if (k->payload_type != KDBUS_PAYLOAD_DBUS1)
440 return 0;
441
442 KDBUS_ITEM_FOREACH(d, k) {
443 size_t l;
444
445 l = d->size - offsetof(struct kdbus_item, data);
446
447 if (d->type == KDBUS_MSG_PAYLOAD_VEC) {
448
449 if (!h) {
450 h = UINT64_TO_PTR(d->vec.address);
451
452 if (!bus_header_is_complete(h, d->vec.size))
453 return -EBADMSG;
454 }
455
456 n_bytes += d->vec.size;
457
458 } else if (d->type == KDBUS_MSG_PAYLOAD_MEMFD) {
459
460 if (!h)
461 return -EBADMSG;
462
463 n_bytes += d->memfd.size;
464
465 } else if (d->type == KDBUS_MSG_FDS) {
466 int *f;
467 unsigned j;
468
469 j = l / sizeof(int);
470 f = realloc(fds, sizeof(int) * (n_fds + j));
471 if (!f)
472 return -ENOMEM;
473
474 fds = f;
475 memcpy(fds + n_fds, d->fds, sizeof(int) * j);
476 n_fds += j;
477
478 } else if (d->type == KDBUS_MSG_SRC_SECLABEL)
479 seclabel = d->str;
480 }
481
482 if (!h)
483 return -EBADMSG;
484
485 r = bus_header_message_size(h, &total);
486 if (r < 0)
487 return r;
488
489 if (n_bytes != total)
490 return -EBADMSG;
491
492 r = bus_message_from_header(h, sizeof(struct bus_header), fds, n_fds, NULL, seclabel, 0, &m);
493 if (r < 0)
494 return r;
495
496 KDBUS_ITEM_FOREACH(d, k) {
497 size_t l;
498
499 l = d->size - offsetof(struct kdbus_item, data);
500
501 if (d->type == KDBUS_MSG_PAYLOAD_VEC) {
502 size_t begin_body;
503
504 begin_body = BUS_MESSAGE_BODY_BEGIN(m);
505
506 if (idx + d->vec.size > begin_body) {
507 struct bus_body_part *part;
508
509 /* Contains body material */
510
511 part = message_append_part(m);
512 if (!part) {
513 r = -ENOMEM;
514 goto fail;
515 }
516
517 if (idx >= begin_body) {
518 part->data = UINT64_TO_PTR(d->vec.address);
519 part->size = d->vec.size;
520 } else {
521 part->data = d->vec.address != 0 ? (uint8_t*) UINT64_TO_PTR(d->vec.address) + (begin_body - idx) : NULL;
522 part->size = d->vec.size - (begin_body - idx);
523 }
524
525 part->is_zero = d->vec.address == 0;
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 addr;
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, &addr);
640 if (r < 0) {
641 if (errno == EAGAIN)
642 return 0;
643
644 return -errno;
645 }
646 k = UINT64_TO_PTR(addr);
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, *cg;
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 cg = make->items;
675 cg->type = KDBUS_MAKE_CGROUP;
676 cg->data64[0] = 1;
677 cg->size = KDBUS_ITEM_HEADER_SIZE + sizeof(uint64_t);
678
679 n = KDBUS_ITEM_NEXT(cg);
680 n->type = KDBUS_MAKE_NAME;
681 sprintf(n->str, "%lu-%s", (unsigned long) getuid(), name);
682 n->size = KDBUS_ITEM_HEADER_SIZE + strlen(n->str) + 1;
683
684 make->size = offsetof(struct kdbus_cmd_bus_make, items) + cg->size + n->size;
685 make->flags = KDBUS_MAKE_POLICY_OPEN;
686 make->bus_flags = 0;
687 make->bloom_size = BLOOM_SIZE;
688 assert_cc(BLOOM_SIZE % 8 == 0);
689
690 p = strjoin("/dev/kdbus/", n->str, "/bus", NULL);
691 if (!p)
692 return -ENOMEM;
693
694 if (ioctl(fd, KDBUS_CMD_BUS_MAKE, make) < 0) {
695 close_nointr_nofail(fd);
696 free(p);
697 return -errno;
698 }
699
700 if (s)
701 *s = p;
702
703 return fd;
704 }
705
706 int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *size) {
707 struct memfd_cache *c;
708 int fd;
709
710 assert(address);
711 assert(size);
712
713 if (!bus || !bus->is_kernel)
714 return -ENOTSUP;
715
716 assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) == 0);
717
718 if (bus->n_memfd_cache <= 0) {
719 int r;
720
721 assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0);
722
723 r = ioctl(bus->input_fd, KDBUS_CMD_MEMFD_NEW, &fd);
724 if (r < 0)
725 return -errno;
726
727 *address = NULL;
728 *size = 0;
729 return fd;
730 }
731
732 c = &bus->memfd_cache[-- bus->n_memfd_cache];
733
734 assert(c->fd >= 0);
735 assert(c->size == 0 || c->address);
736
737 *address = c->address;
738 *size = c->size;
739 fd = c->fd;
740
741 assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0);
742
743 return fd;
744 }
745
746 static void close_and_munmap(int fd, void *address, size_t size) {
747 if (size > 0)
748 assert_se(munmap(address, PAGE_ALIGN(size)) == 0);
749
750 close_nointr_nofail(fd);
751 }
752
753 void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t size) {
754 struct memfd_cache *c;
755
756 assert(fd >= 0);
757 assert(size == 0 || address);
758
759 if (!bus || !bus->is_kernel) {
760 close_and_munmap(fd, address, size);
761 return;
762 }
763
764 assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) == 0);
765
766 if (bus->n_memfd_cache >= ELEMENTSOF(bus->memfd_cache)) {
767 assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0);
768
769 close_and_munmap(fd, address, size);
770 return;
771 }
772
773 c = &bus->memfd_cache[bus->n_memfd_cache++];
774 c->fd = fd;
775 c->address = address;
776
777 /* If overly long, let's return a bit to the OS */
778 if (size > MEMFD_CACHE_ITEM_SIZE_MAX) {
779 uint64_t sz = MEMFD_CACHE_ITEM_SIZE_MAX;
780
781 ioctl(bus->input_fd, KDBUS_CMD_MEMFD_SIZE_SET, &sz);
782
783 c->size = MEMFD_CACHE_ITEM_SIZE_MAX;
784 } else
785 c->size = size;
786
787 assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) == 0);
788 }
789
790 void bus_kernel_flush_memfd(sd_bus *b) {
791 unsigned i;
792
793 assert(b);
794
795 for (i = 0; i < b->n_memfd_cache; i++) {
796 if (b->memfd_cache[i].size > 0)
797 assert_se(munmap(b->memfd_cache[i].address, PAGE_ALIGN(b->memfd_cache[i].size)) == 0);
798
799 close_nointr_nofail(b->memfd_cache[i].fd);
800 }
801 }