chiark / gitweb /
f36f60e496edfe03df8cfa1de18aacbf9c4a7431
[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
451                         log_debug("Got unknown field from kernel %llu", d->type);
452         }
453
454         r = bus_message_parse_fields(m);
455         if (r < 0) {
456                 sd_bus_message_unref(m);
457                 return r;
458         }
459
460         if (k->src_id == KDBUS_SRC_ID_KERNEL)
461                 m->sender = "org.freedesktop.DBus";
462         else {
463                 snprintf(m->sender_buffer, sizeof(m->sender_buffer), ":1.%llu", (unsigned long long) k->src_id);
464                 m->sender = m->sender_buffer;
465         }
466
467         if (!m->destination) {
468                 if (destination)
469                         m->destination = destination;
470                 else if (k->dst_id != KDBUS_DST_ID_WELL_KNOWN_NAME &&
471                          k->dst_id != KDBUS_DST_ID_BROADCAST) {
472                         snprintf(m->destination_buffer, sizeof(m->destination_buffer), ":1.%llu", (unsigned long long) k->dst_id);
473                         m->destination = m->destination_buffer;
474                 }
475         }
476
477         /* We take possession of the kmsg struct now */
478         m->kdbus = k;
479         m->free_kdbus = true;
480         m->free_fds = true;
481
482         fds = NULL;
483
484         *ret = m;
485         return 1;
486 }
487
488 int bus_kernel_read_message(sd_bus *bus, sd_bus_message **m) {
489         struct kdbus_msg *k;
490         size_t sz = 1024;
491         int r;
492
493         assert(bus);
494         assert(m);
495
496         for (;;) {
497                 void *q;
498
499                 q = aligned_alloc(8, sz);
500                 if (!q)
501                         return -errno;
502
503                 free(bus->rbuffer);
504                 k = bus->rbuffer = q;
505                 k->size = sz;
506
507                 /* Let's tell valgrind that there's really no need to
508                  * initialize this fully. This should be removed again
509                  * when valgrind learned the kdbus ioctls natively. */
510 #ifdef HAVE_VALGRIND_MEMCHECK_H
511                 VALGRIND_MAKE_MEM_DEFINED(k, sz);
512 #endif
513
514                 r = ioctl(bus->input_fd, KDBUS_CMD_MSG_RECV, bus->rbuffer);
515                 if (r >= 0)
516                         break;
517
518                 if (errno == EAGAIN)
519                         return 0;
520
521                 if (errno != ENOBUFS)
522                         return -errno;
523
524                 sz *= 2;
525         }
526
527         r = bus_kernel_make_message(bus, k, m);
528         if (r > 0)
529                 bus->rbuffer = NULL;
530         else
531                 close_kdbus_msg(k);
532
533         return r < 0 ? r : 1;
534 }
535
536 int bus_kernel_create(const char *name, char **s) {
537         struct kdbus_cmd_bus_make *make;
538         size_t l;
539         int fd;
540         char *p;
541
542         assert(name);
543         assert(s);
544
545         fd = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
546         if (fd < 0)
547                 return -errno;
548
549         l = strlen(name);
550         make = alloca0(offsetof(struct kdbus_cmd_bus_make, name) + DECIMAL_STR_MAX(uid_t) + 1 + l + 1);
551         sprintf(make->name, "%lu-%s", (unsigned long) getuid(), name);
552         make->size = offsetof(struct kdbus_cmd_bus_make, name) + strlen(make->name) + 1;
553         make->flags = KDBUS_ACCESS_WORLD | KDBUS_POLICY_OPEN;
554         make->bus_flags = 0;
555         make->bloom_size = BLOOM_SIZE;
556
557         assert_cc(BLOOM_SIZE % 8 == 0);
558
559         p = strjoin("/dev/kdbus/", make->name, "/bus", NULL);
560         if (!p)
561                 return -ENOMEM;
562
563         if (ioctl(fd, KDBUS_CMD_BUS_MAKE, make) < 0) {
564                 close_nointr_nofail(fd);
565                 free(p);
566                 return -errno;
567         }
568
569         if (s)
570                 *s = p;
571
572         return fd;
573 }