chiark / gitweb /
6105a020701ee0c2c90c511d2590563b0c79ffb8
[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                 else if (d->type == KDBUS_MSG_SRC_CMDLINE) {
375                         m->cmdline = d->str;
376                         m->cmdline_length = l;
377                 } else
378                         log_debug("Got unknown field from kernel %llu", d->type);
379         }
380
381         r = bus_message_parse_fields(m);
382         if (r < 0) {
383                 sd_bus_message_unref(m);
384                 return r;
385         }
386
387         if (k->src_id == KDBUS_SRC_ID_KERNEL)
388                 m->sender = "org.freedesktop.DBus";
389         else {
390                 snprintf(m->sender_buffer, sizeof(m->sender_buffer), ":1.%llu", (unsigned long long) k->src_id);
391                 m->sender = m->sender_buffer;
392         }
393
394         if (!m->destination) {
395                 if (destination)
396                         m->destination = destination;
397                 else if (k->dst_id != KDBUS_DST_ID_WELL_KNOWN_NAME &&
398                          k->dst_id != KDBUS_DST_ID_BROADCAST) {
399                         snprintf(m->destination_buffer, sizeof(m->destination_buffer), ":1.%llu", (unsigned long long) k->dst_id);
400                         m->destination = m->destination_buffer;
401                 }
402         }
403
404         /* We take possession of the kmsg struct now */
405         m->kdbus = k;
406         m->free_kdbus = true;
407         m->free_fds = true;
408
409         fds = NULL;
410
411         *ret = m;
412         return 1;
413 }
414
415 int bus_kernel_read_message(sd_bus *bus, sd_bus_message **m) {
416         struct kdbus_msg *k;
417         size_t sz = 1024;
418         int r;
419
420         assert(bus);
421         assert(m);
422
423         for (;;) {
424                 void *q;
425
426                 q = aligned_alloc(8, sz);
427                 if (!q)
428                         return -errno;
429
430                 free(bus->rbuffer);
431                 k = bus->rbuffer = q;
432                 k->size = sz;
433
434                 /* Let's tell valgrind that there's really no need to
435                  * initialize this fully. This should be removed again
436                  * when valgrind learned the kdbus ioctls natively. */
437 #ifdef HAVE_VALGRIND_MEMCHECK_H
438                 VALGRIND_MAKE_MEM_DEFINED(k, sz);
439 #endif
440
441                 r = ioctl(bus->input_fd, KDBUS_CMD_MSG_RECV, bus->rbuffer);
442                 if (r >= 0)
443                         break;
444
445                 if (errno == EAGAIN)
446                         return 0;
447
448                 if (errno != ENOBUFS)
449                         return -errno;
450
451                 sz *= 2;
452         }
453
454         r = bus_kernel_make_message(bus, k, m);
455         if (r > 0)
456                 bus->rbuffer = NULL;
457         else
458                 close_kdbus_msg(k);
459
460         return r < 0 ? r : 1;
461 }
462
463 int bus_kernel_create(const char *name, char **s) {
464         struct kdbus_cmd_bus_make *make;
465         size_t l;
466         int fd;
467         char *p;
468
469         assert(name);
470         assert(s);
471
472         fd = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
473         if (fd < 0)
474                 return -errno;
475
476         l = strlen(name);
477         make = alloca(offsetof(struct kdbus_cmd_bus_make, name) + DECIMAL_STR_MAX(uid_t) + 1 + l + 1);
478         sprintf(make->name, "%lu-%s", (unsigned long) getuid(), name);
479         make->size = offsetof(struct kdbus_cmd_bus_make, name) + strlen(make->name) + 1;
480         make->flags = KDBUS_ACCESS_WORLD | KDBUS_POLICY_OPEN;
481         make->bus_flags = 0;
482         make->bloom_size = 16;
483
484         p = strjoin("/dev/kdbus/", make->name, "/bus", NULL);
485         if (!p)
486                 return -ENOMEM;
487
488         if (ioctl(fd, KDBUS_CMD_BUS_MAKE, make) < 0) {
489                 close_nointr_nofail(fd);
490                 free(p);
491                 return -errno;
492         }
493
494         if (s)
495                 *s = p;
496
497         return fd;
498 }