chiark / gitweb /
bus: fix allocation of body parts from memfd
[elogind.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 = 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         r = bus_message_from_header(h, sizeof(struct bus_header), fds, n_fds, NULL, seclabel, 0, &m);
480         if (r < 0)
481                 return r;
482
483         KDBUS_ITEM_FOREACH(d, k) {
484                 size_t l;
485
486                 l = d->size - offsetof(struct kdbus_item, data);
487
488                 if (d->type == KDBUS_MSG_PAYLOAD_VEC) {
489                         size_t begin_body;
490
491                         /* Fill in fields material */
492                         range_contains(idx, d->vec.size, ALIGN8(sizeof(struct bus_header)), BUS_MESSAGE_FIELDS_SIZE(m),
493                                        UINT64_TO_PTR(d->vec.address), &m->fields);
494
495                         begin_body = ALIGN8(sizeof(struct bus_header)) + ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m));
496
497                         if (idx + d->vec.size > begin_body) {
498                                 struct bus_body_part *part;
499
500                                 /* Contains body material */
501
502                                 part = message_append_part(m);
503                                 if (!part) {
504                                         sd_bus_message_unref(m);
505                                         return -ENOMEM;
506                                 }
507
508                                 if (idx >= begin_body) {
509                                         part->data = (void*) d->vec.address;
510                                         part->size = d->vec.size;
511                                 } else {
512                                         part->data = (uint8_t*) (uintptr_t) d->vec.address + (begin_body - idx);
513                                         part->size = d->vec.size - (begin_body - idx);
514                                 }
515
516                                 part->sealed = true;
517                         }
518
519                         idx += d->vec.size;
520
521                 } else if (d->type == KDBUS_MSG_SRC_CREDS) {
522                         m->pid_starttime = d->creds.starttime / NSEC_PER_USEC;
523                         m->uid = d->creds.uid;
524                         m->gid = d->creds.gid;
525                         m->pid = d->creds.pid;
526                         m->tid = d->creds.tid;
527                         m->uid_valid = m->gid_valid = true;
528                 } else if (d->type == KDBUS_MSG_TIMESTAMP) {
529                         m->realtime = d->timestamp.realtime_ns / NSEC_PER_USEC;
530                         m->monotonic = d->timestamp.monotonic_ns / NSEC_PER_USEC;
531                 } else if (d->type == KDBUS_MSG_SRC_PID_COMM)
532                         m->comm = d->str;
533                 else if (d->type == KDBUS_MSG_SRC_TID_COMM)
534                         m->tid_comm = d->str;
535                 else if (d->type == KDBUS_MSG_SRC_EXE)
536                         m->exe = d->str;
537                 else if (d->type == KDBUS_MSG_SRC_CMDLINE) {
538                         m->cmdline = d->str;
539                         m->cmdline_length = l;
540                 } else if (d->type == KDBUS_MSG_SRC_CGROUP)
541                         m->cgroup = d->str;
542                 else if (d->type == KDBUS_MSG_SRC_AUDIT)
543                         m->audit = &d->audit;
544                 else if (d->type == KDBUS_MSG_SRC_CAPS) {
545                         m->capability = d->data;
546                         m->capability_size = l;
547                 } else if (d->type != KDBUS_MSG_FDS &&
548                            d->type != KDBUS_MSG_DST_NAME &&
549                            d->type != KDBUS_MSG_SRC_SECLABEL)
550                         log_debug("Got unknown field from kernel %llu", d->type);
551         }
552
553         if ((BUS_MESSAGE_FIELDS_SIZE(m) > 0 && !m->fields)) {
554                 sd_bus_message_unref(m);
555                 return -EBADMSG;
556         }
557
558         r = bus_message_parse_fields(m);
559         if (r < 0) {
560                 sd_bus_message_unref(m);
561                 return r;
562         }
563
564         if (k->src_id == KDBUS_SRC_ID_KERNEL)
565                 m->sender = "org.freedesktop.DBus";
566         else {
567                 snprintf(m->sender_buffer, sizeof(m->sender_buffer), ":1.%llu", (unsigned long long) k->src_id);
568                 m->sender = m->sender_buffer;
569         }
570
571         if (!m->destination) {
572                 if (destination)
573                         m->destination = destination;
574                 else if (k->dst_id != KDBUS_DST_ID_WELL_KNOWN_NAME &&
575                          k->dst_id != KDBUS_DST_ID_BROADCAST) {
576                         snprintf(m->destination_buffer, sizeof(m->destination_buffer), ":1.%llu", (unsigned long long) k->dst_id);
577                         m->destination = m->destination_buffer;
578                 }
579         }
580
581         /* We take possession of the kmsg struct now */
582         m->kdbus = k;
583         m->bus = sd_bus_ref(bus);
584         m->release_kdbus = true;
585         m->free_fds = true;
586
587         fds = NULL;
588
589         *ret = m;
590         return 1;
591 }
592
593 int bus_kernel_read_message(sd_bus *bus, sd_bus_message **m) {
594         struct kdbus_msg *k;
595         int r;
596
597         assert(bus);
598         assert(m);
599
600         r = ioctl(bus->input_fd, KDBUS_CMD_MSG_RECV, &k);
601         if (r < 0) {
602                 if (errno == EAGAIN)
603                         return 0;
604
605                 return -errno;
606         }
607
608
609 /*                 /\* Let's tell valgrind that there's really no need to */
610 /*                  * initialize this fully. This should be removed again */
611 /*                  * when valgrind learned the kdbus ioctls natively. *\/ */
612 /* #ifdef HAVE_VALGRIND_MEMCHECK_H */
613 /*                 VALGRIND_MAKE_MEM_DEFINED(k, sz); */
614 /* #endif */
615
616
617         r = bus_kernel_make_message(bus, k, m);
618         if (r <= 0)
619                 close_kdbus_msg(bus, k);
620
621         return r < 0 ? r : 1;
622 }
623
624 int bus_kernel_create(const char *name, char **s) {
625         struct kdbus_cmd_bus_make *make;
626         struct kdbus_item *n, *cg;
627         size_t l;
628         int fd;
629         char *p;
630
631         assert(name);
632         assert(s);
633
634         fd = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
635         if (fd < 0)
636                 return -errno;
637
638         l = strlen(name);
639         make = alloca0(offsetof(struct kdbus_cmd_bus_make, items) +
640                        KDBUS_ITEM_HEADER_SIZE + sizeof(uint64_t) +
641                        KDBUS_ITEM_HEADER_SIZE + DECIMAL_STR_MAX(uid_t) + 1 + l + 1);
642
643         cg = make->items;
644         cg->type = KDBUS_MAKE_CGROUP;
645         cg->data64[0] = 1;
646         cg->size = KDBUS_ITEM_HEADER_SIZE + sizeof(uint64_t);
647
648         n = KDBUS_ITEM_NEXT(cg);
649         n->type = KDBUS_MAKE_NAME;
650         sprintf(n->str, "%lu-%s", (unsigned long) getuid(), name);
651         n->size = KDBUS_ITEM_HEADER_SIZE + strlen(n->str) + 1;
652
653         make->size = offsetof(struct kdbus_cmd_bus_make, items) + cg->size + n->size;
654         make->flags = KDBUS_MAKE_POLICY_OPEN;
655         make->bus_flags = 0;
656         make->bloom_size = BLOOM_SIZE;
657         assert_cc(BLOOM_SIZE % 8 == 0);
658
659         p = strjoin("/dev/kdbus/", n->str, "/bus", NULL);
660         if (!p)
661                 return -ENOMEM;
662
663         if (ioctl(fd, KDBUS_CMD_BUS_MAKE, make) < 0) {
664                 close_nointr_nofail(fd);
665                 free(p);
666                 return -errno;
667         }
668
669         if (s)
670                 *s = p;
671
672         return fd;
673 }
674
675 int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *size) {
676         struct memfd_cache *c;
677
678         assert(address);
679         assert(size);
680
681         if (!bus || !bus->is_kernel)
682                 return -ENOTSUP;
683
684         if (bus->n_memfd_cache <= 0) {
685                 int fd, r;
686
687                 r = ioctl(bus->input_fd, KDBUS_CMD_MEMFD_NEW, &fd);
688                 if (r < 0)
689                         return -errno;
690
691                 *address = NULL;
692                 *size = 0;
693                 return fd;
694         }
695
696         c = &bus->memfd_cache[-- bus->n_memfd_cache];
697
698         assert(c->fd >= 0);
699         assert(c->size == 0 || c->address);
700
701         *address = c->address;
702         *size = c->size;
703
704         return c->fd;
705 }
706
707 void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t size) {
708         struct memfd_cache *c;
709
710         assert(fd >= 0);
711         assert(size == 0 || address);
712
713         if (!bus || !bus->is_kernel ||
714             bus->n_memfd_cache >= ELEMENTSOF(bus->memfd_cache)) {
715
716                 if (size > 0)
717                         assert_se(munmap(address, PAGE_ALIGN(size)) == 0);
718
719                 close_nointr_nofail(fd);
720                 return;
721         }
722
723         c = &bus->memfd_cache[bus->n_memfd_cache++];
724         c->fd = fd;
725         c->address = address;
726
727         /* If overly long, let's return a bit to the OS */
728         if (size > MEMFD_CACHE_ITEM_SIZE_MAX) {
729                 uint64_t sz = MEMFD_CACHE_ITEM_SIZE_MAX;
730
731                 ioctl(bus->input_fd, KDBUS_CMD_MEMFD_SIZE_SET, &sz);
732
733                 c->size = MEMFD_CACHE_ITEM_SIZE_MAX;
734         } else
735                 c->size = size;
736 }
737
738 void bus_kernel_flush_memfd(sd_bus *b) {
739         unsigned i;
740
741         assert(b);
742
743         for (i = 0; i < b->n_memfd_cache; i++) {
744                 if (b->memfd_cache[i].size > 0)
745                         assert_se(munmap(b->memfd_cache[i].address, PAGE_ALIGN(b->memfd_cache[i].size)) == 0);
746
747                 close_nointr_nofail(b->memfd_cache[i].fd);
748         }
749 }