chiark / gitweb /
kdbus: update kdbus.h from upstream
[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 = (intptr_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_HELLO_ACCEPT_FD|
278                         KDBUS_HELLO_ATTACH_COMM|
279                         KDBUS_HELLO_ATTACH_EXE|
280                         KDBUS_HELLO_ATTACH_CMDLINE|
281                         KDBUS_HELLO_ATTACH_CGROUP|
282                         KDBUS_HELLO_ATTACH_CAPS|
283                         KDBUS_HELLO_ATTACH_SECLABEL|
284                         KDBUS_HELLO_ATTACH_AUDIT
285         };
286         int r;
287
288         assert(b);
289
290         if (b->is_server)
291                 return -EINVAL;
292
293         r = ioctl(b->input_fd, KDBUS_CMD_HELLO, &hello);
294         if (r < 0)
295                 return -errno;
296
297         /* The higher 32bit of both flags fields are considered
298          * 'incompatible flags'. Refuse them all for now. */
299         if (hello.bus_flags > 0xFFFFFFFFULL ||
300             hello.conn_flags > 0xFFFFFFFFULL)
301                 return -ENOTSUP;
302
303         if (hello.bloom_size != BLOOM_SIZE)
304                 return -ENOTSUP;
305
306         if (asprintf(&b->unique_name, ":1.%llu", (unsigned long long) hello.id) < 0)
307                 return -ENOMEM;
308
309         b->is_kernel = true;
310         b->bus_client = true;
311         b->can_fds = true;
312
313         r = bus_start_running(b);
314         if (r < 0)
315                 return r;
316
317         return 1;
318 }
319
320 int bus_kernel_connect(sd_bus *b) {
321         assert(b);
322         assert(b->input_fd < 0);
323         assert(b->output_fd < 0);
324         assert(b->kernel);
325
326         if (b->is_server)
327                 return -EINVAL;
328
329         b->input_fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC);
330         if (b->input_fd < 0)
331                 return -errno;
332
333         b->output_fd = b->input_fd;
334
335         return bus_kernel_take_fd(b);
336 }
337
338 int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m) {
339         int r;
340
341         assert(bus);
342         assert(m);
343         assert(bus->state == BUS_RUNNING);
344
345         r = bus_message_setup_kmsg(bus, m);
346         if (r < 0)
347                 return r;
348
349         r = ioctl(bus->output_fd, KDBUS_CMD_MSG_SEND, m->kdbus);
350         if (r < 0)
351                 return errno == EAGAIN ? 0 : -errno;
352
353         return 1;
354 }
355
356 static void close_kdbus_msg(struct kdbus_msg *k) {
357         struct kdbus_msg_item *d;
358
359         KDBUS_ITEM_FOREACH(d, k) {
360
361                 if (d->type != KDBUS_MSG_UNIX_FDS)
362                         continue;
363
364                 close_many(d->fds, (d->size - offsetof(struct kdbus_msg_item, fds)) / sizeof(int));
365         }
366 }
367
368 static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k, sd_bus_message **ret) {
369         sd_bus_message *m = NULL;
370         struct kdbus_msg_item *d;
371         unsigned n_payload = 0, n_fds = 0;
372         _cleanup_free_ int *fds = NULL;
373         struct bus_header *h = NULL;
374         size_t total, n_bytes = 0, idx = 0;
375         const char *destination = NULL, *seclabel = NULL;
376         int r;
377
378         assert(bus);
379         assert(k);
380         assert(ret);
381
382         if (k->payload_type != KDBUS_PAYLOAD_DBUS1)
383                 return 0;
384
385         KDBUS_ITEM_FOREACH(d, k) {
386                 size_t l;
387
388                 l = d->size - offsetof(struct kdbus_msg_item, data);
389
390                 if (d->type == KDBUS_MSG_PAYLOAD) {
391
392                         if (!h) {
393                                 if (l < sizeof(struct bus_header))
394                                         return -EBADMSG;
395
396                                 h = (struct bus_header*) d->data;
397                         }
398
399                         n_payload++;
400                         n_bytes += l;
401
402                 } else if (d->type == KDBUS_MSG_UNIX_FDS) {
403                         int *f;
404                         unsigned j;
405
406                         j = l / sizeof(int);
407                         f = realloc(fds, sizeof(int) * (n_fds + j));
408                         if (!f)
409                                 return -ENOMEM;
410
411                         fds = f;
412                         memcpy(fds + n_fds, d->fds, sizeof(int) * j);
413                         n_fds += j;
414
415                 } else if (d->type == KDBUS_MSG_DST_NAME)
416                         destination = d->str;
417                 else if (d->type == KDBUS_MSG_SRC_SECLABEL)
418                         seclabel = d->str;
419         }
420
421         if (!h)
422                 return -EBADMSG;
423
424         r = bus_header_size(h, &total);
425         if (r < 0)
426                 return r;
427
428         if (n_bytes != total)
429                 return -EBADMSG;
430
431         r = bus_message_from_header(h, sizeof(struct bus_header), fds, n_fds, NULL, seclabel, 0, &m);
432         if (r < 0)
433                 return r;
434
435         KDBUS_ITEM_FOREACH(d, k) {
436                 size_t l;
437
438                 l = d->size - offsetof(struct kdbus_msg_item, data);
439
440                 if (d->type == KDBUS_MSG_PAYLOAD) {
441
442                         if (idx == sizeof(struct bus_header) &&
443                             l == ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m)))
444                                 m->fields = d->data;
445                         else if (idx == sizeof(struct bus_header) + ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m)) &&
446                                  l == BUS_MESSAGE_BODY_SIZE(m))
447                                 m->body = d->data;
448                         else if (!(idx == 0 && l == sizeof(struct bus_header))) {
449                                 sd_bus_message_unref(m);
450                                 return -EBADMSG;
451                         }
452
453                         idx += l;
454                 } else if (d->type == KDBUS_MSG_SRC_CREDS) {
455                         m->pid_starttime = d->creds.starttime / NSEC_PER_USEC;
456                         m->uid = d->creds.uid;
457                         m->gid = d->creds.gid;
458                         m->pid = d->creds.pid;
459                         m->tid = d->creds.tid;
460                         m->uid_valid = m->gid_valid = true;
461                 } else if (d->type == KDBUS_MSG_TIMESTAMP) {
462                         m->realtime = d->timestamp.realtime_ns / NSEC_PER_USEC;
463                         m->monotonic = d->timestamp.monotonic_ns / NSEC_PER_USEC;
464                 } else if (d->type == KDBUS_MSG_SRC_PID_COMM)
465                         m->comm = d->str;
466                 else if (d->type == KDBUS_MSG_SRC_TID_COMM)
467                         m->tid_comm = d->str;
468                 else if (d->type == KDBUS_MSG_SRC_EXE)
469                         m->exe = d->str;
470                 else if (d->type == KDBUS_MSG_SRC_CMDLINE) {
471                         m->cmdline = d->str;
472                         m->cmdline_length = l;
473                 } else if (d->type == KDBUS_MSG_SRC_CGROUP)
474                         m->cgroup = d->str;
475                 else if (d->type == KDBUS_MSG_SRC_AUDIT)
476                         m->audit = &d->audit;
477                 else if (d->type == KDBUS_MSG_SRC_CAPS) {
478                         m->capability = d->data;
479                         m->capability_size = l;
480                 } else
481                         log_debug("Got unknown field from kernel %llu", d->type);
482         }
483
484         r = bus_message_parse_fields(m);
485         if (r < 0) {
486                 sd_bus_message_unref(m);
487                 return r;
488         }
489
490         if (k->src_id == KDBUS_SRC_ID_KERNEL)
491                 m->sender = "org.freedesktop.DBus";
492         else {
493                 snprintf(m->sender_buffer, sizeof(m->sender_buffer), ":1.%llu", (unsigned long long) k->src_id);
494                 m->sender = m->sender_buffer;
495         }
496
497         if (!m->destination) {
498                 if (destination)
499                         m->destination = destination;
500                 else if (k->dst_id != KDBUS_DST_ID_WELL_KNOWN_NAME &&
501                          k->dst_id != KDBUS_DST_ID_BROADCAST) {
502                         snprintf(m->destination_buffer, sizeof(m->destination_buffer), ":1.%llu", (unsigned long long) k->dst_id);
503                         m->destination = m->destination_buffer;
504                 }
505         }
506
507         /* We take possession of the kmsg struct now */
508         m->kdbus = k;
509         m->free_kdbus = true;
510         m->free_fds = true;
511
512         fds = NULL;
513
514         *ret = m;
515         return 1;
516 }
517
518 int bus_kernel_read_message(sd_bus *bus, sd_bus_message **m) {
519         struct kdbus_msg *k;
520         size_t sz = 1024;
521         int r;
522
523         assert(bus);
524         assert(m);
525
526         for (;;) {
527                 void *q;
528
529                 q = memalign(8, sz);
530                 if (!q)
531                         return -errno;
532
533                 free(bus->rbuffer);
534                 k = bus->rbuffer = q;
535                 k->size = sz;
536
537                 /* Let's tell valgrind that there's really no need to
538                  * initialize this fully. This should be removed again
539                  * when valgrind learned the kdbus ioctls natively. */
540 #ifdef HAVE_VALGRIND_MEMCHECK_H
541                 VALGRIND_MAKE_MEM_DEFINED(k, sz);
542 #endif
543
544                 r = ioctl(bus->input_fd, KDBUS_CMD_MSG_RECV, bus->rbuffer);
545                 if (r >= 0)
546                         break;
547
548                 if (errno == EAGAIN)
549                         return 0;
550
551                 if (errno != ENOBUFS)
552                         return -errno;
553
554                 sz *= 2;
555         }
556
557         r = bus_kernel_make_message(bus, k, m);
558         if (r > 0)
559                 bus->rbuffer = NULL;
560         else
561                 close_kdbus_msg(k);
562
563         return r < 0 ? r : 1;
564 }
565
566 int bus_kernel_create(const char *name, char **s) {
567         struct kdbus_cmd_bus_make *make;
568         struct kdbus_cmd_make_item *n, *cg;
569         size_t l;
570         int fd;
571         char *p;
572
573         assert(name);
574         assert(s);
575
576         fd = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
577         if (fd < 0)
578                 return -errno;
579
580         l = strlen(name);
581         make = alloca0(offsetof(struct kdbus_cmd_bus_make, items) +
582                        sizeof(struct kdbus_cmd_make_item) + sizeof(uint64_t) +
583                        sizeof(struct kdbus_cmd_make_item) + DECIMAL_STR_MAX(uid_t) + 1 + l + 1);
584
585         cg = make->items;
586         cg->type = KDBUS_MAKE_CGROUP;
587         cg->data64[0] = 1;
588         cg->size = sizeof(struct kdbus_cmd_make_item) + sizeof(uint64_t);
589
590         n = KDBUS_ITEM_NEXT(cg);
591         n->type = KDBUS_MAKE_NAME;
592         sprintf(n->str, "%lu-%s", (unsigned long) getuid(), name);
593         n->size = sizeof(struct kdbus_cmd_make_item) + strlen(n->str) + 1;
594
595         make->size = offsetof(struct kdbus_cmd_bus_make, items) + cg->size + n->size;
596         make->flags = KDBUS_MAKE_ACCESS_WORLD | KDBUS_MAKE_POLICY_OPEN;
597         make->bus_flags = 0;
598         make->bloom_size = BLOOM_SIZE;
599         assert_cc(BLOOM_SIZE % 8 == 0);
600
601         p = strjoin("/dev/kdbus/", n->str, "/bus", NULL);
602         if (!p)
603                 return -ENOMEM;
604
605         if (ioctl(fd, KDBUS_CMD_BUS_MAKE, make) < 0) {
606                 close_nointr_nofail(fd);
607                 free(p);
608                 return -errno;
609         }
610
611         if (s)
612                 *s = p;
613
614         return fd;
615 }