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