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