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