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