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