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