chiark / gitweb /
bus: implement client logic for fd passing
[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
477                         log_debug("Got unknown field from kernel %llu", d->type);
478         }
479
480         r = bus_message_parse_fields(m);
481         if (r < 0) {
482                 sd_bus_message_unref(m);
483                 return r;
484         }
485
486         if (k->src_id == KDBUS_SRC_ID_KERNEL)
487                 m->sender = "org.freedesktop.DBus";
488         else {
489                 snprintf(m->sender_buffer, sizeof(m->sender_buffer), ":1.%llu", (unsigned long long) k->src_id);
490                 m->sender = m->sender_buffer;
491         }
492
493         if (!m->destination) {
494                 if (destination)
495                         m->destination = destination;
496                 else if (k->dst_id != KDBUS_DST_ID_WELL_KNOWN_NAME &&
497                          k->dst_id != KDBUS_DST_ID_BROADCAST) {
498                         snprintf(m->destination_buffer, sizeof(m->destination_buffer), ":1.%llu", (unsigned long long) k->dst_id);
499                         m->destination = m->destination_buffer;
500                 }
501         }
502
503         /* We take possession of the kmsg struct now */
504         m->kdbus = k;
505         m->free_kdbus = true;
506         m->free_fds = true;
507
508         fds = NULL;
509
510         *ret = m;
511         return 1;
512 }
513
514 int bus_kernel_read_message(sd_bus *bus, sd_bus_message **m) {
515         struct kdbus_msg *k;
516         size_t sz = 1024;
517         int r;
518
519         assert(bus);
520         assert(m);
521
522         for (;;) {
523                 void *q;
524
525                 q = memalign(8, sz);
526                 if (!q)
527                         return -errno;
528
529                 free(bus->rbuffer);
530                 k = bus->rbuffer = q;
531                 k->size = sz;
532
533                 /* Let's tell valgrind that there's really no need to
534                  * initialize this fully. This should be removed again
535                  * when valgrind learned the kdbus ioctls natively. */
536 #ifdef HAVE_VALGRIND_MEMCHECK_H
537                 VALGRIND_MAKE_MEM_DEFINED(k, sz);
538 #endif
539
540                 r = ioctl(bus->input_fd, KDBUS_CMD_MSG_RECV, bus->rbuffer);
541                 if (r >= 0)
542                         break;
543
544                 if (errno == EAGAIN)
545                         return 0;
546
547                 if (errno != ENOBUFS)
548                         return -errno;
549
550                 sz *= 2;
551         }
552
553         r = bus_kernel_make_message(bus, k, m);
554         if (r > 0)
555                 bus->rbuffer = NULL;
556         else
557                 close_kdbus_msg(k);
558
559         return r < 0 ? r : 1;
560 }
561
562 int bus_kernel_create(const char *name, char **s) {
563         struct kdbus_cmd_bus_make *make;
564         struct kdbus_cmd_make_item *n, *cg;
565         size_t l;
566         int fd;
567         char *p;
568
569         assert(name);
570         assert(s);
571
572         fd = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
573         if (fd < 0)
574                 return -errno;
575
576         l = strlen(name);
577         make = alloca0(offsetof(struct kdbus_cmd_bus_make, items) +
578                        sizeof(struct kdbus_cmd_make_item) + sizeof(uint64_t) +
579                        sizeof(struct kdbus_cmd_make_item) + DECIMAL_STR_MAX(uid_t) + 1 + l + 1);
580
581         cg = make->items;
582         cg->type = KDBUS_CMD_MAKE_CGROUP;
583         cg->data64[0] = 1;
584         cg->size = sizeof(struct kdbus_cmd_make_item) + sizeof(uint64_t);
585
586         n = KDBUS_ITEM_NEXT(cg);
587         n->type = KDBUS_CMD_MAKE_NAME;
588         sprintf(n->str, "%lu-%s", (unsigned long) getuid(), name);
589         n->size = sizeof(struct kdbus_cmd_make_item) + strlen(n->str) + 1;
590
591         make->size = offsetof(struct kdbus_cmd_bus_make, items) + cg->size + n->size;
592         make->flags = KDBUS_ACCESS_WORLD | KDBUS_POLICY_OPEN;
593         make->bus_flags = 0;
594         make->bloom_size = BLOOM_SIZE;
595         assert_cc(BLOOM_SIZE % 8 == 0);
596
597         p = strjoin("/dev/kdbus/", n->str, "/bus", NULL);
598         if (!p)
599                 return -ENOMEM;
600
601         if (ioctl(fd, KDBUS_CMD_BUS_MAKE, make) < 0) {
602                 close_nointr_nofail(fd);
603                 free(p);
604                 return -errno;
605         }
606
607         if (s)
608                 *s = p;
609
610         return fd;
611 }