]>
Commit | Line | Data |
---|---|---|
6629161f LP |
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 | ||
7211f918 LP |
22 | #ifdef HAVE_VALGRIND_MEMCHECK_H |
23 | #include <valgrind/memcheck.h> | |
24 | #endif | |
25 | ||
6629161f | 26 | #include <fcntl.h> |
c556fe79 | 27 | #include <malloc.h> |
fd8d62d9 | 28 | #include <sys/mman.h> |
6629161f LP |
29 | |
30 | #include "util.h" | |
31 | ||
32 | #include "bus-internal.h" | |
33 | #include "bus-message.h" | |
34 | #include "bus-kernel.h" | |
a56f19c4 | 35 | #include "bus-bloom.h" |
6629161f | 36 | |
6133cee2 KS |
37 | #define KDBUS_ITEM_NEXT(item) \ |
38 | (typeof(item))(((uint8_t *)item) + ALIGN8((item)->size)) | |
9097fe29 | 39 | |
6133cee2 KS |
40 | #define KDBUS_ITEM_FOREACH(item, head) \ |
41 | for (item = (head)->items; \ | |
42 | (uint8_t *)(item) < (uint8_t *)(head) + (head)->size; \ | |
43 | item = KDBUS_ITEM_NEXT(item)) | |
6629161f | 44 | |
febfd508 KS |
45 | #define KDBUS_ITEM_HEADER_SIZE offsetof(struct kdbus_item, data) |
46 | #define KDBUS_ITEM_SIZE(s) ALIGN8((s) + KDBUS_ITEM_HEADER_SIZE) | |
47 | ||
13019ef5 | 48 | #define KDBUS_POOL_SIZE (4*1024*1024) |
fd8d62d9 | 49 | |
6629161f LP |
50 | static int parse_unique_name(const char *s, uint64_t *id) { |
51 | int r; | |
52 | ||
53 | assert(s); | |
54 | assert(id); | |
55 | ||
56 | if (!startswith(s, ":1.")) | |
57 | return 0; | |
58 | ||
59 | r = safe_atou64(s + 3, id); | |
60 | if (r < 0) | |
61 | return r; | |
62 | ||
63 | return 1; | |
64 | } | |
65 | ||
febfd508 | 66 | static void append_payload_vec(struct kdbus_item **d, const void *p, size_t sz) { |
6629161f LP |
67 | assert(d); |
68 | assert(p); | |
69 | assert(sz > 0); | |
70 | ||
e86b80b8 LP |
71 | *d = ALIGN8_PTR(*d); |
72 | ||
febfd508 | 73 | (*d)->size = offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec); |
6629161f | 74 | (*d)->type = KDBUS_MSG_PAYLOAD_VEC; |
18cd014f | 75 | (*d)->vec.address = (uint64_t) p; |
6629161f LP |
76 | (*d)->vec.size = sz; |
77 | ||
febfd508 | 78 | *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size); |
6629161f LP |
79 | } |
80 | ||
febfd508 | 81 | static void append_destination(struct kdbus_item **d, const char *s, size_t length) { |
6629161f | 82 | assert(d); |
b5baa8fe | 83 | assert(s); |
6629161f | 84 | |
e86b80b8 LP |
85 | *d = ALIGN8_PTR(*d); |
86 | ||
febfd508 | 87 | (*d)->size = offsetof(struct kdbus_item, str) + length + 1; |
6629161f | 88 | (*d)->type = KDBUS_MSG_DST_NAME; |
51038c03 | 89 | memcpy((*d)->str, s, length + 1); |
6629161f | 90 | |
febfd508 | 91 | *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size); |
6629161f LP |
92 | } |
93 | ||
febfd508 | 94 | static void* append_bloom(struct kdbus_item **d, size_t length) { |
a56f19c4 LP |
95 | void *r; |
96 | ||
b5baa8fe | 97 | assert(d); |
b5baa8fe LP |
98 | |
99 | *d = ALIGN8_PTR(*d); | |
100 | ||
febfd508 | 101 | (*d)->size = offsetof(struct kdbus_item, data) + length; |
b5baa8fe | 102 | (*d)->type = KDBUS_MSG_BLOOM; |
a56f19c4 | 103 | r = (*d)->data; |
b5baa8fe | 104 | |
febfd508 | 105 | *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size); |
a56f19c4 LP |
106 | |
107 | return r; | |
108 | } | |
109 | ||
febfd508 | 110 | static void append_fds(struct kdbus_item **d, const int fds[], unsigned n_fds) { |
9097fe29 LP |
111 | assert(d); |
112 | assert(fds); | |
113 | assert(n_fds > 0); | |
114 | ||
115 | *d = ALIGN8_PTR(*d); | |
febfd508 | 116 | (*d)->size = offsetof(struct kdbus_item, fds) + sizeof(int) * n_fds; |
fd8d62d9 | 117 | (*d)->type = KDBUS_MSG_FDS; |
9097fe29 LP |
118 | memcpy((*d)->fds, fds, sizeof(int) * n_fds); |
119 | ||
febfd508 | 120 | *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size); |
9097fe29 LP |
121 | } |
122 | ||
a56f19c4 LP |
123 | static int bus_message_setup_bloom(sd_bus_message *m, void *bloom) { |
124 | unsigned i; | |
125 | int r; | |
126 | ||
127 | assert(m); | |
128 | assert(bloom); | |
129 | ||
130 | memset(bloom, 0, BLOOM_SIZE); | |
131 | ||
132 | bloom_add_pair(bloom, "message-type", bus_message_type_to_string(m->header->type)); | |
133 | ||
134 | if (m->interface) | |
135 | bloom_add_pair(bloom, "interface", m->interface); | |
136 | if (m->member) | |
137 | bloom_add_pair(bloom, "member", m->member); | |
138 | if (m->path) { | |
139 | bloom_add_pair(bloom, "path", m->path); | |
140 | bloom_add_prefixes(bloom, "path-slash-prefix", m->path, '/'); | |
141 | } | |
142 | ||
143 | r = sd_bus_message_rewind(m, true); | |
144 | if (r < 0) | |
145 | return r; | |
146 | ||
147 | for (i = 0; i < 64; i++) { | |
148 | char type; | |
149 | const char *t; | |
150 | char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")]; | |
151 | char *e; | |
152 | ||
153 | r = sd_bus_message_peek_type(m, &type, NULL); | |
154 | if (r < 0) | |
155 | return r; | |
156 | ||
157 | if (type != SD_BUS_TYPE_STRING && | |
158 | type != SD_BUS_TYPE_OBJECT_PATH && | |
159 | type != SD_BUS_TYPE_SIGNATURE) | |
160 | break; | |
161 | ||
162 | r = sd_bus_message_read_basic(m, type, &t); | |
163 | if (r < 0) | |
164 | return r; | |
165 | ||
166 | e = stpcpy(buf, "arg"); | |
167 | if (i < 10) | |
168 | *(e++) = '0' + i; | |
169 | else { | |
170 | *(e++) = '0' + (i / 10); | |
171 | *(e++) = '0' + (i % 10); | |
172 | } | |
173 | ||
174 | *e = 0; | |
175 | bloom_add_pair(bloom, buf, t); | |
176 | ||
177 | strcpy(e, "-dot-prefix"); | |
178 | bloom_add_prefixes(bloom, buf, t, '.'); | |
179 | strcpy(e, "-slash-prefix"); | |
180 | bloom_add_prefixes(bloom, buf, t, '/'); | |
181 | } | |
182 | ||
183 | return 0; | |
b5baa8fe LP |
184 | } |
185 | ||
5b7d4c1c | 186 | static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) { |
9b29bb68 | 187 | struct bus_body_part *part; |
febfd508 | 188 | struct kdbus_item *d; |
6629161f LP |
189 | bool well_known; |
190 | uint64_t unique; | |
191 | size_t sz, dl; | |
9b29bb68 | 192 | unsigned i; |
6629161f LP |
193 | int r; |
194 | ||
5b7d4c1c | 195 | assert(b); |
6629161f LP |
196 | assert(m); |
197 | assert(m->sealed); | |
e9a967f9 LP |
198 | |
199 | if (m->kdbus) | |
200 | return 0; | |
6629161f LP |
201 | |
202 | if (m->destination) { | |
203 | r = parse_unique_name(m->destination, &unique); | |
204 | if (r < 0) | |
205 | return r; | |
206 | ||
207 | well_known = r == 0; | |
208 | } else | |
209 | well_known = false; | |
210 | ||
b1454bf0 | 211 | sz = offsetof(struct kdbus_msg, items); |
6629161f | 212 | |
69aec65c | 213 | /* Add in fixed header, fields header and payload */ |
c91cb83c | 214 | sz += (1 + m->n_body_parts) * |
bc7fd8cd | 215 | ALIGN8(offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec)); |
6629161f | 216 | |
69aec65c | 217 | /* Add space for bloom filter */ |
febfd508 | 218 | sz += ALIGN8(offsetof(struct kdbus_item, data) + BLOOM_SIZE); |
b5baa8fe | 219 | |
6629161f LP |
220 | /* Add in well-known destination header */ |
221 | if (well_known) { | |
222 | dl = strlen(m->destination); | |
febfd508 | 223 | sz += ALIGN8(offsetof(struct kdbus_item, str) + dl + 1); |
6629161f LP |
224 | } |
225 | ||
9097fe29 LP |
226 | /* Add space for unix fds */ |
227 | if (m->n_fds > 0) | |
febfd508 | 228 | sz += ALIGN8(offsetof(struct kdbus_item, fds) + sizeof(int)*m->n_fds); |
9097fe29 | 229 | |
c556fe79 | 230 | m->kdbus = memalign(8, sz); |
6629161f LP |
231 | if (!m->kdbus) |
232 | return -ENOMEM; | |
233 | ||
d9115e18 LP |
234 | memset(m->kdbus, 0, sz); |
235 | ||
6629161f LP |
236 | m->kdbus->flags = |
237 | ((m->header->flags & SD_BUS_MESSAGE_NO_REPLY_EXPECTED) ? 0 : KDBUS_MSG_FLAGS_EXPECT_REPLY) | | |
238 | ((m->header->flags & SD_BUS_MESSAGE_NO_AUTO_START) ? KDBUS_MSG_FLAGS_NO_AUTO_START : 0); | |
239 | m->kdbus->dst_id = | |
240 | well_known ? 0 : | |
b5baa8fe | 241 | m->destination ? unique : KDBUS_DST_ID_BROADCAST; |
6629161f LP |
242 | m->kdbus->payload_type = KDBUS_PAYLOAD_DBUS1; |
243 | m->kdbus->cookie = m->header->serial; | |
244 | ||
245 | m->kdbus->timeout_ns = m->timeout * NSEC_PER_USEC; | |
246 | ||
b1454bf0 | 247 | d = m->kdbus->items; |
6629161f LP |
248 | |
249 | if (well_known) | |
250 | append_destination(&d, m->destination, dl); | |
251 | ||
c91cb83c | 252 | append_payload_vec(&d, m->header, BUS_MESSAGE_BODY_BEGIN(m)); |
9b29bb68 | 253 | MESSAGE_FOREACH_PART(part, i, m) |
bc7fd8cd | 254 | append_payload_vec(&d, part->data, part->size); |
6629161f | 255 | |
5b7d4c1c LP |
256 | if (m->kdbus->dst_id == KDBUS_DST_ID_BROADCAST) { |
257 | void *p; | |
258 | ||
a56f19c4 LP |
259 | p = append_bloom(&d, BLOOM_SIZE); |
260 | r = bus_message_setup_bloom(m, p); | |
261 | if (r < 0) { | |
262 | free(m->kdbus); | |
263 | m->kdbus = NULL; | |
264 | return -r; | |
265 | } | |
5b7d4c1c | 266 | } |
b5baa8fe | 267 | |
9097fe29 LP |
268 | if (m->n_fds > 0) |
269 | append_fds(&d, m->fds, m->n_fds); | |
270 | ||
e9a967f9 | 271 | m->kdbus->size = (uint8_t*) d - (uint8_t*) m->kdbus; |
6629161f LP |
272 | assert(m->kdbus->size <= sz); |
273 | ||
e9a967f9 LP |
274 | m->free_kdbus = true; |
275 | ||
6629161f LP |
276 | return 0; |
277 | } | |
278 | ||
279 | int bus_kernel_take_fd(sd_bus *b) { | |
fd8d62d9 LP |
280 | uint8_t h[ALIGN8(sizeof(struct kdbus_cmd_hello)) + |
281 | ALIGN8(KDBUS_ITEM_HEADER_SIZE) + | |
282 | ALIGN8(sizeof(struct kdbus_vec))] = {}; | |
283 | ||
284 | struct kdbus_cmd_hello *hello = (struct kdbus_cmd_hello*) h; | |
285 | ||
6629161f LP |
286 | int r; |
287 | ||
288 | assert(b); | |
289 | ||
f08838da LP |
290 | if (b->is_server) |
291 | return -EINVAL; | |
292 | ||
fd8d62d9 | 293 | if (!b->kdbus_buffer) { |
13019ef5 | 294 | b->kdbus_buffer = mmap(NULL, KDBUS_POOL_SIZE, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); |
fd8d62d9 LP |
295 | if (b->kdbus_buffer == MAP_FAILED) { |
296 | b->kdbus_buffer = NULL; | |
297 | return -errno; | |
298 | } | |
299 | } | |
300 | ||
301 | hello->size = sizeof(h); | |
302 | hello->conn_flags = | |
303 | KDBUS_HELLO_ACCEPT_FD| | |
304 | KDBUS_HELLO_ATTACH_COMM| | |
305 | KDBUS_HELLO_ATTACH_EXE| | |
306 | KDBUS_HELLO_ATTACH_CMDLINE| | |
307 | KDBUS_HELLO_ATTACH_CGROUP| | |
308 | KDBUS_HELLO_ATTACH_CAPS| | |
309 | KDBUS_HELLO_ATTACH_SECLABEL| | |
310 | KDBUS_HELLO_ATTACH_AUDIT; | |
311 | ||
13019ef5 | 312 | hello->items[0].type = KDBUS_HELLO_POOL; |
fd8d62d9 LP |
313 | hello->items[0].size = KDBUS_ITEM_HEADER_SIZE + sizeof(struct kdbus_vec); |
314 | hello->items[0].vec.address = (uint64_t) b->kdbus_buffer; | |
13019ef5 | 315 | hello->items[0].vec.size = KDBUS_POOL_SIZE; |
fd8d62d9 LP |
316 | |
317 | r = ioctl(b->input_fd, KDBUS_CMD_HELLO, hello); | |
6629161f LP |
318 | if (r < 0) |
319 | return -errno; | |
320 | ||
5b7d4c1c LP |
321 | /* The higher 32bit of both flags fields are considered |
322 | * 'incompatible flags'. Refuse them all for now. */ | |
fd8d62d9 LP |
323 | if (hello->bus_flags > 0xFFFFFFFFULL || |
324 | hello->conn_flags > 0xFFFFFFFFULL) | |
5b7d4c1c LP |
325 | return -ENOTSUP; |
326 | ||
fd8d62d9 | 327 | if (hello->bloom_size != BLOOM_SIZE) |
a56f19c4 LP |
328 | return -ENOTSUP; |
329 | ||
fd8d62d9 | 330 | if (asprintf(&b->unique_name, ":1.%llu", (unsigned long long) hello->id) < 0) |
de297575 LP |
331 | return -ENOMEM; |
332 | ||
6629161f | 333 | b->is_kernel = true; |
f08838da | 334 | b->bus_client = true; |
9097fe29 | 335 | b->can_fds = true; |
6629161f LP |
336 | |
337 | r = bus_start_running(b); | |
338 | if (r < 0) | |
339 | return r; | |
340 | ||
341 | return 1; | |
342 | } | |
343 | ||
344 | int bus_kernel_connect(sd_bus *b) { | |
345 | assert(b); | |
346 | assert(b->input_fd < 0); | |
347 | assert(b->output_fd < 0); | |
348 | assert(b->kernel); | |
349 | ||
f08838da LP |
350 | if (b->is_server) |
351 | return -EINVAL; | |
352 | ||
6629161f | 353 | b->input_fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC); |
c320885c | 354 | if (b->input_fd < 0) |
6629161f LP |
355 | return -errno; |
356 | ||
357 | b->output_fd = b->input_fd; | |
358 | ||
359 | return bus_kernel_take_fd(b); | |
360 | } | |
361 | ||
362 | int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m) { | |
363 | int r; | |
364 | ||
365 | assert(bus); | |
366 | assert(m); | |
367 | assert(bus->state == BUS_RUNNING); | |
368 | ||
5b7d4c1c | 369 | r = bus_message_setup_kmsg(bus, m); |
6629161f LP |
370 | if (r < 0) |
371 | return r; | |
372 | ||
373 | r = ioctl(bus->output_fd, KDBUS_CMD_MSG_SEND, m->kdbus); | |
374 | if (r < 0) | |
375 | return errno == EAGAIN ? 0 : -errno; | |
376 | ||
51038c03 | 377 | return 1; |
6629161f LP |
378 | } |
379 | ||
fd8d62d9 | 380 | static void close_kdbus_msg(sd_bus *bus, struct kdbus_msg *k) { |
febfd508 | 381 | struct kdbus_item *d; |
6629161f | 382 | |
fd8d62d9 LP |
383 | assert(bus); |
384 | assert(k); | |
385 | ||
386 | ioctl(bus->input_fd, KDBUS_CMD_MSG_RELEASE, k); | |
387 | ||
6133cee2 | 388 | KDBUS_ITEM_FOREACH(d, k) { |
6629161f | 389 | |
fd8d62d9 | 390 | if (d->type != KDBUS_MSG_FDS) |
6629161f LP |
391 | continue; |
392 | ||
febfd508 | 393 | close_many(d->fds, (d->size - offsetof(struct kdbus_item, fds)) / sizeof(int)); |
6629161f LP |
394 | } |
395 | } | |
396 | ||
397 | static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k, sd_bus_message **ret) { | |
398 | sd_bus_message *m = NULL; | |
febfd508 | 399 | struct kdbus_item *d; |
6629161f LP |
400 | unsigned n_payload = 0, n_fds = 0; |
401 | _cleanup_free_ int *fds = NULL; | |
402 | struct bus_header *h = NULL; | |
403 | size_t total, n_bytes = 0, idx = 0; | |
69aec65c | 404 | const char *destination = NULL, *seclabel = NULL; |
6629161f LP |
405 | int r; |
406 | ||
407 | assert(bus); | |
408 | assert(k); | |
409 | assert(ret); | |
410 | ||
411 | if (k->payload_type != KDBUS_PAYLOAD_DBUS1) | |
412 | return 0; | |
413 | ||
6133cee2 | 414 | KDBUS_ITEM_FOREACH(d, k) { |
6629161f LP |
415 | size_t l; |
416 | ||
febfd508 | 417 | l = d->size - offsetof(struct kdbus_item, data); |
6629161f | 418 | |
fd8d62d9 | 419 | if (d->type == KDBUS_MSG_PAYLOAD_VEC) { |
6629161f LP |
420 | |
421 | if (!h) { | |
9b05bc48 | 422 | h = UINT64_TO_PTR(d->vec.address); |
c91cb83c LP |
423 | |
424 | if (!bus_header_is_complete(h, d->vec.size)) | |
425 | return -EBADMSG; | |
6629161f LP |
426 | } |
427 | ||
428 | n_payload++; | |
fd8d62d9 | 429 | n_bytes += d->vec.size; |
6629161f | 430 | |
fd8d62d9 | 431 | } else if (d->type == KDBUS_MSG_FDS) { |
6629161f LP |
432 | int *f; |
433 | unsigned j; | |
434 | ||
435 | j = l / sizeof(int); | |
436 | f = realloc(fds, sizeof(int) * (n_fds + j)); | |
437 | if (!f) | |
438 | return -ENOMEM; | |
439 | ||
440 | fds = f; | |
9097fe29 | 441 | memcpy(fds + n_fds, d->fds, sizeof(int) * j); |
6629161f | 442 | n_fds += j; |
f9be01f3 | 443 | |
69aec65c | 444 | } else if (d->type == KDBUS_MSG_DST_NAME) |
51038c03 | 445 | destination = d->str; |
69aec65c LP |
446 | else if (d->type == KDBUS_MSG_SRC_SECLABEL) |
447 | seclabel = d->str; | |
6629161f LP |
448 | } |
449 | ||
450 | if (!h) | |
451 | return -EBADMSG; | |
452 | ||
c91cb83c | 453 | r = bus_header_message_size(h, &total); |
6629161f LP |
454 | if (r < 0) |
455 | return r; | |
456 | ||
457 | if (n_bytes != total) | |
458 | return -EBADMSG; | |
459 | ||
69aec65c | 460 | r = bus_message_from_header(h, sizeof(struct bus_header), fds, n_fds, NULL, seclabel, 0, &m); |
6629161f LP |
461 | if (r < 0) |
462 | return r; | |
463 | ||
6133cee2 | 464 | KDBUS_ITEM_FOREACH(d, k) { |
6629161f LP |
465 | size_t l; |
466 | ||
febfd508 | 467 | l = d->size - offsetof(struct kdbus_item, data); |
6629161f | 468 | |
fd8d62d9 | 469 | if (d->type == KDBUS_MSG_PAYLOAD_VEC) { |
bc7fd8cd | 470 | size_t begin_body; |
fd8d62d9 | 471 | |
c91cb83c | 472 | begin_body = BUS_MESSAGE_BODY_BEGIN(m); |
bc7fd8cd LP |
473 | |
474 | if (idx + d->vec.size > begin_body) { | |
475 | struct bus_body_part *part; | |
476 | ||
477 | /* Contains body material */ | |
478 | ||
479 | part = message_append_part(m); | |
480 | if (!part) { | |
481 | sd_bus_message_unref(m); | |
482 | return -ENOMEM; | |
483 | } | |
484 | ||
485 | if (idx >= begin_body) { | |
c91cb83c | 486 | part->data = UINT64_TO_PTR(d->vec.address); |
bc7fd8cd LP |
487 | part->size = d->vec.size; |
488 | } else { | |
453a0c29 | 489 | part->data = d->vec.address != 0 ? (uint8_t*) UINT64_TO_PTR(d->vec.address) + (begin_body - idx) : NULL; |
bc7fd8cd LP |
490 | part->size = d->vec.size - (begin_body - idx); |
491 | } | |
492 | ||
453a0c29 | 493 | part->is_zero = d->vec.address == 0; |
bc7fd8cd LP |
494 | part->sealed = true; |
495 | } | |
fd8d62d9 LP |
496 | |
497 | idx += d->vec.size; | |
69aec65c | 498 | |
69aec65c LP |
499 | } else if (d->type == KDBUS_MSG_SRC_CREDS) { |
500 | m->pid_starttime = d->creds.starttime / NSEC_PER_USEC; | |
501 | m->uid = d->creds.uid; | |
502 | m->gid = d->creds.gid; | |
503 | m->pid = d->creds.pid; | |
504 | m->tid = d->creds.tid; | |
505 | m->uid_valid = m->gid_valid = true; | |
506 | } else if (d->type == KDBUS_MSG_TIMESTAMP) { | |
507 | m->realtime = d->timestamp.realtime_ns / NSEC_PER_USEC; | |
508 | m->monotonic = d->timestamp.monotonic_ns / NSEC_PER_USEC; | |
509 | } else if (d->type == KDBUS_MSG_SRC_PID_COMM) | |
510 | m->comm = d->str; | |
511 | else if (d->type == KDBUS_MSG_SRC_TID_COMM) | |
512 | m->tid_comm = d->str; | |
513 | else if (d->type == KDBUS_MSG_SRC_EXE) | |
514 | m->exe = d->str; | |
77930f11 LP |
515 | else if (d->type == KDBUS_MSG_SRC_CMDLINE) { |
516 | m->cmdline = d->str; | |
517 | m->cmdline_length = l; | |
4a875b61 LP |
518 | } else if (d->type == KDBUS_MSG_SRC_CGROUP) |
519 | m->cgroup = d->str; | |
120f919e LP |
520 | else if (d->type == KDBUS_MSG_SRC_AUDIT) |
521 | m->audit = &d->audit; | |
102ea8e4 LP |
522 | else if (d->type == KDBUS_MSG_SRC_CAPS) { |
523 | m->capability = d->data; | |
524 | m->capability_size = l; | |
fd8d62d9 LP |
525 | } else if (d->type != KDBUS_MSG_FDS && |
526 | d->type != KDBUS_MSG_DST_NAME && | |
527 | d->type != KDBUS_MSG_SRC_SECLABEL) | |
77930f11 | 528 | log_debug("Got unknown field from kernel %llu", d->type); |
69aec65c | 529 | } |
acb5a3cb | 530 | |
6629161f LP |
531 | r = bus_message_parse_fields(m); |
532 | if (r < 0) { | |
533 | sd_bus_message_unref(m); | |
534 | return r; | |
535 | } | |
536 | ||
51038c03 LP |
537 | if (k->src_id == KDBUS_SRC_ID_KERNEL) |
538 | m->sender = "org.freedesktop.DBus"; | |
539 | else { | |
540 | snprintf(m->sender_buffer, sizeof(m->sender_buffer), ":1.%llu", (unsigned long long) k->src_id); | |
541 | m->sender = m->sender_buffer; | |
542 | } | |
543 | ||
544 | if (!m->destination) { | |
545 | if (destination) | |
546 | m->destination = destination; | |
547 | else if (k->dst_id != KDBUS_DST_ID_WELL_KNOWN_NAME && | |
548 | k->dst_id != KDBUS_DST_ID_BROADCAST) { | |
549 | snprintf(m->destination_buffer, sizeof(m->destination_buffer), ":1.%llu", (unsigned long long) k->dst_id); | |
550 | m->destination = m->destination_buffer; | |
551 | } | |
552 | } | |
553 | ||
6629161f LP |
554 | /* We take possession of the kmsg struct now */ |
555 | m->kdbus = k; | |
fd8d62d9 LP |
556 | m->bus = sd_bus_ref(bus); |
557 | m->release_kdbus = true; | |
6629161f LP |
558 | m->free_fds = true; |
559 | ||
560 | fds = NULL; | |
561 | ||
562 | *ret = m; | |
563 | return 1; | |
564 | } | |
565 | ||
566 | int bus_kernel_read_message(sd_bus *bus, sd_bus_message **m) { | |
567 | struct kdbus_msg *k; | |
6629161f LP |
568 | int r; |
569 | ||
570 | assert(bus); | |
571 | assert(m); | |
572 | ||
fd8d62d9 LP |
573 | r = ioctl(bus->input_fd, KDBUS_CMD_MSG_RECV, &k); |
574 | if (r < 0) { | |
6629161f LP |
575 | if (errno == EAGAIN) |
576 | return 0; | |
577 | ||
fd8d62d9 | 578 | return -errno; |
6629161f LP |
579 | } |
580 | ||
fd8d62d9 LP |
581 | |
582 | /* /\* Let's tell valgrind that there's really no need to */ | |
583 | /* * initialize this fully. This should be removed again */ | |
584 | /* * when valgrind learned the kdbus ioctls natively. *\/ */ | |
585 | /* #ifdef HAVE_VALGRIND_MEMCHECK_H */ | |
586 | /* VALGRIND_MAKE_MEM_DEFINED(k, sz); */ | |
587 | /* #endif */ | |
588 | ||
589 | ||
6629161f | 590 | r = bus_kernel_make_message(bus, k, m); |
fd8d62d9 LP |
591 | if (r <= 0) |
592 | close_kdbus_msg(bus, k); | |
6629161f | 593 | |
51038c03 | 594 | return r < 0 ? r : 1; |
6629161f LP |
595 | } |
596 | ||
597 | int bus_kernel_create(const char *name, char **s) { | |
5b7d4c1c | 598 | struct kdbus_cmd_bus_make *make; |
febfd508 | 599 | struct kdbus_item *n, *cg; |
6629161f LP |
600 | size_t l; |
601 | int fd; | |
602 | char *p; | |
603 | ||
604 | assert(name); | |
605 | assert(s); | |
606 | ||
607 | fd = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC); | |
608 | if (fd < 0) | |
609 | return -errno; | |
610 | ||
611 | l = strlen(name); | |
a2cef833 | 612 | make = alloca0(offsetof(struct kdbus_cmd_bus_make, items) + |
febfd508 KS |
613 | KDBUS_ITEM_HEADER_SIZE + sizeof(uint64_t) + |
614 | KDBUS_ITEM_HEADER_SIZE + DECIMAL_STR_MAX(uid_t) + 1 + l + 1); | |
a2cef833 KS |
615 | |
616 | cg = make->items; | |
799e7ea8 | 617 | cg->type = KDBUS_MAKE_CGROUP; |
a2cef833 | 618 | cg->data64[0] = 1; |
febfd508 | 619 | cg->size = KDBUS_ITEM_HEADER_SIZE + sizeof(uint64_t); |
a2cef833 KS |
620 | |
621 | n = KDBUS_ITEM_NEXT(cg); | |
799e7ea8 | 622 | n->type = KDBUS_MAKE_NAME; |
a2cef833 | 623 | sprintf(n->str, "%lu-%s", (unsigned long) getuid(), name); |
febfd508 | 624 | n->size = KDBUS_ITEM_HEADER_SIZE + strlen(n->str) + 1; |
a2cef833 KS |
625 | |
626 | make->size = offsetof(struct kdbus_cmd_bus_make, items) + cg->size + n->size; | |
18cd014f | 627 | make->flags = KDBUS_MAKE_POLICY_OPEN; |
5b7d4c1c | 628 | make->bus_flags = 0; |
a56f19c4 | 629 | make->bloom_size = BLOOM_SIZE; |
a56f19c4 | 630 | assert_cc(BLOOM_SIZE % 8 == 0); |
5b7d4c1c | 631 | |
a2cef833 | 632 | p = strjoin("/dev/kdbus/", n->str, "/bus", NULL); |
6629161f LP |
633 | if (!p) |
634 | return -ENOMEM; | |
635 | ||
5b7d4c1c | 636 | if (ioctl(fd, KDBUS_CMD_BUS_MAKE, make) < 0) { |
6629161f LP |
637 | close_nointr_nofail(fd); |
638 | free(p); | |
639 | return -errno; | |
640 | } | |
641 | ||
642 | if (s) | |
643 | *s = p; | |
644 | ||
645 | return fd; | |
646 | } | |
bc7fd8cd LP |
647 | |
648 | int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *size) { | |
649 | struct memfd_cache *c; | |
650 | ||
651 | assert(address); | |
652 | assert(size); | |
653 | ||
654 | if (!bus || !bus->is_kernel) | |
655 | return -ENOTSUP; | |
656 | ||
657 | if (bus->n_memfd_cache <= 0) { | |
9b05bc48 | 658 | int fd, r; |
bc7fd8cd | 659 | |
9b05bc48 LP |
660 | r = ioctl(bus->input_fd, KDBUS_CMD_MEMFD_NEW, &fd); |
661 | if (r < 0) | |
bc7fd8cd LP |
662 | return -errno; |
663 | ||
664 | *address = NULL; | |
665 | *size = 0; | |
666 | return fd; | |
667 | } | |
668 | ||
669 | c = &bus->memfd_cache[-- bus->n_memfd_cache]; | |
670 | ||
671 | assert(c->fd >= 0); | |
672 | assert(c->size == 0 || c->address); | |
673 | ||
674 | *address = c->address; | |
675 | *size = c->size; | |
676 | ||
677 | return c->fd; | |
678 | } | |
679 | ||
680 | void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t size) { | |
681 | struct memfd_cache *c; | |
682 | ||
683 | assert(fd >= 0); | |
684 | assert(size == 0 || address); | |
685 | ||
686 | if (!bus || !bus->is_kernel || | |
687 | bus->n_memfd_cache >= ELEMENTSOF(bus->memfd_cache)) { | |
688 | ||
689 | if (size > 0) | |
690 | assert_se(munmap(address, PAGE_ALIGN(size)) == 0); | |
691 | ||
692 | close_nointr_nofail(fd); | |
693 | return; | |
694 | } | |
695 | ||
696 | c = &bus->memfd_cache[bus->n_memfd_cache++]; | |
697 | c->fd = fd; | |
698 | c->address = address; | |
699 | ||
700 | /* If overly long, let's return a bit to the OS */ | |
701 | if (size > MEMFD_CACHE_ITEM_SIZE_MAX) { | |
702 | uint64_t sz = MEMFD_CACHE_ITEM_SIZE_MAX; | |
703 | ||
704 | ioctl(bus->input_fd, KDBUS_CMD_MEMFD_SIZE_SET, &sz); | |
705 | ||
706 | c->size = MEMFD_CACHE_ITEM_SIZE_MAX; | |
707 | } else | |
708 | c->size = size; | |
709 | } | |
710 | ||
711 | void bus_kernel_flush_memfd(sd_bus *b) { | |
712 | unsigned i; | |
713 | ||
714 | assert(b); | |
715 | ||
716 | for (i = 0; i < b->n_memfd_cache; i++) { | |
717 | if (b->memfd_cache[i].size > 0) | |
718 | assert_se(munmap(b->memfd_cache[i].address, PAGE_ALIGN(b->memfd_cache[i].size)) == 0); | |
719 | ||
720 | close_nointr_nofail(b->memfd_cache[i].fd); | |
721 | } | |
722 | } |