]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd-bus/bus-kernel.c
kdbus: generare bloom filters properly for messages we send
[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
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 }