1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Lennart Poettering
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.
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.
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/>.
22 #ifdef HAVE_VALGRIND_MEMCHECK_H
23 #include <valgrind/memcheck.h>
31 #include "bus-internal.h"
32 #include "bus-message.h"
33 #include "bus-kernel.h"
34 #include "bus-bloom.h"
36 #define KDBUS_ITEM_NEXT(item) \
37 (typeof(item))(((uint8_t *)item) + ALIGN8((item)->size))
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))
44 static int parse_unique_name(const char *s
, uint64_t *id
) {
50 if (!startswith(s
, ":1."))
53 r
= safe_atou64(s
+ 3, id
);
60 static void append_payload_vec(struct kdbus_msg_item
**d
, const void *p
, size_t sz
) {
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
;
72 *d
= (struct kdbus_msg_item
*) ((uint8_t*) *d
+ (*d
)->size
);
75 static void append_destination(struct kdbus_msg_item
**d
, const char *s
, size_t length
) {
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);
85 *d
= (struct kdbus_msg_item
*) ((uint8_t*) *d
+ (*d
)->size
);
88 static void* append_bloom(struct kdbus_msg_item
**d
, size_t length
) {
95 (*d
)->size
= offsetof(struct kdbus_msg_item
, data
) + length
;
96 (*d
)->type
= KDBUS_MSG_BLOOM
;
99 *d
= (struct kdbus_msg_item
*) ((uint8_t*) *d
+ (*d
)->size
);
104 static void append_fds(struct kdbus_msg_item
**d
, const int fds
[], unsigned n_fds
) {
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
);
114 *d
= (struct kdbus_msg_item
*) ((uint8_t*) *d
+ (*d
)->size
);
117 static int bus_message_setup_bloom(sd_bus_message
*m
, void *bloom
) {
124 memset(bloom
, 0, BLOOM_SIZE
);
126 bloom_add_pair(bloom
, "message-type", bus_message_type_to_string(m
->header
->type
));
129 bloom_add_pair(bloom
, "interface", m
->interface
);
131 bloom_add_pair(bloom
, "member", m
->member
);
133 bloom_add_pair(bloom
, "path", m
->path
);
134 bloom_add_prefixes(bloom
, "path-slash-prefix", m
->path
, '/');
137 r
= sd_bus_message_rewind(m
, true);
141 for (i
= 0; i
< 64; i
++) {
144 char buf
[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
147 r
= sd_bus_message_peek_type(m
, &type
, NULL
);
151 if (type
!= SD_BUS_TYPE_STRING
&&
152 type
!= SD_BUS_TYPE_OBJECT_PATH
&&
153 type
!= SD_BUS_TYPE_SIGNATURE
)
156 r
= sd_bus_message_read_basic(m
, type
, &t
);
160 e
= stpcpy(buf
, "arg");
164 *(e
++) = '0' + (i
/ 10);
165 *(e
++) = '0' + (i
% 10);
169 bloom_add_pair(bloom
, buf
, t
);
171 strcpy(e
, "-dot-prefix");
172 bloom_add_prefixes(bloom
, buf
, t
, '.');
173 strcpy(e
, "-slash-prefix");
174 bloom_add_prefixes(bloom
, buf
, t
, '/');
180 static int bus_message_setup_kmsg(sd_bus
*b
, sd_bus_message
*m
) {
181 struct kdbus_msg_item
*d
;
194 if (m
->destination
) {
195 r
= parse_unique_name(m
->destination
, &unique
);
203 sz
= offsetof(struct kdbus_msg
, items
);
205 /* Add in fixed header, fields header and payload */
206 sz
+= 3 * ALIGN8(offsetof(struct kdbus_msg_item
, vec
) + sizeof(struct kdbus_vec
));
208 /* Add space for bloom filter */
209 sz
+= ALIGN8(offsetof(struct kdbus_msg_item
, data
) + BLOOM_SIZE
);
211 /* Add in well-known destination header */
213 dl
= strlen(m
->destination
);
214 sz
+= ALIGN8(offsetof(struct kdbus_msg_item
, str
) + dl
+ 1);
217 /* Add space for unix fds */
219 sz
+= ALIGN8(offsetof(struct kdbus_msg_item
, fds
) + sizeof(int)*m
->n_fds
);
221 m
->kdbus
= memalign(8, sz
);
225 memset(m
->kdbus
, 0, sz
);
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);
232 m
->destination
? unique
: KDBUS_DST_ID_BROADCAST
;
233 m
->kdbus
->payload_type
= KDBUS_PAYLOAD_DBUS1
;
234 m
->kdbus
->cookie
= m
->header
->serial
;
236 m
->kdbus
->timeout_ns
= m
->timeout
* NSEC_PER_USEC
;
241 append_destination(&d
, m
->destination
, dl
);
243 append_payload_vec(&d
, m
->header
, sizeof(*m
->header
));
246 append_payload_vec(&d
, m
->fields
, ALIGN8(m
->header
->fields_size
));
249 append_payload_vec(&d
, m
->body
, m
->header
->body_size
);
251 if (m
->kdbus
->dst_id
== KDBUS_DST_ID_BROADCAST
) {
254 p
= append_bloom(&d
, BLOOM_SIZE
);
255 r
= bus_message_setup_bloom(m
, p
);
264 append_fds(&d
, m
->fds
, m
->n_fds
);
266 m
->kdbus
->size
= (uint8_t*) d
- (uint8_t*) m
->kdbus
;
267 assert(m
->kdbus
->size
<= sz
);
269 m
->free_kdbus
= true;
274 int bus_kernel_take_fd(sd_bus
*b
) {
275 struct kdbus_cmd_hello hello
= {
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
293 r
= ioctl(b
->input_fd
, KDBUS_CMD_HELLO
, &hello
);
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
)
303 if (hello
.bloom_size
!= BLOOM_SIZE
)
306 if (asprintf(&b
->unique_name
, ":1.%llu", (unsigned long long) hello
.id
) < 0)
310 b
->bus_client
= true;
313 r
= bus_start_running(b
);
320 int bus_kernel_connect(sd_bus
*b
) {
322 assert(b
->input_fd
< 0);
323 assert(b
->output_fd
< 0);
329 b
->input_fd
= open(b
->kernel
, O_RDWR
|O_NOCTTY
|O_CLOEXEC
);
333 b
->output_fd
= b
->input_fd
;
335 return bus_kernel_take_fd(b
);
338 int bus_kernel_write_message(sd_bus
*bus
, sd_bus_message
*m
) {
343 assert(bus
->state
== BUS_RUNNING
);
345 r
= bus_message_setup_kmsg(bus
, m
);
349 r
= ioctl(bus
->output_fd
, KDBUS_CMD_MSG_SEND
, m
->kdbus
);
351 return errno
== EAGAIN
? 0 : -errno
;
356 static void close_kdbus_msg(struct kdbus_msg
*k
) {
357 struct kdbus_msg_item
*d
;
359 KDBUS_ITEM_FOREACH(d
, k
) {
361 if (d
->type
!= KDBUS_MSG_UNIX_FDS
)
364 close_many(d
->fds
, (d
->size
- offsetof(struct kdbus_msg_item
, fds
)) / sizeof(int));
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
;
382 if (k
->payload_type
!= KDBUS_PAYLOAD_DBUS1
)
385 KDBUS_ITEM_FOREACH(d
, k
) {
388 l
= d
->size
- offsetof(struct kdbus_msg_item
, data
);
390 if (d
->type
== KDBUS_MSG_PAYLOAD
) {
393 if (l
< sizeof(struct bus_header
))
396 h
= (struct bus_header
*) d
->data
;
402 } else if (d
->type
== KDBUS_MSG_UNIX_FDS
) {
407 f
= realloc(fds
, sizeof(int) * (n_fds
+ j
));
412 memcpy(fds
+ n_fds
, d
->fds
, sizeof(int) * j
);
415 } else if (d
->type
== KDBUS_MSG_DST_NAME
)
416 destination
= d
->str
;
417 else if (d
->type
== KDBUS_MSG_SRC_SECLABEL
)
424 r
= bus_header_size(h
, &total
);
428 if (n_bytes
!= total
)
431 r
= bus_message_from_header(h
, sizeof(struct bus_header
), fds
, n_fds
, NULL
, seclabel
, 0, &m
);
435 KDBUS_ITEM_FOREACH(d
, k
) {
438 l
= d
->size
- offsetof(struct kdbus_msg_item
, data
);
440 if (d
->type
== KDBUS_MSG_PAYLOAD
) {
442 if (idx
== sizeof(struct bus_header
) &&
443 l
== ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m
)))
445 else if (idx
== sizeof(struct bus_header
) + ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m
)) &&
446 l
== BUS_MESSAGE_BODY_SIZE(m
))
448 else if (!(idx
== 0 && l
== sizeof(struct bus_header
))) {
449 sd_bus_message_unref(m
);
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
)
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
)
470 else if (d
->type
== KDBUS_MSG_SRC_CMDLINE
) {
472 m
->cmdline_length
= l
;
473 } else if (d
->type
== KDBUS_MSG_SRC_CGROUP
)
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
;
481 log_debug("Got unknown field from kernel %llu", d
->type
);
484 r
= bus_message_parse_fields(m
);
486 sd_bus_message_unref(m
);
490 if (k
->src_id
== KDBUS_SRC_ID_KERNEL
)
491 m
->sender
= "org.freedesktop.DBus";
493 snprintf(m
->sender_buffer
, sizeof(m
->sender_buffer
), ":1.%llu", (unsigned long long) k
->src_id
);
494 m
->sender
= m
->sender_buffer
;
497 if (!m
->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
;
507 /* We take possession of the kmsg struct now */
509 m
->free_kdbus
= true;
518 int bus_kernel_read_message(sd_bus
*bus
, sd_bus_message
**m
) {
534 k
= bus
->rbuffer
= q
;
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
);
544 r
= ioctl(bus
->input_fd
, KDBUS_CMD_MSG_RECV
, bus
->rbuffer
);
551 if (errno
!= ENOBUFS
)
557 r
= bus_kernel_make_message(bus
, k
, m
);
563 return r
< 0 ? r
: 1;
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
;
576 fd
= open("/dev/kdbus/control", O_RDWR
|O_NOCTTY
|O_CLOEXEC
);
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);
586 cg
->type
= KDBUS_MAKE_CGROUP
;
588 cg
->size
= sizeof(struct kdbus_cmd_make_item
) + sizeof(uint64_t);
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;
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
;
598 make
->bloom_size
= BLOOM_SIZE
;
599 assert_cc(BLOOM_SIZE
% 8 == 0);
601 p
= strjoin("/dev/kdbus/", n
->str
, "/bus", NULL
);
605 if (ioctl(fd
, KDBUS_CMD_BUS_MAKE
, make
) < 0) {
606 close_nointr_nofail(fd
);