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