chiark / gitweb /
bus: rename KDBUS_CMD_FNAME_POLICY_NONE -> KDBUS_CMD_FNAME_POLICY_OPEN
[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 = aligned_alloc(8, 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         if (b->is_server)
162                 return -EINVAL;
163
164         r = ioctl(b->input_fd, KDBUS_CMD_HELLO, &hello);
165         if (r < 0)
166                 return -errno;
167
168         if (asprintf(&b->unique_name, ":1.%llu", (unsigned long long) hello.id) < 0)
169                 return -ENOMEM;
170
171         b->is_kernel = true;
172         b->bus_client = true;
173
174         r = bus_start_running(b);
175         if (r < 0)
176                 return r;
177
178         return 1;
179 }
180
181 int bus_kernel_connect(sd_bus *b) {
182         assert(b);
183         assert(b->input_fd < 0);
184         assert(b->output_fd < 0);
185         assert(b->kernel);
186
187         if (b->is_server)
188                 return -EINVAL;
189
190         b->input_fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC);
191         if (b->input_fd < 0)
192                 return -errno;
193
194         b->output_fd = b->input_fd;
195
196         return bus_kernel_take_fd(b);
197 }
198
199 int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m) {
200         int r;
201
202         assert(bus);
203         assert(m);
204         assert(bus->state == BUS_RUNNING);
205
206         r = bus_message_setup_kmsg(m);
207         if (r < 0)
208                 return r;
209
210         r = ioctl(bus->output_fd, KDBUS_CMD_MSG_SEND, m->kdbus);
211         if (r < 0)
212                 return errno == EAGAIN ? 0 : -errno;
213
214         return 0;
215 }
216
217 static void close_kdbus_msg(struct kdbus_msg *k) {
218         struct kdbus_msg_data *d;
219
220         KDBUS_MSG_FOREACH_DATA(d, k) {
221
222                 if (d->type != KDBUS_MSG_UNIX_FDS)
223                         continue;
224
225                 close_many(d->fds, (d->size - offsetof(struct kdbus_msg_data, fds)) / sizeof(int));
226         }
227 }
228
229 static int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k, sd_bus_message **ret) {
230         sd_bus_message *m = NULL;
231         struct kdbus_msg_data *d;
232         unsigned n_payload = 0, n_fds = 0;
233         _cleanup_free_ int *fds = NULL;
234         struct bus_header *h = NULL;
235         size_t total, n_bytes = 0, idx = 0;
236         struct kdbus_creds *creds = NULL;
237         uint64_t nsec = 0;
238         int r;
239
240         assert(bus);
241         assert(k);
242         assert(ret);
243
244         if (k->payload_type != KDBUS_PAYLOAD_DBUS1)
245                 return 0;
246
247         KDBUS_MSG_FOREACH_DATA(d, k) {
248                 size_t l;
249
250                 l = d->size - offsetof(struct kdbus_msg_data, data);
251
252                 if (d->type == KDBUS_MSG_PAYLOAD) {
253
254                         if (!h) {
255                                 if (l < sizeof(struct bus_header))
256                                         return -EBADMSG;
257
258                                 h = (struct bus_header*) d->data;
259                         }
260
261                         n_payload++;
262                         n_bytes += l;
263
264                 } else if (d->type == KDBUS_MSG_UNIX_FDS) {
265                         int *f;
266                         unsigned j;
267
268                         j = l / sizeof(int);
269                         f = realloc(fds, sizeof(int) * (n_fds + j));
270                         if (!f)
271                                 return -ENOMEM;
272
273                         fds = f;
274                         memcpy(fds + n_fds, d->fds, j);
275                         n_fds += j;
276
277                 } else if (d->type == KDBUS_MSG_SRC_CREDS)
278                         creds = &d->creds;
279                 else if (d->type == KDBUS_MSG_TIMESTAMP)
280                         nsec = d->ts_ns;
281         }
282
283         if (!h)
284                 return -EBADMSG;
285
286         r = bus_header_size(h, &total);
287         if (r < 0)
288                 return r;
289
290         if (n_bytes != total)
291                 return -EBADMSG;
292
293         r = bus_message_from_header(h, sizeof(struct bus_header), fds, n_fds, NULL, NULL, 0, &m);
294         if (r < 0)
295                 return r;
296
297         KDBUS_MSG_FOREACH_DATA(d, k) {
298                 size_t l;
299
300                 if (d->type != KDBUS_MSG_PAYLOAD)
301                         continue;
302
303                 l = d->size - offsetof(struct kdbus_msg_data, data);
304                 if (idx == sizeof(struct bus_header) &&
305                     l == BUS_MESSAGE_FIELDS_SIZE(m))
306                         m->fields = d->data;
307                 else if (idx == sizeof(struct bus_header) + ALIGN8(BUS_MESSAGE_FIELDS_SIZE(m)) &&
308                          l == BUS_MESSAGE_BODY_SIZE(m))
309                         m->body = d->data;
310                 else if (!(idx == 0 && l == sizeof(struct bus_header)) &&
311                          !(idx == sizeof(struct bus_header) + BUS_MESSAGE_FIELDS_SIZE(m))) {
312                         sd_bus_message_unref(m);
313                         return -EBADMSG;
314                 }
315
316                 idx += l;
317         }
318
319         if (creds) {
320                 m->pid_starttime = creds->starttime / NSEC_PER_USEC;
321                 m->uid = creds->uid;
322                 m->gid = creds->gid;
323                 m->pid = creds->pid;
324                 m->tid = creds->tid;
325                 m->uid_valid = m->gid_valid = true;
326         }
327
328         m->timestamp = nsec / NSEC_PER_USEC;
329
330         r = bus_message_parse_fields(m);
331         if (r < 0) {
332                 sd_bus_message_unref(m);
333                 return r;
334         }
335
336         /* We take possession of the kmsg struct now */
337         m->kdbus = k;
338         m->free_kdbus = true;
339         m->free_fds = true;
340
341         fds = NULL;
342
343         *ret = m;
344         return 1;
345 }
346
347 int bus_kernel_read_message(sd_bus *bus, sd_bus_message **m) {
348         struct kdbus_msg *k;
349         size_t sz = 1024;
350         int r;
351
352         assert(bus);
353         assert(m);
354
355         for (;;) {
356                 void *q;
357
358                 q = aligned_alloc(8, sz);
359                 if (!q)
360                         return -errno;
361
362                 free(bus->rbuffer);
363                 k = bus->rbuffer = q;
364                 k->size = sz;
365
366                 /* Let's tell valgrind that there's really no need to
367                  * initialize this fully. This should be removed again
368                  * when valgrind learned the kdbus ioctls natively. */
369 #ifdef HAVE_VALGRIND_MEMCHECK_H
370                 VALGRIND_MAKE_MEM_DEFINED(k, sz);
371 #endif
372
373                 r = ioctl(bus->input_fd, KDBUS_CMD_MSG_RECV, bus->rbuffer);
374                 if (r >= 0)
375                         break;
376
377                 if (errno == EAGAIN)
378                         return 0;
379
380                 if (errno != ENOBUFS)
381                         return -errno;
382
383                 sz *= 2;
384         }
385
386         r = bus_kernel_make_message(bus, k, m);
387         if (r > 0)
388                 bus->rbuffer = NULL;
389         else
390                 close_kdbus_msg(k);
391
392         return r;
393 }
394
395 int bus_kernel_create(const char *name, char **s) {
396         struct kdbus_cmd_fname *fname;
397         size_t l;
398         int fd;
399         char *p;
400
401         assert(name);
402         assert(s);
403
404         fd = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
405         if (fd < 0)
406                 return -errno;
407
408         l = strlen(name);
409         fname = alloca(offsetof(struct kdbus_cmd_fname, name) + DECIMAL_STR_MAX(uid_t) + 1 + l + 1);
410         sprintf(fname->name, "%lu-%s", (unsigned long) getuid(), name);
411         fname->size = offsetof(struct kdbus_cmd_fname, name) + strlen(fname->name) + 1;
412         fname->kernel_flags = KDBUS_CMD_FNAME_ACCESS_WORLD | KDBUS_CMD_FNAME_POLICY_OPEN;
413         fname->user_flags = 0;
414
415         p = strjoin("/dev/kdbus/", fname->name, "/bus", NULL);
416         if (!p)
417                 return -ENOMEM;
418
419         if (ioctl(fd, KDBUS_CMD_BUS_MAKE, fname) < 0) {
420                 close_nointr_nofail(fd);
421                 free(p);
422                 return -errno;
423         }
424
425         if (s)
426                 *s = p;
427
428         return fd;
429 }