chiark / gitweb /
e329b14be819d43f16cc5287ba97cb10ab7367ac
[elogind.git] / src / libsystemd-bus / bus-kernel.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #ifdef HAVE_VALGRIND_MEMCHECK_H
23 #include <valgrind/memcheck.h>
24 #endif
25
26 #include <fcntl.h>
27 #include <malloc.h>
28 #include <sys/mman.h>
29
30 #include "util.h"
31
32 #include "bus-internal.h"
33 #include "bus-message.h"
34 #include "bus-kernel.h"
35 #include "bus-bloom.h"
36
37 #define KDBUS_ITEM_NEXT(item) \
38         (typeof(item))(((uint8_t *)item) + ALIGN8((item)->size))
39
40 #define KDBUS_ITEM_FOREACH(item, head)                                          \
41         for (item = (head)->items;                                              \
42              (uint8_t *)(item) < (uint8_t *)(head) + (head)->size;              \
43              item = KDBUS_ITEM_NEXT(item))
44
45 #define KDBUS_ITEM_HEADER_SIZE offsetof(struct kdbus_item, data)
46 #define KDBUS_ITEM_SIZE(s) ALIGN8((s) + KDBUS_ITEM_HEADER_SIZE)
47
48 #define KDBUS_POOL_SIZE (4*1024*1024)
49
50 static int parse_unique_name(const char *s, uint64_t *id) {
51         int r;
52
53         assert(s);
54         assert(id);
55
56         if (!startswith(s, ":1."))
57                 return 0;
58
59         r = safe_atou64(s + 3, id);
60         if (r < 0)
61                 return r;
62
63         return 1;
64 }
65
66 static void append_payload_vec(struct kdbus_item **d, const void *p, size_t sz) {
67         assert(d);
68         assert(p);
69         assert(sz > 0);
70
71         *d = ALIGN8_PTR(*d);
72
73         (*d)->size = offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec);
74         (*d)->type = KDBUS_MSG_PAYLOAD_VEC;
75         (*d)->vec.address = (uint64_t) p;
76         (*d)->vec.size = sz;
77
78         *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
79 }
80
81 static void append_destination(struct kdbus_item **d, const char *s, size_t length) {
82         assert(d);
83         assert(s);
84
85         *d = ALIGN8_PTR(*d);
86
87         (*d)->size = offsetof(struct kdbus_item, str) + length + 1;
88         (*d)->type = KDBUS_MSG_DST_NAME;
89         memcpy((*d)->str, s, length + 1);
90
91         *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
92 }
93
94 static void* append_bloom(struct kdbus_item **d, size_t length) {
95         void *r;
96
97         assert(d);
98
99         *d = ALIGN8_PTR(*d);
100
101         (*d)->size = offsetof(struct kdbus_item, data) + length;
102         (*d)->type = KDBUS_MSG_BLOOM;
103         r = (*d)->data;
104
105         *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
106
107         return r;
108 }
109
110 static void append_fds(struct kdbus_item **d, const int fds[], unsigned n_fds) {
111         assert(d);
112         assert(fds);
113         assert(n_fds > 0);
114
115         *d = ALIGN8_PTR(*d);
116         (*d)->size = offsetof(struct kdbus_item, fds) + sizeof(int) * n_fds;
117         (*d)->type = KDBUS_MSG_FDS;
118         memcpy((*d)->fds, fds, sizeof(int) * n_fds);
119
120         *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
121 }
122
123 static int bus_message_setup_bloom(sd_bus_message *m, void *bloom) {
124         unsigned i;
125         int r;
126
127         assert(m);
128         assert(bloom);
129
130         memset(bloom, 0, BLOOM_SIZE);
131
132         bloom_add_pair(bloom, "message-type", bus_message_type_to_string(m->header->type));
133
134         if (m->interface)
135                 bloom_add_pair(bloom, "interface", m->interface);
136         if (m->member)
137                 bloom_add_pair(bloom, "member", m->member);
138         if (m->path) {
139                 bloom_add_pair(bloom, "path", m->path);
140                 bloom_add_prefixes(bloom, "path-slash-prefix", m->path, '/');
141         }
142
143         r = sd_bus_message_rewind(m, true);
144         if (r < 0)
145                 return r;
146
147         for (i = 0; i < 64; i++) {
148                 char type;
149                 const char *t;
150                 char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
151                 char *e;
152
153                 r = sd_bus_message_peek_type(m, &type, NULL);
154                 if (r < 0)
155                         return r;
156
157                 if (type != SD_BUS_TYPE_STRING &&
158                     type != SD_BUS_TYPE_OBJECT_PATH &&
159                     type != SD_BUS_TYPE_SIGNATURE)
160                         break;
161
162                 r = sd_bus_message_read_basic(m, type, &t);
163                 if (r < 0)
164                         return r;
165
166                 e = stpcpy(buf, "arg");
167                 if (i < 10)
168                         *(e++) = '0' + i;
169                 else {
170                         *(e++) = '0' + (i / 10);
171                         *(e++) = '0' + (i % 10);
172                 }
173
174                 *e = 0;
175                 bloom_add_pair(bloom, buf, t);
176
177                 strcpy(e, "-dot-prefix");
178                 bloom_add_prefixes(bloom, buf, t, '.');
179                 strcpy(e, "-slash-prefix");
180                 bloom_add_prefixes(bloom, buf, t, '/');
181         }
182
183         return 0;
184 }
185
186 static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) {
187         struct 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*)(uintptr_t) 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),
489                                        (void *)(uintptr_t) d->vec.address, &m->fields);
490                         range_contains(idx, d->vec.size, ALIGN8(sizeof(struct bus_header)) + ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m)),
491                                        BUS_MESSAGE_BODY_SIZE(m), (void *)(uintptr_t) d->vec.address, &m->body);
492
493                         idx += d->vec.size;
494
495                 } else if (d->type == KDBUS_MSG_SRC_CREDS) {
496                         m->pid_starttime = d->creds.starttime / NSEC_PER_USEC;
497                         m->uid = d->creds.uid;
498                         m->gid = d->creds.gid;
499                         m->pid = d->creds.pid;
500                         m->tid = d->creds.tid;
501                         m->uid_valid = m->gid_valid = true;
502                 } else if (d->type == KDBUS_MSG_TIMESTAMP) {
503                         m->realtime = d->timestamp.realtime_ns / NSEC_PER_USEC;
504                         m->monotonic = d->timestamp.monotonic_ns / NSEC_PER_USEC;
505                 } else if (d->type == KDBUS_MSG_SRC_PID_COMM)
506                         m->comm = d->str;
507                 else if (d->type == KDBUS_MSG_SRC_TID_COMM)
508                         m->tid_comm = d->str;
509                 else if (d->type == KDBUS_MSG_SRC_EXE)
510                         m->exe = d->str;
511                 else if (d->type == KDBUS_MSG_SRC_CMDLINE) {
512                         m->cmdline = d->str;
513                         m->cmdline_length = l;
514                 } else if (d->type == KDBUS_MSG_SRC_CGROUP)
515                         m->cgroup = d->str;
516                 else if (d->type == KDBUS_MSG_SRC_AUDIT)
517                         m->audit = &d->audit;
518                 else if (d->type == KDBUS_MSG_SRC_CAPS) {
519                         m->capability = d->data;
520                         m->capability_size = l;
521                 } else if (d->type != KDBUS_MSG_FDS &&
522                            d->type != KDBUS_MSG_DST_NAME &&
523                            d->type != KDBUS_MSG_SRC_SECLABEL)
524                         log_debug("Got unknown field from kernel %llu", d->type);
525         }
526
527         if ((BUS_MESSAGE_FIELDS_SIZE(m) > 0 && !m->fields) ||
528             (BUS_MESSAGE_BODY_SIZE(m) > 0 && !m->body)) {
529                 sd_bus_message_unref(m);
530                 return -EBADMSG;
531         }
532
533         r = bus_message_parse_fields(m);
534         if (r < 0) {
535                 sd_bus_message_unref(m);
536                 return r;
537         }
538
539         if (k->src_id == KDBUS_SRC_ID_KERNEL)
540                 m->sender = "org.freedesktop.DBus";
541         else {
542                 snprintf(m->sender_buffer, sizeof(m->sender_buffer), ":1.%llu", (unsigned long long) k->src_id);
543                 m->sender = m->sender_buffer;
544         }
545
546         if (!m->destination) {
547                 if (destination)
548                         m->destination = destination;
549                 else if (k->dst_id != KDBUS_DST_ID_WELL_KNOWN_NAME &&
550                          k->dst_id != KDBUS_DST_ID_BROADCAST) {
551                         snprintf(m->destination_buffer, sizeof(m->destination_buffer), ":1.%llu", (unsigned long long) k->dst_id);
552                         m->destination = m->destination_buffer;
553                 }
554         }
555
556         /* We take possession of the kmsg struct now */
557         m->kdbus = k;
558         m->bus = sd_bus_ref(bus);
559         m->release_kdbus = true;
560         m->free_fds = true;
561
562         fds = NULL;
563
564         *ret = m;
565         return 1;
566 }
567
568 int bus_kernel_read_message(sd_bus *bus, sd_bus_message **m) {
569         struct kdbus_msg *k;
570         int r;
571
572         assert(bus);
573         assert(m);
574
575         r = ioctl(bus->input_fd, KDBUS_CMD_MSG_RECV, &k);
576         if (r < 0) {
577                 if (errno == EAGAIN)
578                         return 0;
579
580                 return -errno;
581         }
582
583
584 /*                 /\* Let's tell valgrind that there's really no need to */
585 /*                  * initialize this fully. This should be removed again */
586 /*                  * when valgrind learned the kdbus ioctls natively. *\/ */
587 /* #ifdef HAVE_VALGRIND_MEMCHECK_H */
588 /*                 VALGRIND_MAKE_MEM_DEFINED(k, sz); */
589 /* #endif */
590
591
592         r = bus_kernel_make_message(bus, k, m);
593         if (r <= 0)
594                 close_kdbus_msg(bus, k);
595
596         return r < 0 ? r : 1;
597 }
598
599 int bus_kernel_create(const char *name, char **s) {
600         struct kdbus_cmd_bus_make *make;
601         struct kdbus_item *n, *cg;
602         size_t l;
603         int fd;
604         char *p;
605
606         assert(name);
607         assert(s);
608
609         fd = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
610         if (fd < 0)
611                 return -errno;
612
613         l = strlen(name);
614         make = alloca0(offsetof(struct kdbus_cmd_bus_make, items) +
615                        KDBUS_ITEM_HEADER_SIZE + sizeof(uint64_t) +
616                        KDBUS_ITEM_HEADER_SIZE + DECIMAL_STR_MAX(uid_t) + 1 + l + 1);
617
618         cg = make->items;
619         cg->type = KDBUS_MAKE_CGROUP;
620         cg->data64[0] = 1;
621         cg->size = KDBUS_ITEM_HEADER_SIZE + sizeof(uint64_t);
622
623         n = KDBUS_ITEM_NEXT(cg);
624         n->type = KDBUS_MAKE_NAME;
625         sprintf(n->str, "%lu-%s", (unsigned long) getuid(), name);
626         n->size = KDBUS_ITEM_HEADER_SIZE + strlen(n->str) + 1;
627
628         make->size = offsetof(struct kdbus_cmd_bus_make, items) + cg->size + n->size;
629         make->flags = KDBUS_MAKE_POLICY_OPEN;
630         make->bus_flags = 0;
631         make->bloom_size = BLOOM_SIZE;
632         assert_cc(BLOOM_SIZE % 8 == 0);
633
634         p = strjoin("/dev/kdbus/", n->str, "/bus", NULL);
635         if (!p)
636                 return -ENOMEM;
637
638         if (ioctl(fd, KDBUS_CMD_BUS_MAKE, make) < 0) {
639                 close_nointr_nofail(fd);
640                 free(p);
641                 return -errno;
642         }
643
644         if (s)
645                 *s = p;
646
647         return fd;
648 }