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