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