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