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