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