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