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