chiark / gitweb /
bus: fix test-bus-memfd
[elogind.git] / src / libsystemd-bus / bus-kernel.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #ifdef HAVE_VALGRIND_MEMCHECK_H
23 #include <valgrind/memcheck.h>
24 #endif
25
26 #include <fcntl.h>
27 #include <malloc.h>
28 #include <sys/mman.h>
29
30 #include "util.h"
31
32 #include "bus-internal.h"
33 #include "bus-message.h"
34 #include "bus-kernel.h"
35 #include "bus-bloom.h"
36
37 #define KDBUS_ITEM_NEXT(item) \
38         (typeof(item))(((uint8_t *)item) + ALIGN8((item)->size))
39
40 #define KDBUS_ITEM_FOREACH(item, head)                                          \
41         for (item = (head)->items;                                              \
42              (uint8_t *)(item) < (uint8_t *)(head) + (head)->size;              \
43              item = KDBUS_ITEM_NEXT(item))
44
45 #define KDBUS_ITEM_HEADER_SIZE offsetof(struct kdbus_item, data)
46 #define KDBUS_ITEM_SIZE(s) ALIGN8((s) + KDBUS_ITEM_HEADER_SIZE)
47
48 #define KDBUS_POOL_SIZE (4*1024*1024)
49
50 static int parse_unique_name(const char *s, uint64_t *id) {
51         int r;
52
53         assert(s);
54         assert(id);
55
56         if (!startswith(s, ":1."))
57                 return 0;
58
59         r = safe_atou64(s + 3, id);
60         if (r < 0)
61                 return r;
62
63         return 1;
64 }
65
66 static void append_payload_vec(struct kdbus_item **d, const void *p, size_t sz) {
67         assert(d);
68         assert(p);
69         assert(sz > 0);
70
71         *d = ALIGN8_PTR(*d);
72
73         (*d)->size = offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec);
74         (*d)->type = KDBUS_MSG_PAYLOAD_VEC;
75         (*d)->vec.address = (intptr_t) p;
76         (*d)->vec.size = sz;
77
78         *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
79 }
80
81 static void append_destination(struct kdbus_item **d, const char *s, size_t length) {
82         assert(d);
83         assert(s);
84
85         *d = ALIGN8_PTR(*d);
86
87         (*d)->size = offsetof(struct kdbus_item, str) + length + 1;
88         (*d)->type = KDBUS_MSG_DST_NAME;
89         memcpy((*d)->str, s, length + 1);
90
91         *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
92 }
93
94 static void* append_bloom(struct kdbus_item **d, size_t length) {
95         void *r;
96
97         assert(d);
98
99         *d = ALIGN8_PTR(*d);
100
101         (*d)->size = offsetof(struct kdbus_item, data) + length;
102         (*d)->type = KDBUS_MSG_BLOOM;
103         r = (*d)->data;
104
105         *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
106
107         return r;
108 }
109
110 static void append_fds(struct kdbus_item **d, const int fds[], unsigned n_fds) {
111         assert(d);
112         assert(fds);
113         assert(n_fds > 0);
114
115         *d = ALIGN8_PTR(*d);
116         (*d)->size = offsetof(struct kdbus_item, fds) + sizeof(int) * n_fds;
117         (*d)->type = KDBUS_MSG_FDS;
118         memcpy((*d)->fds, fds, sizeof(int) * n_fds);
119
120         *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
121 }
122
123 static int bus_message_setup_bloom(sd_bus_message *m, void *bloom) {
124         unsigned i;
125         int r;
126
127         assert(m);
128         assert(bloom);
129
130         memset(bloom, 0, BLOOM_SIZE);
131
132         bloom_add_pair(bloom, "message-type", bus_message_type_to_string(m->header->type));
133
134         if (m->interface)
135                 bloom_add_pair(bloom, "interface", m->interface);
136         if (m->member)
137                 bloom_add_pair(bloom, "member", m->member);
138         if (m->path) {
139                 bloom_add_pair(bloom, "path", m->path);
140                 bloom_add_prefixes(bloom, "path-slash-prefix", m->path, '/');
141         }
142
143         r = sd_bus_message_rewind(m, true);
144         if (r < 0)
145                 return r;
146
147         for (i = 0; i < 64; i++) {
148                 char type;
149                 const char *t;
150                 char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
151                 char *e;
152
153                 r = sd_bus_message_peek_type(m, &type, NULL);
154                 if (r < 0)
155                         return r;
156
157                 if (type != SD_BUS_TYPE_STRING &&
158                     type != SD_BUS_TYPE_OBJECT_PATH &&
159                     type != SD_BUS_TYPE_SIGNATURE)
160                         break;
161
162                 r = sd_bus_message_read_basic(m, type, &t);
163                 if (r < 0)
164                         return r;
165
166                 e = stpcpy(buf, "arg");
167                 if (i < 10)
168                         *(e++) = '0' + i;
169                 else {
170                         *(e++) = '0' + (i / 10);
171                         *(e++) = '0' + (i % 10);
172                 }
173
174                 *e = 0;
175                 bloom_add_pair(bloom, buf, t);
176
177                 strcpy(e, "-dot-prefix");
178                 bloom_add_prefixes(bloom, buf, t, '.');
179                 strcpy(e, "-slash-prefix");
180                 bloom_add_prefixes(bloom, buf, t, '/');
181         }
182
183         return 0;
184 }
185
186 static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) {
187         struct kdbus_item *d;
188         bool well_known;
189         uint64_t unique;
190         size_t sz, dl;
191         int r;
192
193         assert(b);
194         assert(m);
195         assert(m->sealed);
196
197         if (m->kdbus)
198                 return 0;
199
200         if (m->destination) {
201                 r = parse_unique_name(m->destination, &unique);
202                 if (r < 0)
203                         return r;
204
205                 well_known = r == 0;
206         } else
207                 well_known = false;
208
209         sz = offsetof(struct kdbus_msg, items);
210
211         /* Add in fixed header, fields header and payload */
212         sz += 3 * ALIGN8(offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec));
213
214         /* Add space for bloom filter */
215         sz += ALIGN8(offsetof(struct kdbus_item, data) + BLOOM_SIZE);
216
217         /* Add in well-known destination header */
218         if (well_known) {
219                 dl = strlen(m->destination);
220                 sz += ALIGN8(offsetof(struct kdbus_item, str) + dl + 1);
221         }
222
223         /* Add space for unix fds */
224         if (m->n_fds > 0)
225                 sz += ALIGN8(offsetof(struct kdbus_item, fds) + sizeof(int)*m->n_fds);
226
227         m->kdbus = memalign(8, sz);
228         if (!m->kdbus)
229                 return -ENOMEM;
230
231         memset(m->kdbus, 0, sz);
232
233         m->kdbus->flags =
234                 ((m->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED) ? 0 : KDBUS_MSG_FLAGS_EXPECT_REPLY) |
235                 ((m->header->flags & SD_BUS_MESSAGE_NO_AUTO_START) ? KDBUS_MSG_FLAGS_NO_AUTO_START : 0);
236         m->kdbus->dst_id =
237                 well_known ? 0 :
238                 m->destination ? unique : KDBUS_DST_ID_BROADCAST;
239         m->kdbus->payload_type = KDBUS_PAYLOAD_DBUS1;
240         m->kdbus->cookie = m->header->serial;
241
242         m->kdbus->timeout_ns = m->timeout * NSEC_PER_USEC;
243
244         d = m->kdbus->items;
245
246         if (well_known)
247                 append_destination(&d, m->destination, dl);
248
249         append_payload_vec(&d, m->header, sizeof(*m->header));
250
251         if (m->fields)
252                 append_payload_vec(&d, m->fields, ALIGN8(m->header->fields_size));
253
254         if (m->body)
255                 append_payload_vec(&d, m->body, m->header->body_size);
256
257         if (m->kdbus->dst_id == KDBUS_DST_ID_BROADCAST) {
258                 void *p;
259
260                 p = append_bloom(&d, BLOOM_SIZE);
261                 r = bus_message_setup_bloom(m, p);
262                 if (r < 0) {
263                         free(m->kdbus);
264                         m->kdbus = NULL;
265                         return -r;
266                 }
267         }
268
269         if (m->n_fds > 0)
270                 append_fds(&d, m->fds, m->n_fds);
271
272         m->kdbus->size = (uint8_t*) d - (uint8_t*) m->kdbus;
273         assert(m->kdbus->size <= sz);
274
275         m->free_kdbus = true;
276
277         return 0;
278 }
279
280 int bus_kernel_take_fd(sd_bus *b) {
281         uint8_t h[ALIGN8(sizeof(struct kdbus_cmd_hello)) +
282                   ALIGN8(KDBUS_ITEM_HEADER_SIZE) +
283                   ALIGN8(sizeof(struct kdbus_vec))] = {};
284
285         struct kdbus_cmd_hello *hello = (struct kdbus_cmd_hello*) h;
286
287         int r;
288
289         assert(b);
290
291         if (b->is_server)
292                 return -EINVAL;
293
294         if (!b->kdbus_buffer) {
295                 b->kdbus_buffer = mmap(NULL, KDBUS_POOL_SIZE, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
296                 if (b->kdbus_buffer == MAP_FAILED) {
297                         b->kdbus_buffer = NULL;
298                         return -errno;
299                 }
300         }
301
302         hello->size = sizeof(h);
303         hello->conn_flags =
304                 KDBUS_HELLO_ACCEPT_FD|
305                 KDBUS_HELLO_ATTACH_COMM|
306                 KDBUS_HELLO_ATTACH_EXE|
307                 KDBUS_HELLO_ATTACH_CMDLINE|
308                 KDBUS_HELLO_ATTACH_CGROUP|
309                 KDBUS_HELLO_ATTACH_CAPS|
310                 KDBUS_HELLO_ATTACH_SECLABEL|
311                 KDBUS_HELLO_ATTACH_AUDIT;
312
313         hello->items[0].type = KDBUS_HELLO_POOL;
314         hello->items[0].size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_vec);
315         hello->items[0].vec.address = (uint64_t) b->kdbus_buffer;
316         hello->items[0].vec.size = KDBUS_POOL_SIZE;
317
318         r = ioctl(b->input_fd, KDBUS_CMD_HELLO, hello);
319         if (r < 0)
320                 return -errno;
321
322         /* The higher 32bit of both flags fields are considered
323          * 'incompatible flags'. Refuse them all for now. */
324         if (hello->bus_flags > 0xFFFFFFFFULL ||
325             hello->conn_flags > 0xFFFFFFFFULL)
326                 return -ENOTSUP;
327
328         if (hello->bloom_size != BLOOM_SIZE)
329                 return -ENOTSUP;
330
331         if (asprintf(&b->unique_name, ":1.%llu", (unsigned long long) hello->id) < 0)
332                 return -ENOMEM;
333
334         b->is_kernel = true;
335         b->bus_client = true;
336         b->can_fds = true;
337
338         r = bus_start_running(b);
339         if (r < 0)
340                 return r;
341
342         return 1;
343 }
344
345 int bus_kernel_connect(sd_bus *b) {
346         assert(b);
347         assert(b->input_fd < 0);
348         assert(b->output_fd < 0);
349         assert(b->kernel);
350
351         if (b->is_server)
352                 return -EINVAL;
353
354         b->input_fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC);
355         if (b->input_fd < 0)
356                 return -errno;
357
358         b->output_fd = b->input_fd;
359
360         return bus_kernel_take_fd(b);
361 }
362
363 int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m) {
364         int r;
365
366         assert(bus);
367         assert(m);
368         assert(bus->state == BUS_RUNNING);
369
370         r = bus_message_setup_kmsg(bus, m);
371         if (r < 0)
372                 return r;
373
374         r = ioctl(bus->output_fd, KDBUS_CMD_MSG_SEND, m->kdbus);
375         if (r < 0)
376                 return errno == EAGAIN ? 0 : -errno;
377
378         return 1;
379 }
380
381 static void close_kdbus_msg(sd_bus *bus, struct kdbus_msg *k) {
382         struct kdbus_item *d;
383
384         assert(bus);
385         assert(k);
386
387         ioctl(bus->input_fd, KDBUS_CMD_MSG_RELEASE, k);
388
389         KDBUS_ITEM_FOREACH(d, k) {
390
391                 if (d->type != KDBUS_MSG_FDS)
392                         continue;
393
394                 close_many(d->fds, (d->size - offsetof(struct kdbus_item, fds)) / sizeof(int));
395         }
396 }
397
398 static bool range_contains(size_t astart, size_t asize, size_t bstart, size_t bsize, void *a, void **b) {
399
400         if (bstart < astart)
401                 return false;
402
403         if (bstart + bsize > astart + asize)
404                 return false;
405
406         *b = (uint8_t*) a + (bstart - astart);
407
408         return true;
409 }
410
411 static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k, sd_bus_message **ret) {
412         sd_bus_message *m = NULL;
413         struct kdbus_item *d;
414         unsigned n_payload = 0, n_fds = 0;
415         _cleanup_free_ int *fds = NULL;
416         struct bus_header *h = NULL;
417         size_t total, n_bytes = 0, idx = 0;
418         const char *destination = NULL, *seclabel = NULL;
419         int r;
420
421         assert(bus);
422         assert(k);
423         assert(ret);
424
425         if (k->payload_type != KDBUS_PAYLOAD_DBUS1)
426                 return 0;
427
428         KDBUS_ITEM_FOREACH(d, k) {
429                 size_t l;
430
431                 l = d->size - offsetof(struct kdbus_item, data);
432
433                 if (d->type == KDBUS_MSG_PAYLOAD_VEC) {
434
435                         if (!h) {
436                                 if (d->vec.size < sizeof(struct bus_header))
437                                         return -EBADMSG;
438
439                                 h = (struct bus_header*) d->vec.address;
440                         }
441
442                         n_payload++;
443                         n_bytes += d->vec.size;
444
445                 } else if (d->type == KDBUS_MSG_FDS) {
446                         int *f;
447                         unsigned j;
448
449                         j = l / sizeof(int);
450                         f = realloc(fds, sizeof(int) * (n_fds + j));
451                         if (!f)
452                                 return -ENOMEM;
453
454                         fds = f;
455                         memcpy(fds + n_fds, d->fds, sizeof(int) * j);
456                         n_fds += j;
457
458                 } else if (d->type == KDBUS_MSG_DST_NAME)
459                         destination = d->str;
460                 else if (d->type == KDBUS_MSG_SRC_SECLABEL)
461                         seclabel = d->str;
462         }
463
464         if (!h)
465                 return -EBADMSG;
466
467         r = bus_header_size(h, &total);
468         if (r < 0)
469                 return r;
470
471         if (n_bytes != total)
472                 return -EBADMSG;
473
474         if (n_payload > 2)
475                 return -EBADMSG;
476
477         r = bus_message_from_header(h, sizeof(struct bus_header), fds, n_fds, NULL, seclabel, 0, &m);
478         if (r < 0)
479                 return r;
480
481         KDBUS_ITEM_FOREACH(d, k) {
482                 size_t l;
483
484                 l = d->size - offsetof(struct kdbus_item, data);
485
486                 if (d->type == KDBUS_MSG_PAYLOAD_VEC) {
487
488                         range_contains(idx, d->vec.size, ALIGN8(sizeof(struct bus_header)), BUS_MESSAGE_FIELDS_SIZE(m), (void*) d->vec.address, &m->fields);
489                         range_contains(idx, d->vec.size, ALIGN8(sizeof(struct bus_header)) + ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m)), BUS_MESSAGE_BODY_SIZE(m), (void*) d->vec.address, &m->body);
490
491                         idx += d->vec.size;
492
493                 } else if (d->type == KDBUS_MSG_SRC_CREDS) {
494                         m->pid_starttime = d->creds.starttime / NSEC_PER_USEC;
495                         m->uid = d->creds.uid;
496                         m->gid = d->creds.gid;
497                         m->pid = d->creds.pid;
498                         m->tid = d->creds.tid;
499                         m->uid_valid = m->gid_valid = true;
500                 } else if (d->type == KDBUS_MSG_TIMESTAMP) {
501                         m->realtime = d->timestamp.realtime_ns / NSEC_PER_USEC;
502                         m->monotonic = d->timestamp.monotonic_ns / NSEC_PER_USEC;
503                 } else if (d->type == KDBUS_MSG_SRC_PID_COMM)
504                         m->comm = d->str;
505                 else if (d->type == KDBUS_MSG_SRC_TID_COMM)
506                         m->tid_comm = d->str;
507                 else if (d->type == KDBUS_MSG_SRC_EXE)
508                         m->exe = d->str;
509                 else if (d->type == KDBUS_MSG_SRC_CMDLINE) {
510                         m->cmdline = d->str;
511                         m->cmdline_length = l;
512                 } else if (d->type == KDBUS_MSG_SRC_CGROUP)
513                         m->cgroup = d->str;
514                 else if (d->type == KDBUS_MSG_SRC_AUDIT)
515                         m->audit = &d->audit;
516                 else if (d->type == KDBUS_MSG_SRC_CAPS) {
517                         m->capability = d->data;
518                         m->capability_size = l;
519                 } else if (d->type != KDBUS_MSG_FDS &&
520                            d->type != KDBUS_MSG_DST_NAME &&
521                            d->type != KDBUS_MSG_SRC_SECLABEL)
522                         log_debug("Got unknown field from kernel %llu", d->type);
523         }
524
525         if ((BUS_MESSAGE_FIELDS_SIZE(m) > 0 && !m->fields) ||
526             (BUS_MESSAGE_BODY_SIZE(m) > 0 && !m->body)) {
527                 sd_bus_message_unref(m);
528                 return -EBADMSG;
529         }
530
531         r = bus_message_parse_fields(m);
532         if (r < 0) {
533                 sd_bus_message_unref(m);
534                 return r;
535         }
536
537         if (k->src_id == KDBUS_SRC_ID_KERNEL)
538                 m->sender = "org.freedesktop.DBus";
539         else {
540                 snprintf(m->sender_buffer, sizeof(m->sender_buffer), ":1.%llu", (unsigned long long) k->src_id);
541                 m->sender = m->sender_buffer;
542         }
543
544         if (!m->destination) {
545                 if (destination)
546                         m->destination = destination;
547                 else if (k->dst_id != KDBUS_DST_ID_WELL_KNOWN_NAME &&
548                          k->dst_id != KDBUS_DST_ID_BROADCAST) {
549                         snprintf(m->destination_buffer, sizeof(m->destination_buffer), ":1.%llu", (unsigned long long) k->dst_id);
550                         m->destination = m->destination_buffer;
551                 }
552         }
553
554         /* We take possession of the kmsg struct now */
555         m->kdbus = k;
556         m->bus = sd_bus_ref(bus);
557         m->release_kdbus = true;
558         m->free_fds = true;
559
560         fds = NULL;
561
562         *ret = m;
563         return 1;
564 }
565
566 int bus_kernel_read_message(sd_bus *bus, sd_bus_message **m) {
567         struct kdbus_msg *k;
568         int r;
569
570         assert(bus);
571         assert(m);
572
573         r = ioctl(bus->input_fd, KDBUS_CMD_MSG_RECV, &k);
574         if (r < 0) {
575                 if (errno == EAGAIN)
576                         return 0;
577
578                 return -errno;
579         }
580
581
582 /*                 /\* Let's tell valgrind that there's really no need to */
583 /*                  * initialize this fully. This should be removed again */
584 /*                  * when valgrind learned the kdbus ioctls natively. *\/ */
585 /* #ifdef HAVE_VALGRIND_MEMCHECK_H */
586 /*                 VALGRIND_MAKE_MEM_DEFINED(k, sz); */
587 /* #endif */
588
589
590         r = bus_kernel_make_message(bus, k, m);
591         if (r <= 0)
592                 close_kdbus_msg(bus, k);
593
594         return r < 0 ? r : 1;
595 }
596
597 int bus_kernel_create(const char *name, char **s) {
598         struct kdbus_cmd_bus_make *make;
599         struct kdbus_item *n, *cg;
600         size_t l;
601         int fd;
602         char *p;
603
604         assert(name);
605         assert(s);
606
607         fd = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
608         if (fd < 0)
609                 return -errno;
610
611         l = strlen(name);
612         make = alloca0(offsetof(struct kdbus_cmd_bus_make, items) +
613                        KDBUS_ITEM_HEADER_SIZE + sizeof(uint64_t) +
614                        KDBUS_ITEM_HEADER_SIZE + DECIMAL_STR_MAX(uid_t) + 1 + l + 1);
615
616         cg = make->items;
617         cg->type = KDBUS_MAKE_CGROUP;
618         cg->data64[0] = 1;
619         cg->size = KDBUS_ITEM_HEADER_SIZE + sizeof(uint64_t);
620
621         n = KDBUS_ITEM_NEXT(cg);
622         n->type = KDBUS_MAKE_NAME;
623         sprintf(n->str, "%lu-%s", (unsigned long) getuid(), name);
624         n->size = KDBUS_ITEM_HEADER_SIZE + strlen(n->str) + 1;
625
626         make->size = offsetof(struct kdbus_cmd_bus_make, items) + cg->size + n->size;
627         make->flags = KDBUS_MAKE_ACCESS_WORLD | KDBUS_MAKE_POLICY_OPEN;
628         make->bus_flags = 0;
629         make->bloom_size = BLOOM_SIZE;
630         assert_cc(BLOOM_SIZE % 8 == 0);
631
632         p = strjoin("/dev/kdbus/", n->str, "/bus", NULL);
633         if (!p)
634                 return -ENOMEM;
635
636         if (ioctl(fd, KDBUS_CMD_BUS_MAKE, make) < 0) {
637                 close_nointr_nofail(fd);
638                 free(p);
639                 return -errno;
640         }
641
642         if (s)
643                 *s = p;
644
645         return fd;
646 }