Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include <errno.h>
4 : : #include <fcntl.h>
5 : : #include <sys/mman.h>
6 : :
7 : : #include "sd-bus.h"
8 : :
9 : : #include "alloc-util.h"
10 : : #include "bus-gvariant.h"
11 : : #include "bus-internal.h"
12 : : #include "bus-message.h"
13 : : #include "bus-signature.h"
14 : : #include "bus-type.h"
15 : : #include "bus-util.h"
16 : : #include "fd-util.h"
17 : : #include "io-util.h"
18 : : #include "memfd-util.h"
19 : : #include "memory-util.h"
20 : : #include "string-util.h"
21 : : #include "strv.h"
22 : : #include "time-util.h"
23 : : #include "utf8.h"
24 : :
25 : : static int message_append_basic(sd_bus_message *m, char type, const void *p, const void **stored);
26 : :
27 : 18500 : static void *adjust_pointer(const void *p, void *old_base, size_t sz, void *new_base) {
28 : :
29 [ + + ]: 18500 : if (!p)
30 : 13356 : return NULL;
31 : :
32 [ + + ]: 5144 : if (old_base == new_base)
33 : 3876 : return (void*) p;
34 : :
35 [ - + ]: 1268 : if ((uint8_t*) p < (uint8_t*) old_base)
36 : 0 : return (void*) p;
37 : :
38 [ + + ]: 1268 : if ((uint8_t*) p >= (uint8_t*) old_base + sz)
39 : 4 : return (void*) p;
40 : :
41 : 1264 : return (uint8_t*) new_base + ((uint8_t*) p - (uint8_t*) old_base);
42 : : }
43 : :
44 : 567 : static void message_free_part(sd_bus_message *m, struct bus_body_part *part) {
45 [ - + ]: 567 : assert(m);
46 [ - + ]: 567 : assert(part);
47 : :
48 [ - + ]: 567 : if (part->memfd >= 0)
49 : 0 : close_and_munmap(part->memfd, part->mmap_begin, part->mapped);
50 [ - + ]: 567 : else if (part->munmap_this)
51 : 0 : munmap(part->mmap_begin, part->mapped);
52 [ + + ]: 567 : else if (part->free_this)
53 : 268 : free(part->data);
54 : :
55 [ - + ]: 567 : if (part != &m->body)
56 : 0 : free(part);
57 : 567 : }
58 : :
59 : 1154 : static void message_reset_parts(sd_bus_message *m) {
60 : : struct bus_body_part *part;
61 : :
62 [ - + ]: 1154 : assert(m);
63 : :
64 : 1154 : part = &m->body;
65 [ + + ]: 1721 : while (m->n_body_parts > 0) {
66 : 567 : struct bus_body_part *next = part->next;
67 : 567 : message_free_part(m, part);
68 : 567 : part = next;
69 : 567 : m->n_body_parts--;
70 : : }
71 : :
72 : 1154 : m->body_end = NULL;
73 : :
74 : 1154 : m->cached_rindex_part = NULL;
75 : 1154 : m->cached_rindex_part_begin = 0;
76 : 1154 : }
77 : :
78 : 27493 : static struct bus_container *message_get_last_container(sd_bus_message *m) {
79 [ - + ]: 27493 : assert(m);
80 : :
81 [ + + ]: 27493 : if (m->n_containers == 0)
82 : 8477 : return &m->root_container;
83 : :
84 [ - + ]: 19016 : assert(m->containers);
85 : 19016 : return m->containers + m->n_containers - 1;
86 : : }
87 : :
88 : 2322 : static void message_free_last_container(sd_bus_message *m) {
89 : : struct bus_container *c;
90 : :
91 : 2322 : c = message_get_last_container(m);
92 : :
93 : 2322 : free(c->signature);
94 : 2322 : free(c->peeked_signature);
95 : 2322 : free(c->offsets);
96 : :
97 : : /* Move to previous container, but not if we are on root container */
98 [ + + ]: 2322 : if (m->n_containers > 0)
99 : 1168 : m->n_containers--;
100 : 2322 : }
101 : :
102 : 1681 : static void message_reset_containers(sd_bus_message *m) {
103 [ - + ]: 1681 : assert(m);
104 : :
105 [ + + ]: 1709 : while (m->n_containers > 0)
106 : 28 : message_free_last_container(m);
107 : :
108 : 1681 : m->containers = mfree(m->containers);
109 : 1681 : m->containers_allocated = 0;
110 : 1681 : m->root_container.index = 0;
111 : 1681 : }
112 : :
113 : 1154 : static sd_bus_message* message_free(sd_bus_message *m) {
114 [ - + ]: 1154 : assert(m);
115 : :
116 [ + - ]: 1154 : if (m->free_header)
117 : 1154 : free(m->header);
118 : :
119 : 1154 : message_reset_parts(m);
120 : :
121 : : /* Note that we don't unref m->bus here. That's already done by sd_bus_message_unref() as each user
122 : : * reference to the bus message also is considered a reference to the bus connection itself. */
123 : :
124 [ + + ]: 1154 : if (m->free_fds) {
125 : 538 : close_many(m->fds, m->n_fds);
126 : 538 : free(m->fds);
127 : : }
128 : :
129 [ + + ]: 1154 : if (m->iovec != m->iovec_fixed)
130 : 308 : free(m->iovec);
131 : :
132 : 1154 : message_reset_containers(m);
133 [ - + ]: 1154 : assert(m->n_containers == 0);
134 : 1154 : message_free_last_container(m);
135 : :
136 : 1154 : bus_creds_done(&m->creds);
137 : 1154 : return mfree(m);
138 : : }
139 : :
140 : 2208 : static void *message_extend_fields(sd_bus_message *m, size_t align, size_t sz, bool add_offset) {
141 : : void *op, *np;
142 : : size_t old_size, new_size, start;
143 : :
144 [ - + ]: 2208 : assert(m);
145 : :
146 [ - + ]: 2208 : if (m->poisoned)
147 : 0 : return NULL;
148 : :
149 : 2208 : old_size = sizeof(struct bus_header) + m->fields_size;
150 : 2208 : start = ALIGN_TO(old_size, align);
151 : 2208 : new_size = start + sz;
152 : :
153 [ + - - + ]: 2208 : if (new_size < start ||
154 : : new_size > (size_t) ((uint32_t) -1))
155 : 0 : goto poison;
156 : :
157 [ - + ]: 2208 : if (old_size == new_size)
158 : 0 : return (uint8_t*) m->header + old_size;
159 : :
160 [ + + ]: 2208 : if (m->free_header) {
161 : 1588 : np = realloc(m->header, ALIGN8(new_size));
162 [ - + ]: 1588 : if (!np)
163 : 0 : goto poison;
164 : : } else {
165 : : /* Initially, the header is allocated as part of
166 : : * the sd_bus_message itself, let's replace it by
167 : : * dynamic data */
168 : :
169 : 620 : np = malloc(ALIGN8(new_size));
170 [ - + ]: 620 : if (!np)
171 : 0 : goto poison;
172 : :
173 : 620 : memcpy(np, m->header, sizeof(struct bus_header));
174 : : }
175 : :
176 : : /* Zero out padding */
177 [ + + ]: 2208 : if (start > old_size)
178 [ + - ]: 1408 : memzero((uint8_t*) np + old_size, start - old_size);
179 : :
180 : 2208 : op = m->header;
181 : 2208 : m->header = np;
182 : 2208 : m->fields_size = new_size - sizeof(struct bus_header);
183 : :
184 : : /* Adjust quick access pointers */
185 : 2208 : m->path = adjust_pointer(m->path, op, old_size, m->header);
186 : 2208 : m->interface = adjust_pointer(m->interface, op, old_size, m->header);
187 : 2208 : m->member = adjust_pointer(m->member, op, old_size, m->header);
188 : 2208 : m->destination = adjust_pointer(m->destination, op, old_size, m->header);
189 : 2208 : m->sender = adjust_pointer(m->sender, op, old_size, m->header);
190 : 2208 : m->error.name = adjust_pointer(m->error.name, op, old_size, m->header);
191 : :
192 : 2208 : m->free_header = true;
193 : :
194 [ + + ]: 2208 : if (add_offset) {
195 [ - + ]: 32 : if (m->n_header_offsets >= ELEMENTSOF(m->header_offsets))
196 : 0 : goto poison;
197 : :
198 : 32 : m->header_offsets[m->n_header_offsets++] = new_size - sizeof(struct bus_header);
199 : : }
200 : :
201 : 2208 : return (uint8_t*) np + start;
202 : :
203 : 0 : poison:
204 : 0 : m->poisoned = true;
205 : 0 : return NULL;
206 : : }
207 : :
208 : 1784 : static int message_append_field_string(
209 : : sd_bus_message *m,
210 : : uint64_t h,
211 : : char type,
212 : : const char *s,
213 : : const char **ret) {
214 : :
215 : : size_t l;
216 : : uint8_t *p;
217 : :
218 [ - + ]: 1784 : assert(m);
219 : :
220 : : /* dbus1 only allows 8bit header field ids */
221 [ - + ]: 1784 : if (h > 0xFF)
222 : 0 : return -EINVAL;
223 : :
224 : : /* dbus1 doesn't allow strings over 32bit, let's enforce this
225 : : * globally, to not risk convertability */
226 : 1784 : l = strlen(s);
227 [ - + ]: 1784 : if (l > UINT32_MAX)
228 : 0 : return -EINVAL;
229 : :
230 : : /* Signature "(yv)" where the variant contains "s" */
231 : :
232 [ + + ]: 1784 : if (BUS_MESSAGE_IS_GVARIANT(m)) {
233 : :
234 : : /* (field id 64bit, ((string + NUL) + NUL + signature string 's') */
235 : 32 : p = message_extend_fields(m, 8, 8 + l + 1 + 1 + 1, true);
236 [ - + ]: 32 : if (!p)
237 : 0 : return -ENOMEM;
238 : :
239 : 32 : *((uint64_t*) p) = h;
240 : 32 : memcpy(p+8, s, l);
241 : 32 : p[8+l] = 0;
242 : 32 : p[8+l+1] = 0;
243 : 32 : p[8+l+2] = type;
244 : :
245 [ + - ]: 32 : if (ret)
246 : 32 : *ret = (char*) p + 8;
247 : :
248 : : } else {
249 : : /* (field id byte + (signature length + signature 's' + NUL) + (string length + string + NUL)) */
250 : 1752 : p = message_extend_fields(m, 8, 4 + 4 + l + 1, false);
251 [ - + ]: 1752 : if (!p)
252 : 0 : return -ENOMEM;
253 : :
254 : 1752 : p[0] = (uint8_t) h;
255 : 1752 : p[1] = 1;
256 : 1752 : p[2] = type;
257 : 1752 : p[3] = 0;
258 : :
259 : 1752 : ((uint32_t*) p)[1] = l;
260 : 1752 : memcpy(p + 8, s, l + 1);
261 : :
262 [ + - ]: 1752 : if (ret)
263 : 1752 : *ret = (char*) p + 8;
264 : : }
265 : :
266 : 1784 : return 0;
267 : : }
268 : :
269 : 240 : static int message_append_field_signature(
270 : : sd_bus_message *m,
271 : : uint64_t h,
272 : : const char *s,
273 : : const char **ret) {
274 : :
275 : : size_t l;
276 : : uint8_t *p;
277 : :
278 [ - + ]: 240 : assert(m);
279 : :
280 : : /* dbus1 only allows 8bit header field ids */
281 [ - + ]: 240 : if (h > 0xFF)
282 : 0 : return -EINVAL;
283 : :
284 : : /* dbus1 doesn't allow signatures over 8bit, let's enforce
285 : : * this globally, to not risk convertability */
286 : 240 : l = strlen(s);
287 [ - + ]: 240 : if (l > SD_BUS_MAXIMUM_SIGNATURE_LENGTH)
288 : 0 : return -EINVAL;
289 : :
290 : : /* Signature "(yv)" where the variant contains "g" */
291 : :
292 [ - + ]: 240 : if (BUS_MESSAGE_IS_GVARIANT(m))
293 : : /* For gvariant the serialization is the same as for normal strings */
294 : 0 : return message_append_field_string(m, h, 'g', s, ret);
295 : : else {
296 : : /* (field id byte + (signature length + signature 'g' + NUL) + (string length + string + NUL)) */
297 : 240 : p = message_extend_fields(m, 8, 4 + 1 + l + 1, false);
298 [ - + ]: 240 : if (!p)
299 : 0 : return -ENOMEM;
300 : :
301 : 240 : p[0] = (uint8_t) h;
302 : 240 : p[1] = 1;
303 : 240 : p[2] = SD_BUS_TYPE_SIGNATURE;
304 : 240 : p[3] = 0;
305 : 240 : p[4] = l;
306 : 240 : memcpy(p + 5, s, l + 1);
307 : :
308 [ - + ]: 240 : if (ret)
309 : 0 : *ret = (const char*) p + 5;
310 : : }
311 : :
312 : 240 : return 0;
313 : : }
314 : :
315 : 176 : static int message_append_field_uint32(sd_bus_message *m, uint64_t h, uint32_t x) {
316 : : uint8_t *p;
317 : :
318 [ - + ]: 176 : assert(m);
319 : :
320 : : /* dbus1 only allows 8bit header field ids */
321 [ - + ]: 176 : if (h > 0xFF)
322 : 0 : return -EINVAL;
323 : :
324 [ - + ]: 176 : if (BUS_MESSAGE_IS_GVARIANT(m)) {
325 : : /* (field id 64bit + ((value + NUL + signature string 'u') */
326 : :
327 : 0 : p = message_extend_fields(m, 8, 8 + 4 + 1 + 1, true);
328 [ # # ]: 0 : if (!p)
329 : 0 : return -ENOMEM;
330 : :
331 : 0 : *((uint64_t*) p) = h;
332 : 0 : *((uint32_t*) (p + 8)) = x;
333 : 0 : p[12] = 0;
334 : 0 : p[13] = 'u';
335 : : } else {
336 : : /* (field id byte + (signature length + signature 'u' + NUL) + value) */
337 : 176 : p = message_extend_fields(m, 8, 4 + 4, false);
338 [ - + ]: 176 : if (!p)
339 : 0 : return -ENOMEM;
340 : :
341 : 176 : p[0] = (uint8_t) h;
342 : 176 : p[1] = 1;
343 : 176 : p[2] = 'u';
344 : 176 : p[3] = 0;
345 : :
346 : 176 : ((uint32_t*) p)[1] = x;
347 : : }
348 : :
349 : 176 : return 0;
350 : : }
351 : :
352 : 0 : static int message_append_field_uint64(sd_bus_message *m, uint64_t h, uint64_t x) {
353 : : uint8_t *p;
354 : :
355 [ # # ]: 0 : assert(m);
356 : :
357 : : /* dbus1 only allows 8bit header field ids */
358 [ # # ]: 0 : if (h > 0xFF)
359 : 0 : return -EINVAL;
360 : :
361 [ # # ]: 0 : if (BUS_MESSAGE_IS_GVARIANT(m)) {
362 : : /* (field id 64bit + ((value + NUL + signature string 't') */
363 : :
364 : 0 : p = message_extend_fields(m, 8, 8 + 8 + 1 + 1, true);
365 [ # # ]: 0 : if (!p)
366 : 0 : return -ENOMEM;
367 : :
368 : 0 : *((uint64_t*) p) = h;
369 : 0 : *((uint64_t*) (p + 8)) = x;
370 : 0 : p[16] = 0;
371 : 0 : p[17] = 't';
372 : : } else {
373 : : /* (field id byte + (signature length + signature 't' + NUL) + 4 byte padding + value) */
374 : 0 : p = message_extend_fields(m, 8, 4 + 4 + 8, false);
375 [ # # ]: 0 : if (!p)
376 : 0 : return -ENOMEM;
377 : :
378 : 0 : p[0] = (uint8_t) h;
379 : 0 : p[1] = 1;
380 : 0 : p[2] = 't';
381 : 0 : p[3] = 0;
382 : 0 : p[4] = 0;
383 : 0 : p[5] = 0;
384 : 0 : p[6] = 0;
385 : 0 : p[7] = 0;
386 : :
387 : 0 : ((uint64_t*) p)[1] = x;
388 : : }
389 : :
390 : 0 : return 0;
391 : : }
392 : :
393 : 172 : static int message_append_reply_cookie(sd_bus_message *m, uint64_t cookie) {
394 [ - + ]: 172 : assert(m);
395 : :
396 [ - + ]: 172 : if (BUS_MESSAGE_IS_GVARIANT(m))
397 : 0 : return message_append_field_uint64(m, BUS_MESSAGE_HEADER_REPLY_SERIAL, cookie);
398 : : else {
399 : : /* 64bit cookies are not supported on dbus1 */
400 [ - + ]: 172 : if (cookie > 0xffffffffUL)
401 : 0 : return -EOPNOTSUPP;
402 : :
403 : 172 : return message_append_field_uint32(m, BUS_MESSAGE_HEADER_REPLY_SERIAL, (uint32_t) cookie);
404 : : }
405 : : }
406 : :
407 : 534 : int bus_message_from_header(
408 : : sd_bus *bus,
409 : : void *header,
410 : : size_t header_accessible,
411 : : void *footer,
412 : : size_t footer_accessible,
413 : : size_t message_size,
414 : : int *fds,
415 : : size_t n_fds,
416 : : const char *label,
417 : : size_t extra,
418 : : sd_bus_message **ret) {
419 : :
420 : 534 : _cleanup_free_ sd_bus_message *m = NULL;
421 : : struct bus_header *h;
422 : : size_t a, label_sz;
423 : :
424 [ - + ]: 534 : assert(bus);
425 [ - + # # ]: 534 : assert(header || header_accessible <= 0);
426 [ - + # # ]: 534 : assert(footer || footer_accessible <= 0);
427 [ + + - + ]: 534 : assert(fds || n_fds <= 0);
428 [ - + ]: 534 : assert(ret);
429 : :
430 [ - + ]: 534 : if (header_accessible < sizeof(struct bus_header))
431 : 0 : return -EBADMSG;
432 : :
433 [ - + ]: 534 : if (header_accessible > message_size)
434 : 0 : return -EBADMSG;
435 [ - + ]: 534 : if (footer_accessible > message_size)
436 : 0 : return -EBADMSG;
437 : :
438 : 534 : h = header;
439 [ + - - + ]: 534 : if (!IN_SET(h->version, 1, 2))
440 : 0 : return -EBADMSG;
441 : :
442 [ - + ]: 534 : if (h->type == _SD_BUS_MESSAGE_TYPE_INVALID)
443 : 0 : return -EBADMSG;
444 : :
445 [ + - - + ]: 534 : if (!IN_SET(h->endian, BUS_LITTLE_ENDIAN, BUS_BIG_ENDIAN))
446 : 0 : return -EBADMSG;
447 : :
448 : : /* Note that we are happy with unknown flags in the flags header! */
449 : :
450 : 534 : a = ALIGN(sizeof(sd_bus_message)) + ALIGN(extra);
451 : :
452 [ - + ]: 534 : if (label) {
453 : 0 : label_sz = strlen(label);
454 : 0 : a += label_sz + 1;
455 : : }
456 : :
457 : 534 : m = malloc0(a);
458 [ - + ]: 534 : if (!m)
459 : 0 : return -ENOMEM;
460 : :
461 : 534 : m->sealed = true;
462 : 534 : m->header = header;
463 : 534 : m->header_accessible = header_accessible;
464 : 534 : m->footer = footer;
465 : 534 : m->footer_accessible = footer_accessible;
466 : :
467 [ + + ]: 534 : if (BUS_MESSAGE_IS_GVARIANT(m)) {
468 : : size_t ws;
469 : :
470 [ - + ]: 4 : if (h->dbus2.cookie == 0)
471 : 0 : return -EBADMSG;
472 : :
473 : : /* dbus2 derives the sizes from the message size and
474 : : the offset table at the end, since it is formatted as
475 : : gvariant "yyyyuta{tv}v". Since the message itself is a
476 : : structure with precisely to variable sized entries,
477 : : there's only one offset in the table, which marks the
478 : : end of the fields array. */
479 : :
480 : 4 : ws = bus_gvariant_determine_word_size(message_size, 0);
481 [ - + ]: 4 : if (footer_accessible < ws)
482 : 0 : return -EBADMSG;
483 : :
484 : 4 : m->fields_size = bus_gvariant_read_word_le((uint8_t*) footer + footer_accessible - ws, ws);
485 [ - + ]: 4 : if (ALIGN8(m->fields_size) > message_size - ws)
486 : 0 : return -EBADMSG;
487 [ - + ]: 4 : if (m->fields_size < sizeof(struct bus_header))
488 : 0 : return -EBADMSG;
489 : :
490 : 4 : m->fields_size -= sizeof(struct bus_header);
491 : 4 : m->body_size = message_size - (sizeof(struct bus_header) + ALIGN8(m->fields_size));
492 : : } else {
493 [ - + ]: 530 : if (h->dbus1.serial == 0)
494 : 0 : return -EBADMSG;
495 : :
496 : : /* dbus1 has the sizes in the header */
497 : 530 : m->fields_size = BUS_MESSAGE_BSWAP32(m, h->dbus1.fields_size);
498 : 530 : m->body_size = BUS_MESSAGE_BSWAP32(m, h->dbus1.body_size);
499 : :
500 [ - + ]: 530 : if (sizeof(struct bus_header) + ALIGN8(m->fields_size) + m->body_size != message_size)
501 : 0 : return -EBADMSG;
502 : : }
503 : :
504 : 534 : m->fds = fds;
505 : 534 : m->n_fds = n_fds;
506 : :
507 [ - + ]: 534 : if (label) {
508 : 0 : m->creds.label = (char*) m + ALIGN(sizeof(sd_bus_message)) + ALIGN(extra);
509 : 0 : memcpy(m->creds.label, label, label_sz + 1);
510 : :
511 : 0 : m->creds.mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
512 : : }
513 : :
514 : 534 : m->n_ref = 1;
515 : 534 : m->bus = sd_bus_ref(bus);
516 : :
517 : 534 : *ret = TAKE_PTR(m);
518 : :
519 : 534 : return 0;
520 : : }
521 : :
522 : 534 : int bus_message_from_malloc(
523 : : sd_bus *bus,
524 : : void *buffer,
525 : : size_t length,
526 : : int *fds,
527 : : size_t n_fds,
528 : : const char *label,
529 : : sd_bus_message **ret) {
530 : :
531 : 534 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
532 : : size_t sz;
533 : : int r;
534 : :
535 : 534 : r = bus_message_from_header(
536 : : bus,
537 : : buffer, length, /* in this case the initial bytes and the final bytes are the same */
538 : : buffer, length,
539 : : length,
540 : : fds, n_fds,
541 : : label,
542 : : 0, &m);
543 [ - + ]: 534 : if (r < 0)
544 : 0 : return r;
545 : :
546 : 534 : sz = length - sizeof(struct bus_header) - ALIGN8(m->fields_size);
547 [ + + ]: 534 : if (sz > 0) {
548 : 299 : m->n_body_parts = 1;
549 : 299 : m->body.data = (uint8_t*) buffer + sizeof(struct bus_header) + ALIGN8(m->fields_size);
550 : 299 : m->body.size = sz;
551 : 299 : m->body.sealed = true;
552 : 299 : m->body.memfd = -1;
553 : : }
554 : :
555 : 534 : m->n_iovec = 1;
556 : 534 : m->iovec = m->iovec_fixed;
557 : 534 : m->iovec[0] = IOVEC_MAKE(buffer, length);
558 : :
559 : 534 : r = bus_message_parse_fields(m);
560 [ - + ]: 534 : if (r < 0)
561 : 0 : return r;
562 : :
563 : : /* We take possession of the memory and fds now */
564 : 534 : m->free_header = true;
565 : 534 : m->free_fds = true;
566 : :
567 : 534 : *ret = TAKE_PTR(m);
568 : 534 : return 0;
569 : : }
570 : :
571 : 620 : _public_ int sd_bus_message_new(
572 : : sd_bus *bus,
573 : : sd_bus_message **m,
574 : : uint8_t type) {
575 : :
576 : : sd_bus_message *t;
577 : :
578 [ - + - + ]: 620 : assert_return(bus, -ENOTCONN);
579 [ - + - + ]: 620 : assert_return(bus->state != BUS_UNSET, -ENOTCONN);
580 [ - + - + ]: 620 : assert_return(m, -EINVAL);
581 [ - + - + ]: 620 : assert_return(type < _SD_BUS_MESSAGE_TYPE_MAX, -EINVAL);
582 : :
583 : 620 : t = malloc0(ALIGN(sizeof(sd_bus_message)) + sizeof(struct bus_header));
584 [ - + ]: 620 : if (!t)
585 : 0 : return -ENOMEM;
586 : :
587 : 620 : t->n_ref = 1;
588 : 620 : t->bus = sd_bus_ref(bus);
589 : 620 : t->header = (struct bus_header*) ((uint8_t*) t + ALIGN(sizeof(struct sd_bus_message)));
590 : 620 : t->header->endian = BUS_NATIVE_ENDIAN;
591 : 620 : t->header->type = type;
592 : 620 : t->header->version = bus->message_version;
593 [ + + + + : 620 : t->allow_fds = bus->can_fds || !IN_SET(bus->state, BUS_HELLO, BUS_RUNNING);
+ + ]
594 : 620 : t->root_container.need_offsets = BUS_MESSAGE_IS_GVARIANT(t);
595 : :
596 [ - + ]: 620 : if (bus->allow_interactive_authorization)
597 : 0 : t->header->flags |= BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION;
598 : :
599 : 620 : *m = t;
600 : 620 : return 0;
601 : : }
602 : :
603 : 52 : _public_ int sd_bus_message_new_signal(
604 : : sd_bus *bus,
605 : : sd_bus_message **m,
606 : : const char *path,
607 : : const char *interface,
608 : : const char *member) {
609 : :
610 : 52 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *t = NULL;
611 : : int r;
612 : :
613 [ - + - + ]: 52 : assert_return(bus, -ENOTCONN);
614 [ - + - + ]: 52 : assert_return(bus->state != BUS_UNSET, -ENOTCONN);
615 [ - + - + ]: 52 : assert_return(object_path_is_valid(path), -EINVAL);
616 [ - + - + ]: 52 : assert_return(interface_name_is_valid(interface), -EINVAL);
617 [ - + - + ]: 52 : assert_return(member_name_is_valid(member), -EINVAL);
618 [ - + - + ]: 52 : assert_return(m, -EINVAL);
619 : :
620 : 52 : r = sd_bus_message_new(bus, &t, SD_BUS_MESSAGE_SIGNAL);
621 [ - + ]: 52 : if (r < 0)
622 : 0 : return -ENOMEM;
623 : :
624 [ - + ]: 52 : assert(t);
625 : :
626 : 52 : t->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
627 : :
628 : 52 : r = message_append_field_string(t, BUS_MESSAGE_HEADER_PATH, SD_BUS_TYPE_OBJECT_PATH, path, &t->path);
629 [ - + ]: 52 : if (r < 0)
630 : 0 : return r;
631 : 52 : r = message_append_field_string(t, BUS_MESSAGE_HEADER_INTERFACE, SD_BUS_TYPE_STRING, interface, &t->interface);
632 [ - + ]: 52 : if (r < 0)
633 : 0 : return r;
634 : 52 : r = message_append_field_string(t, BUS_MESSAGE_HEADER_MEMBER, SD_BUS_TYPE_STRING, member, &t->member);
635 [ - + ]: 52 : if (r < 0)
636 : 0 : return r;
637 : :
638 : 52 : *m = TAKE_PTR(t);
639 : 52 : return 0;
640 : : }
641 : :
642 : 396 : _public_ int sd_bus_message_new_method_call(
643 : : sd_bus *bus,
644 : : sd_bus_message **m,
645 : : const char *destination,
646 : : const char *path,
647 : : const char *interface,
648 : : const char *member) {
649 : :
650 : 396 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *t = NULL;
651 : : int r;
652 : :
653 [ - + - + ]: 396 : assert_return(bus, -ENOTCONN);
654 [ - + - + ]: 396 : assert_return(bus->state != BUS_UNSET, -ENOTCONN);
655 [ + - - + : 396 : assert_return(!destination || service_name_is_valid(destination), -EINVAL);
- + ]
656 [ - + - + ]: 396 : assert_return(object_path_is_valid(path), -EINVAL);
657 [ + - - + : 396 : assert_return(!interface || interface_name_is_valid(interface), -EINVAL);
- + ]
658 [ - + - + ]: 396 : assert_return(member_name_is_valid(member), -EINVAL);
659 [ - + - + ]: 396 : assert_return(m, -EINVAL);
660 : :
661 : 396 : r = sd_bus_message_new(bus, &t, SD_BUS_MESSAGE_METHOD_CALL);
662 [ - + ]: 396 : if (r < 0)
663 : 0 : return -ENOMEM;
664 : :
665 [ - + ]: 396 : assert(t);
666 : :
667 : 396 : r = message_append_field_string(t, BUS_MESSAGE_HEADER_PATH, SD_BUS_TYPE_OBJECT_PATH, path, &t->path);
668 [ - + ]: 396 : if (r < 0)
669 : 0 : return r;
670 : 396 : r = message_append_field_string(t, BUS_MESSAGE_HEADER_MEMBER, SD_BUS_TYPE_STRING, member, &t->member);
671 [ - + ]: 396 : if (r < 0)
672 : 0 : return r;
673 : :
674 [ + - ]: 396 : if (interface) {
675 : 396 : r = message_append_field_string(t, BUS_MESSAGE_HEADER_INTERFACE, SD_BUS_TYPE_STRING, interface, &t->interface);
676 [ - + ]: 396 : if (r < 0)
677 : 0 : return r;
678 : : }
679 : :
680 [ + - ]: 396 : if (destination) {
681 : 396 : r = message_append_field_string(t, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, destination, &t->destination);
682 [ - + ]: 396 : if (r < 0)
683 : 0 : return r;
684 : : }
685 : :
686 : 396 : *m = TAKE_PTR(t);
687 : 396 : return 0;
688 : : }
689 : :
690 : 168 : static int message_new_reply(
691 : : sd_bus_message *call,
692 : : uint8_t type,
693 : : sd_bus_message **m) {
694 : :
695 : 168 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *t = NULL;
696 : : uint64_t cookie;
697 : : int r;
698 : :
699 [ - + - + ]: 168 : assert_return(call, -EINVAL);
700 [ - + - + ]: 168 : assert_return(call->sealed, -EPERM);
701 [ - + - + ]: 168 : assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
702 [ - + - + ]: 168 : assert_return(call->bus->state != BUS_UNSET, -ENOTCONN);
703 [ - + - + ]: 168 : assert_return(m, -EINVAL);
704 : :
705 : 168 : cookie = BUS_MESSAGE_COOKIE(call);
706 [ - + ]: 168 : if (cookie == 0)
707 : 0 : return -EOPNOTSUPP;
708 : :
709 : 168 : r = sd_bus_message_new(call->bus, &t, type);
710 [ - + ]: 168 : if (r < 0)
711 : 0 : return -ENOMEM;
712 : :
713 [ - + ]: 168 : assert(t);
714 : :
715 : 168 : t->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
716 : 168 : t->reply_cookie = cookie;
717 : 168 : r = message_append_reply_cookie(t, t->reply_cookie);
718 [ - + ]: 168 : if (r < 0)
719 : 0 : return r;
720 : :
721 [ + + ]: 168 : if (call->sender) {
722 : 20 : r = message_append_field_string(t, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, call->sender, &t->destination);
723 [ - + ]: 20 : if (r < 0)
724 : 0 : return r;
725 : : }
726 : :
727 : 168 : t->dont_send = !!(call->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED);
728 : 168 : t->enforced_reply_signature = call->enforced_reply_signature;
729 : :
730 : 168 : *m = TAKE_PTR(t);
731 : 168 : return 0;
732 : : }
733 : :
734 : 152 : _public_ int sd_bus_message_new_method_return(
735 : : sd_bus_message *call,
736 : : sd_bus_message **m) {
737 : :
738 : 152 : return message_new_reply(call, SD_BUS_MESSAGE_METHOD_RETURN, m);
739 : : }
740 : :
741 : 16 : _public_ int sd_bus_message_new_method_error(
742 : : sd_bus_message *call,
743 : : sd_bus_message **m,
744 : : const sd_bus_error *e) {
745 : :
746 : 16 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *t = NULL;
747 : : int r;
748 : :
749 [ - + - + ]: 16 : assert_return(sd_bus_error_is_set(e), -EINVAL);
750 [ - + - + ]: 16 : assert_return(m, -EINVAL);
751 : :
752 : 16 : r = message_new_reply(call, SD_BUS_MESSAGE_METHOD_ERROR, &t);
753 [ - + ]: 16 : if (r < 0)
754 : 0 : return r;
755 : :
756 : 16 : r = message_append_field_string(t, BUS_MESSAGE_HEADER_ERROR_NAME, SD_BUS_TYPE_STRING, e->name, &t->error.name);
757 [ - + ]: 16 : if (r < 0)
758 : 0 : return r;
759 : :
760 [ + - ]: 16 : if (e->message) {
761 : 16 : r = message_append_basic(t, SD_BUS_TYPE_STRING, e->message, (const void**) &t->error.message);
762 [ - + ]: 16 : if (r < 0)
763 : 0 : return r;
764 : : }
765 : :
766 : 16 : t->error._need_free = -1;
767 : :
768 : 16 : *m = TAKE_PTR(t);
769 : 16 : return 0;
770 : : }
771 : :
772 : 0 : _public_ int sd_bus_message_new_method_errorf(
773 : : sd_bus_message *call,
774 : : sd_bus_message **m,
775 : : const char *name,
776 : : const char *format,
777 : : ...) {
778 : :
779 : 0 : _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
780 : : va_list ap;
781 : :
782 [ # # # # ]: 0 : assert_return(name, -EINVAL);
783 [ # # # # ]: 0 : assert_return(m, -EINVAL);
784 : :
785 : 0 : va_start(ap, format);
786 : 0 : bus_error_setfv(&error, name, format, ap);
787 : 0 : va_end(ap);
788 : :
789 : 0 : return sd_bus_message_new_method_error(call, m, &error);
790 : : }
791 : :
792 : 0 : _public_ int sd_bus_message_new_method_errno(
793 : : sd_bus_message *call,
794 : : sd_bus_message **m,
795 : : int error,
796 : : const sd_bus_error *p) {
797 : :
798 : 0 : _cleanup_(sd_bus_error_free) sd_bus_error berror = SD_BUS_ERROR_NULL;
799 : :
800 [ # # ]: 0 : if (sd_bus_error_is_set(p))
801 : 0 : return sd_bus_message_new_method_error(call, m, p);
802 : :
803 : 0 : sd_bus_error_set_errno(&berror, error);
804 : :
805 : 0 : return sd_bus_message_new_method_error(call, m, &berror);
806 : : }
807 : :
808 : 0 : _public_ int sd_bus_message_new_method_errnof(
809 : : sd_bus_message *call,
810 : : sd_bus_message **m,
811 : : int error,
812 : : const char *format,
813 : : ...) {
814 : :
815 : 0 : _cleanup_(sd_bus_error_free) sd_bus_error berror = SD_BUS_ERROR_NULL;
816 : : va_list ap;
817 : :
818 : 0 : va_start(ap, format);
819 : 0 : sd_bus_error_set_errnofv(&berror, error, format, ap);
820 : 0 : va_end(ap);
821 : :
822 : 0 : return sd_bus_message_new_method_error(call, m, &berror);
823 : : }
824 : :
825 : 8 : void bus_message_set_sender_local(sd_bus *bus, sd_bus_message *m) {
826 [ - + ]: 8 : assert(bus);
827 [ - + ]: 8 : assert(m);
828 : :
829 : 8 : m->sender = m->creds.unique_name = (char*) "org.freedesktop.DBus.Local";
830 : 8 : m->creds.well_known_names_local = true;
831 : 8 : m->creds.mask |= (SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_WELL_KNOWN_NAMES) & bus->creds_mask;
832 : 8 : }
833 : :
834 : 4 : void bus_message_set_sender_driver(sd_bus *bus, sd_bus_message *m) {
835 [ - + ]: 4 : assert(bus);
836 [ - + ]: 4 : assert(m);
837 : :
838 : 4 : m->sender = m->creds.unique_name = (char*) "org.freedesktop.DBus";
839 : 4 : m->creds.well_known_names_driver = true;
840 : 4 : m->creds.mask |= (SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_WELL_KNOWN_NAMES) & bus->creds_mask;
841 : 4 : }
842 : :
843 : 4 : int bus_message_new_synthetic_error(
844 : : sd_bus *bus,
845 : : uint64_t cookie,
846 : : const sd_bus_error *e,
847 : : sd_bus_message **m) {
848 : :
849 : 4 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *t = NULL;
850 : : int r;
851 : :
852 [ - + ]: 4 : assert(bus);
853 [ - + ]: 4 : assert(sd_bus_error_is_set(e));
854 [ - + ]: 4 : assert(m);
855 : :
856 : 4 : r = sd_bus_message_new(bus, &t, SD_BUS_MESSAGE_METHOD_ERROR);
857 [ - + ]: 4 : if (r < 0)
858 : 0 : return -ENOMEM;
859 : :
860 [ - + ]: 4 : assert(t);
861 : :
862 : 4 : t->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
863 : 4 : t->reply_cookie = cookie;
864 : :
865 : 4 : r = message_append_reply_cookie(t, t->reply_cookie);
866 [ - + ]: 4 : if (r < 0)
867 : 0 : return r;
868 : :
869 [ + - + - ]: 4 : if (bus && bus->unique_name) {
870 : 4 : r = message_append_field_string(t, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, bus->unique_name, &t->destination);
871 [ - + ]: 4 : if (r < 0)
872 : 0 : return r;
873 : : }
874 : :
875 : 4 : r = message_append_field_string(t, BUS_MESSAGE_HEADER_ERROR_NAME, SD_BUS_TYPE_STRING, e->name, &t->error.name);
876 [ - + ]: 4 : if (r < 0)
877 : 0 : return r;
878 : :
879 [ + - ]: 4 : if (e->message) {
880 : 4 : r = message_append_basic(t, SD_BUS_TYPE_STRING, e->message, (const void**) &t->error.message);
881 [ - + ]: 4 : if (r < 0)
882 : 0 : return r;
883 : : }
884 : :
885 : 4 : t->error._need_free = -1;
886 : :
887 : 4 : bus_message_set_sender_driver(bus, t);
888 : :
889 : 4 : *m = TAKE_PTR(t);
890 : 4 : return 0;
891 : : }
892 : :
893 : 1490 : _public_ sd_bus_message* sd_bus_message_ref(sd_bus_message *m) {
894 [ - + ]: 1490 : if (!m)
895 : 0 : return NULL;
896 : :
897 : : /* We are fine if this message so far was either explicitly reffed or not reffed but queued into at
898 : : * least one bus connection object. */
899 [ + + - + ]: 1490 : assert(m->n_ref > 0 || m->n_queued > 0);
900 : :
901 : 1490 : m->n_ref++;
902 : :
903 : : /* Each user reference to a bus message shall also be considered a ref on the bus */
904 : 1490 : sd_bus_ref(m->bus);
905 : 1490 : return m;
906 : : }
907 : :
908 : 2680 : _public_ sd_bus_message* sd_bus_message_unref(sd_bus_message *m) {
909 [ + + ]: 2680 : if (!m)
910 : 36 : return NULL;
911 : :
912 [ - + ]: 2644 : assert(m->n_ref > 0);
913 : :
914 : 2644 : sd_bus_unref(m->bus); /* Each regular ref is also a ref on the bus connection. Let's hence drop it
915 : : * here. Note we have to do this before decrementing our own n_ref here, since
916 : : * otherwise, if this message is currently queued sd_bus_unref() might call
917 : : * bus_message_unref_queued() for this which might then destroy the message
918 : : * while we are still processing it. */
919 : 2644 : m->n_ref--;
920 : :
921 [ + + + + ]: 2644 : if (m->n_ref > 0 || m->n_queued > 0)
922 : 1682 : return NULL;
923 : :
924 : : /* Unset the bus field if neither the user has a reference nor this message is queued. We are careful
925 : : * to reset the field only after the last reference to the bus is dropped, after all we might keep
926 : : * multiple references to the bus, once for each reference kept on ourselves. */
927 : 962 : m->bus = NULL;
928 : :
929 : 962 : return message_free(m);
930 : : }
931 : :
932 : 718 : sd_bus_message* bus_message_ref_queued(sd_bus_message *m, sd_bus *bus) {
933 [ - + ]: 718 : if (!m)
934 : 0 : return NULL;
935 : :
936 : : /* If this is a different bus than the message is associated with, then implicitly turn this into a
937 : : * regular reference. This means that you can create a memory leak by enqueuing a message generated
938 : : * on one bus onto another at the same time as enqueueing a message from the second one on the first,
939 : : * as we'll not detect the cyclic references there. */
940 [ - + ]: 718 : if (bus != m->bus)
941 : 0 : return sd_bus_message_ref(m);
942 : :
943 [ - + # # ]: 718 : assert(m->n_ref > 0 || m->n_queued > 0);
944 : 718 : m->n_queued++;
945 : :
946 : 718 : return m;
947 : : }
948 : :
949 : 718 : sd_bus_message* bus_message_unref_queued(sd_bus_message *m, sd_bus *bus) {
950 [ - + ]: 718 : if (!m)
951 : 0 : return NULL;
952 : :
953 [ - + ]: 718 : if (bus != m->bus)
954 : 0 : return sd_bus_message_unref(m);
955 : :
956 [ - + ]: 718 : assert(m->n_queued > 0);
957 : 718 : m->n_queued--;
958 : :
959 [ + + - + ]: 718 : if (m->n_ref > 0 || m->n_queued > 0)
960 : 526 : return NULL;
961 : :
962 : 192 : m->bus = NULL;
963 : :
964 : 192 : return message_free(m);
965 : : }
966 : :
967 : 0 : _public_ int sd_bus_message_get_type(sd_bus_message *m, uint8_t *type) {
968 [ # # # # ]: 0 : assert_return(m, -EINVAL);
969 [ # # # # ]: 0 : assert_return(type, -EINVAL);
970 : :
971 : 0 : *type = m->header->type;
972 : 0 : return 0;
973 : : }
974 : :
975 : 0 : _public_ int sd_bus_message_get_cookie(sd_bus_message *m, uint64_t *cookie) {
976 : : uint64_t c;
977 : :
978 [ # # # # ]: 0 : assert_return(m, -EINVAL);
979 [ # # # # ]: 0 : assert_return(cookie, -EINVAL);
980 : :
981 : 0 : c = BUS_MESSAGE_COOKIE(m);
982 [ # # ]: 0 : if (c == 0)
983 : 0 : return -ENODATA;
984 : :
985 : 0 : *cookie = BUS_MESSAGE_COOKIE(m);
986 : 0 : return 0;
987 : : }
988 : :
989 : 0 : _public_ int sd_bus_message_get_reply_cookie(sd_bus_message *m, uint64_t *cookie) {
990 [ # # # # ]: 0 : assert_return(m, -EINVAL);
991 [ # # # # ]: 0 : assert_return(cookie, -EINVAL);
992 : :
993 [ # # ]: 0 : if (m->reply_cookie == 0)
994 : 0 : return -ENODATA;
995 : :
996 : 0 : *cookie = m->reply_cookie;
997 : 0 : return 0;
998 : : }
999 : :
1000 : 0 : _public_ int sd_bus_message_get_expect_reply(sd_bus_message *m) {
1001 [ # # # # ]: 0 : assert_return(m, -EINVAL);
1002 : :
1003 [ # # ]: 0 : return m->header->type == SD_BUS_MESSAGE_METHOD_CALL &&
1004 [ # # ]: 0 : !(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED);
1005 : : }
1006 : :
1007 : 0 : _public_ int sd_bus_message_get_auto_start(sd_bus_message *m) {
1008 [ # # # # ]: 0 : assert_return(m, -EINVAL);
1009 : :
1010 : 0 : return !(m->header->flags & BUS_MESSAGE_NO_AUTO_START);
1011 : : }
1012 : :
1013 : 0 : _public_ int sd_bus_message_get_allow_interactive_authorization(sd_bus_message *m) {
1014 [ # # # # ]: 0 : assert_return(m, -EINVAL);
1015 : :
1016 [ # # ]: 0 : return m->header->type == SD_BUS_MESSAGE_METHOD_CALL &&
1017 [ # # ]: 0 : (m->header->flags & BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION);
1018 : : }
1019 : :
1020 : 108 : _public_ const char *sd_bus_message_get_path(sd_bus_message *m) {
1021 [ - + - + ]: 108 : assert_return(m, NULL);
1022 : :
1023 : 108 : return m->path;
1024 : : }
1025 : :
1026 : 120 : _public_ const char *sd_bus_message_get_interface(sd_bus_message *m) {
1027 [ - + - + ]: 120 : assert_return(m, NULL);
1028 : :
1029 : 120 : return m->interface;
1030 : : }
1031 : :
1032 : 196 : _public_ const char *sd_bus_message_get_member(sd_bus_message *m) {
1033 [ - + - + ]: 196 : assert_return(m, NULL);
1034 : :
1035 : 196 : return m->member;
1036 : : }
1037 : :
1038 : 104 : _public_ const char *sd_bus_message_get_destination(sd_bus_message *m) {
1039 [ - + - + ]: 104 : assert_return(m, NULL);
1040 : :
1041 : 104 : return m->destination;
1042 : : }
1043 : :
1044 : 104 : _public_ const char *sd_bus_message_get_sender(sd_bus_message *m) {
1045 [ - + - + ]: 104 : assert_return(m, NULL);
1046 : :
1047 : 104 : return m->sender;
1048 : : }
1049 : :
1050 : 0 : _public_ const sd_bus_error *sd_bus_message_get_error(sd_bus_message *m) {
1051 [ # # # # ]: 0 : assert_return(m, NULL);
1052 : :
1053 [ # # ]: 0 : if (!sd_bus_error_is_set(&m->error))
1054 : 0 : return NULL;
1055 : :
1056 : 0 : return &m->error;
1057 : : }
1058 : :
1059 : 0 : _public_ int sd_bus_message_get_monotonic_usec(sd_bus_message *m, uint64_t *usec) {
1060 [ # # # # ]: 0 : assert_return(m, -EINVAL);
1061 [ # # # # ]: 0 : assert_return(usec, -EINVAL);
1062 : :
1063 [ # # ]: 0 : if (m->monotonic <= 0)
1064 : 0 : return -ENODATA;
1065 : :
1066 : 0 : *usec = m->monotonic;
1067 : 0 : return 0;
1068 : : }
1069 : :
1070 : 0 : _public_ int sd_bus_message_get_realtime_usec(sd_bus_message *m, uint64_t *usec) {
1071 [ # # # # ]: 0 : assert_return(m, -EINVAL);
1072 [ # # # # ]: 0 : assert_return(usec, -EINVAL);
1073 : :
1074 [ # # ]: 0 : if (m->realtime <= 0)
1075 : 0 : return -ENODATA;
1076 : :
1077 : 0 : *usec = m->realtime;
1078 : 0 : return 0;
1079 : : }
1080 : :
1081 : 0 : _public_ int sd_bus_message_get_seqnum(sd_bus_message *m, uint64_t *seqnum) {
1082 [ # # # # ]: 0 : assert_return(m, -EINVAL);
1083 [ # # # # ]: 0 : assert_return(seqnum, -EINVAL);
1084 : :
1085 [ # # ]: 0 : if (m->seqnum <= 0)
1086 : 0 : return -ENODATA;
1087 : :
1088 : 0 : *seqnum = m->seqnum;
1089 : 0 : return 0;
1090 : : }
1091 : :
1092 : 148 : _public_ sd_bus_creds *sd_bus_message_get_creds(sd_bus_message *m) {
1093 [ - + - + ]: 148 : assert_return(m, NULL);
1094 : :
1095 [ + + ]: 148 : if (m->creds.mask == 0)
1096 : 92 : return NULL;
1097 : :
1098 : 56 : return &m->creds;
1099 : : }
1100 : :
1101 : 24 : _public_ int sd_bus_message_is_signal(
1102 : : sd_bus_message *m,
1103 : : const char *interface,
1104 : : const char *member) {
1105 : :
1106 [ - + - + ]: 24 : assert_return(m, -EINVAL);
1107 : :
1108 [ - + ]: 24 : if (m->header->type != SD_BUS_MESSAGE_SIGNAL)
1109 : 0 : return 0;
1110 : :
1111 [ + - - + ]: 24 : if (interface && !streq_ptr(m->interface, interface))
1112 : 0 : return 0;
1113 : :
1114 [ + - - + ]: 24 : if (member && !streq_ptr(m->member, member))
1115 : 0 : return 0;
1116 : :
1117 : 24 : return 1;
1118 : : }
1119 : :
1120 : 392 : _public_ int sd_bus_message_is_method_call(
1121 : : sd_bus_message *m,
1122 : : const char *interface,
1123 : : const char *member) {
1124 : :
1125 [ - + - + ]: 392 : assert_return(m, -EINVAL);
1126 : :
1127 [ + + ]: 392 : if (m->header->type != SD_BUS_MESSAGE_METHOD_CALL)
1128 : 152 : return 0;
1129 : :
1130 [ + - + + ]: 240 : if (interface && !streq_ptr(m->interface, interface))
1131 : 108 : return 0;
1132 : :
1133 [ + - + + ]: 132 : if (member && !streq_ptr(m->member, member))
1134 : 52 : return 0;
1135 : :
1136 : 80 : return 1;
1137 : : }
1138 : :
1139 : 27 : _public_ int sd_bus_message_is_method_error(sd_bus_message *m, const char *name) {
1140 [ - + - + ]: 27 : assert_return(m, -EINVAL);
1141 : :
1142 [ + - ]: 27 : if (m->header->type != SD_BUS_MESSAGE_METHOD_ERROR)
1143 : 27 : return 0;
1144 : :
1145 [ # # # # ]: 0 : if (name && !streq_ptr(m->error.name, name))
1146 : 0 : return 0;
1147 : :
1148 : 0 : return 1;
1149 : : }
1150 : :
1151 : 0 : _public_ int sd_bus_message_set_expect_reply(sd_bus_message *m, int b) {
1152 [ # # # # ]: 0 : assert_return(m, -EINVAL);
1153 [ # # # # ]: 0 : assert_return(!m->sealed, -EPERM);
1154 [ # # # # ]: 0 : assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EPERM);
1155 : :
1156 [ # # ]: 0 : SET_FLAG(m->header->flags, BUS_MESSAGE_NO_REPLY_EXPECTED, !b);
1157 : :
1158 : 0 : return 0;
1159 : : }
1160 : :
1161 : 0 : _public_ int sd_bus_message_set_auto_start(sd_bus_message *m, int b) {
1162 [ # # # # ]: 0 : assert_return(m, -EINVAL);
1163 [ # # # # ]: 0 : assert_return(!m->sealed, -EPERM);
1164 : :
1165 [ # # ]: 0 : SET_FLAG(m->header->flags, BUS_MESSAGE_NO_AUTO_START, !b);
1166 : :
1167 : 0 : return 0;
1168 : : }
1169 : :
1170 : 0 : _public_ int sd_bus_message_set_allow_interactive_authorization(sd_bus_message *m, int b) {
1171 [ # # # # ]: 0 : assert_return(m, -EINVAL);
1172 [ # # # # ]: 0 : assert_return(!m->sealed, -EPERM);
1173 : :
1174 [ # # ]: 0 : SET_FLAG(m->header->flags, BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION, b);
1175 : :
1176 : 0 : return 0;
1177 : : }
1178 : :
1179 : 268 : struct bus_body_part *message_append_part(sd_bus_message *m) {
1180 : : struct bus_body_part *part;
1181 : :
1182 [ - + ]: 268 : assert(m);
1183 : :
1184 [ - + ]: 268 : if (m->poisoned)
1185 : 0 : return NULL;
1186 : :
1187 [ + - ]: 268 : if (m->n_body_parts <= 0) {
1188 : 268 : part = &m->body;
1189 [ + - ]: 268 : zero(*part);
1190 : : } else {
1191 [ # # ]: 0 : assert(m->body_end);
1192 : :
1193 : 0 : part = new0(struct bus_body_part, 1);
1194 [ # # ]: 0 : if (!part) {
1195 : 0 : m->poisoned = true;
1196 : 0 : return NULL;
1197 : : }
1198 : :
1199 : 0 : m->body_end->next = part;
1200 : : }
1201 : :
1202 : 268 : part->memfd = -1;
1203 : 268 : m->body_end = part;
1204 : 268 : m->n_body_parts++;
1205 : :
1206 : 268 : return part;
1207 : : }
1208 : :
1209 : 0 : static void part_zero(struct bus_body_part *part, size_t sz) {
1210 [ # # ]: 0 : assert(part);
1211 [ # # ]: 0 : assert(sz > 0);
1212 [ # # ]: 0 : assert(sz < 8);
1213 : :
1214 : : /* All other fields can be left in their defaults */
1215 [ # # ]: 0 : assert(!part->data);
1216 [ # # ]: 0 : assert(part->memfd < 0);
1217 : :
1218 : 0 : part->size = sz;
1219 : 0 : part->is_zero = true;
1220 : 0 : part->sealed = true;
1221 : 0 : }
1222 : :
1223 : 1736 : static int part_make_space(
1224 : : struct sd_bus_message *m,
1225 : : struct bus_body_part *part,
1226 : : size_t sz,
1227 : : void **q) {
1228 : :
1229 : : void *n;
1230 : :
1231 [ - + ]: 1736 : assert(m);
1232 [ - + ]: 1736 : assert(part);
1233 [ - + ]: 1736 : assert(!part->sealed);
1234 : :
1235 [ - + ]: 1736 : if (m->poisoned)
1236 : 0 : return -ENOMEM;
1237 : :
1238 [ + + + + ]: 1736 : if (part->allocated == 0 || sz > part->allocated) {
1239 : : size_t new_allocated;
1240 : :
1241 [ + - ]: 424 : new_allocated = sz > 0 ? 2 * sz : 64;
1242 : 424 : n = realloc(part->data, new_allocated);
1243 [ - + ]: 424 : if (!n) {
1244 : 0 : m->poisoned = true;
1245 : 0 : return -ENOMEM;
1246 : : }
1247 : :
1248 : 424 : part->data = n;
1249 : 424 : part->allocated = new_allocated;
1250 : 424 : part->free_this = true;
1251 : : }
1252 : :
1253 [ + - ]: 1736 : if (q)
1254 [ + - ]: 1736 : *q = part->data ? (uint8_t*) part->data + part->size : NULL;
1255 : :
1256 : 1736 : part->size = sz;
1257 : 1736 : return 0;
1258 : : }
1259 : :
1260 : 112 : static int message_add_offset(sd_bus_message *m, size_t offset) {
1261 : : struct bus_container *c;
1262 : :
1263 [ - + ]: 112 : assert(m);
1264 [ - + ]: 112 : assert(BUS_MESSAGE_IS_GVARIANT(m));
1265 : :
1266 : : /* Add offset to current container, unless this is the first
1267 : : * item in it, which will have the 0 offset, which we can
1268 : : * ignore. */
1269 : 112 : c = message_get_last_container(m);
1270 : :
1271 [ + + ]: 112 : if (!c->need_offsets)
1272 : 20 : return 0;
1273 : :
1274 [ - + ]: 92 : if (!GREEDY_REALLOC(c->offsets, c->offsets_allocated, c->n_offsets + 1))
1275 : 0 : return -ENOMEM;
1276 : :
1277 : 92 : c->offsets[c->n_offsets++] = offset;
1278 : 92 : return 0;
1279 : : }
1280 : :
1281 : 2036 : static void message_extend_containers(sd_bus_message *m, size_t expand) {
1282 : : struct bus_container *c;
1283 : :
1284 [ - + ]: 2036 : assert(m);
1285 : :
1286 [ + + ]: 2036 : if (expand <= 0)
1287 : 300 : return;
1288 : :
1289 : : /* Update counters */
1290 [ + + ]: 5304 : for (c = m->containers; c < m->containers + m->n_containers; c++) {
1291 : :
1292 [ + + ]: 3568 : if (c->array_size)
1293 : 1640 : *c->array_size += expand;
1294 : : }
1295 : : }
1296 : :
1297 : 2036 : static void *message_extend_body(
1298 : : sd_bus_message *m,
1299 : : size_t align,
1300 : : size_t sz,
1301 : : bool add_offset,
1302 : : bool force_inline) {
1303 : :
1304 : : size_t start_body, end_body, padding, added;
1305 : : void *p;
1306 : : int r;
1307 : :
1308 [ - + ]: 2036 : assert(m);
1309 [ - + ]: 2036 : assert(align > 0);
1310 [ - + ]: 2036 : assert(!m->sealed);
1311 : :
1312 [ - + ]: 2036 : if (m->poisoned)
1313 : 0 : return NULL;
1314 : :
1315 : 2036 : start_body = ALIGN_TO((size_t) m->body_size, align);
1316 : 2036 : end_body = start_body + sz;
1317 : :
1318 : 2036 : padding = start_body - m->body_size;
1319 : 2036 : added = padding + sz;
1320 : :
1321 : : /* Check for 32bit overflows */
1322 [ + - - + ]: 2036 : if (end_body > (size_t) ((uint32_t) -1) ||
1323 : : end_body < start_body) {
1324 : 0 : m->poisoned = true;
1325 : 0 : return NULL;
1326 : : }
1327 : :
1328 [ + + ]: 2036 : if (added > 0) {
1329 : 1736 : struct bus_body_part *part = NULL;
1330 : : bool add_new_part;
1331 : :
1332 : 1736 : add_new_part =
1333 : 3204 : m->n_body_parts <= 0 ||
1334 [ + - ]: 1468 : m->body_end->sealed ||
1335 [ + + + - : 3208 : (padding != ALIGN_TO(m->body_end->size, align) - m->body_end->size) ||
+ + ]
1336 [ - + ]: 4 : (force_inline && m->body_end->size > MEMFD_MIN_SIZE);
1337 : : /* If this must be an inlined extension, let's create a new part if
1338 : : * the previous part is large enough to be inlined. */
1339 : :
1340 [ + + ]: 1736 : if (add_new_part) {
1341 [ - + ]: 268 : if (padding > 0) {
1342 : 0 : part = message_append_part(m);
1343 [ # # ]: 0 : if (!part)
1344 : 0 : return NULL;
1345 : :
1346 : 0 : part_zero(part, padding);
1347 : : }
1348 : :
1349 : 268 : part = message_append_part(m);
1350 [ - + ]: 268 : if (!part)
1351 : 0 : return NULL;
1352 : :
1353 : 268 : r = part_make_space(m, part, sz, &p);
1354 [ - + ]: 268 : if (r < 0)
1355 : 0 : return NULL;
1356 : : } else {
1357 : : struct bus_container *c;
1358 : : void *op;
1359 : : size_t os, start_part, end_part;
1360 : :
1361 : 1468 : part = m->body_end;
1362 : 1468 : op = part->data;
1363 : 1468 : os = part->size;
1364 : :
1365 : 1468 : start_part = ALIGN_TO(part->size, align);
1366 : 1468 : end_part = start_part + sz;
1367 : :
1368 : 1468 : r = part_make_space(m, part, end_part, &p);
1369 [ - + ]: 1468 : if (r < 0)
1370 : 0 : return NULL;
1371 : :
1372 [ + + ]: 1468 : if (padding > 0) {
1373 [ + - ]: 684 : memzero(p, padding);
1374 : 684 : p = (uint8_t*) p + padding;
1375 : : }
1376 : :
1377 : : /* Readjust pointers */
1378 [ + + ]: 5028 : for (c = m->containers; c < m->containers + m->n_containers; c++)
1379 : 3560 : c->array_size = adjust_pointer(c->array_size, op, os, part->data);
1380 : :
1381 : 1468 : m->error.message = (const char*) adjust_pointer(m->error.message, op, os, part->data);
1382 : : }
1383 : : } else
1384 : : /* Return something that is not NULL and is aligned */
1385 : 300 : p = (uint8_t*) align;
1386 : :
1387 : 2036 : m->body_size = end_body;
1388 : 2036 : message_extend_containers(m, added);
1389 : :
1390 [ + + ]: 2036 : if (add_offset) {
1391 : 112 : r = message_add_offset(m, end_body);
1392 [ - + ]: 112 : if (r < 0) {
1393 : 0 : m->poisoned = true;
1394 : 0 : return NULL;
1395 : : }
1396 : : }
1397 : :
1398 : 2036 : return p;
1399 : : }
1400 : :
1401 : 4 : static int message_push_fd(sd_bus_message *m, int fd) {
1402 : : int *f, copy;
1403 : :
1404 [ - + ]: 4 : assert(m);
1405 : :
1406 [ - + ]: 4 : if (fd < 0)
1407 : 0 : return -EINVAL;
1408 : :
1409 [ - + ]: 4 : if (!m->allow_fds)
1410 : 0 : return -EOPNOTSUPP;
1411 : :
1412 : 4 : copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
1413 [ - + ]: 4 : if (copy < 0)
1414 : 0 : return -errno;
1415 : :
1416 : 4 : f = reallocarray(m->fds, sizeof(int), m->n_fds + 1);
1417 [ - + ]: 4 : if (!f) {
1418 : 0 : m->poisoned = true;
1419 : 0 : safe_close(copy);
1420 : 0 : return -ENOMEM;
1421 : : }
1422 : :
1423 : 4 : m->fds = f;
1424 : 4 : m->fds[m->n_fds] = copy;
1425 : 4 : m->free_fds = true;
1426 : :
1427 : 4 : return copy;
1428 : : }
1429 : :
1430 : 1024 : int message_append_basic(sd_bus_message *m, char type, const void *p, const void **stored) {
1431 : 1024 : _cleanup_close_ int fd = -1;
1432 : : struct bus_container *c;
1433 : : ssize_t align, sz;
1434 : : void *a;
1435 : :
1436 [ - + - + ]: 1024 : assert_return(m, -EINVAL);
1437 [ - + - + ]: 1024 : assert_return(!m->sealed, -EPERM);
1438 [ - + - + ]: 1024 : assert_return(bus_type_is_basic(type), -EINVAL);
1439 [ - + - + ]: 1024 : assert_return(!m->poisoned, -ESTALE);
1440 : :
1441 : 1024 : c = message_get_last_container(m);
1442 : :
1443 [ + + + + ]: 1024 : if (c->signature && c->signature[c->index]) {
1444 : : /* Container signature is already set */
1445 : :
1446 [ - + ]: 684 : if (c->signature[c->index] != type)
1447 : 0 : return -ENXIO;
1448 : : } else {
1449 : : char *e;
1450 : :
1451 : : /* Maybe we can append to the signature? But only if this is the top-level container */
1452 [ - + ]: 340 : if (c->enclosing != 0)
1453 : 0 : return -ENXIO;
1454 : :
1455 : 340 : e = strextend(&c->signature, CHAR_TO_STR(type), NULL);
1456 [ - + ]: 340 : if (!e) {
1457 : 0 : m->poisoned = true;
1458 : 0 : return -ENOMEM;
1459 : : }
1460 : : }
1461 : :
1462 [ + + ]: 1024 : if (BUS_MESSAGE_IS_GVARIANT(m)) {
1463 : : uint8_t u8;
1464 : : uint32_t u32;
1465 : :
1466 [ + - - - : 56 : switch (type) {
+ ]
1467 : :
1468 : 24 : case SD_BUS_TYPE_SIGNATURE:
1469 : : case SD_BUS_TYPE_STRING:
1470 : 24 : p = strempty(p);
1471 : :
1472 : : _fallthrough_;
1473 : 24 : case SD_BUS_TYPE_OBJECT_PATH:
1474 [ - + ]: 24 : if (!p)
1475 : 0 : return -EINVAL;
1476 : :
1477 : 24 : align = 1;
1478 : 24 : sz = strlen(p) + 1;
1479 : 24 : break;
1480 : :
1481 : 0 : case SD_BUS_TYPE_BOOLEAN:
1482 : :
1483 [ # # # # ]: 0 : u8 = p && *(int*) p;
1484 : 0 : p = &u8;
1485 : :
1486 : 0 : align = sz = 1;
1487 : 0 : break;
1488 : :
1489 : 0 : case SD_BUS_TYPE_UNIX_FD:
1490 : :
1491 [ # # ]: 0 : if (!p)
1492 : 0 : return -EINVAL;
1493 : :
1494 : 0 : fd = message_push_fd(m, *(int*) p);
1495 [ # # ]: 0 : if (fd < 0)
1496 : 0 : return fd;
1497 : :
1498 : 0 : u32 = m->n_fds;
1499 : 0 : p = &u32;
1500 : :
1501 : 0 : align = sz = 4;
1502 : 0 : break;
1503 : :
1504 : 32 : default:
1505 : 32 : align = bus_gvariant_get_alignment(CHAR_TO_STR(type));
1506 : 32 : sz = bus_gvariant_get_size(CHAR_TO_STR(type));
1507 : 32 : break;
1508 : : }
1509 : :
1510 [ - + ]: 56 : assert(align > 0);
1511 [ - + ]: 56 : assert(sz > 0);
1512 : :
1513 : 56 : a = message_extend_body(m, align, sz, true, false);
1514 [ - + ]: 56 : if (!a)
1515 : 0 : return -ENOMEM;
1516 : :
1517 : 56 : memcpy(a, p, sz);
1518 : :
1519 [ - + ]: 56 : if (stored)
1520 : 0 : *stored = (const uint8_t*) a;
1521 : :
1522 : : } else {
1523 : : uint32_t u32;
1524 : :
1525 [ + + + + : 968 : switch (type) {
+ + ]
1526 : :
1527 : 780 : case SD_BUS_TYPE_STRING:
1528 : : /* To make things easy we'll serialize a NULL string
1529 : : * into the empty string */
1530 : 780 : p = strempty(p);
1531 : :
1532 : : _fallthrough_;
1533 : 816 : case SD_BUS_TYPE_OBJECT_PATH:
1534 : :
1535 [ - + ]: 816 : if (!p)
1536 : 0 : return -EINVAL;
1537 : :
1538 : 816 : align = 4;
1539 : 816 : sz = 4 + strlen(p) + 1;
1540 : 816 : break;
1541 : :
1542 : 8 : case SD_BUS_TYPE_SIGNATURE:
1543 : :
1544 : 8 : p = strempty(p);
1545 : :
1546 : 8 : align = 1;
1547 : 8 : sz = 1 + strlen(p) + 1;
1548 : 8 : break;
1549 : :
1550 : 8 : case SD_BUS_TYPE_BOOLEAN:
1551 : :
1552 [ + - + - ]: 8 : u32 = p && *(int*) p;
1553 : 8 : p = &u32;
1554 : :
1555 : 8 : align = sz = 4;
1556 : 8 : break;
1557 : :
1558 : 4 : case SD_BUS_TYPE_UNIX_FD:
1559 : :
1560 [ - + ]: 4 : if (!p)
1561 : 0 : return -EINVAL;
1562 : :
1563 : 4 : fd = message_push_fd(m, *(int*) p);
1564 [ - + ]: 4 : if (fd < 0)
1565 : 0 : return fd;
1566 : :
1567 : 4 : u32 = m->n_fds;
1568 : 4 : p = &u32;
1569 : :
1570 : 4 : align = sz = 4;
1571 : 4 : break;
1572 : :
1573 : 132 : default:
1574 : 132 : align = bus_type_get_alignment(type);
1575 : 132 : sz = bus_type_get_size(type);
1576 : 132 : break;
1577 : : }
1578 : :
1579 [ - + ]: 968 : assert(align > 0);
1580 [ - + ]: 968 : assert(sz > 0);
1581 : :
1582 : 968 : a = message_extend_body(m, align, sz, false, false);
1583 [ - + ]: 968 : if (!a)
1584 : 0 : return -ENOMEM;
1585 : :
1586 [ + + + + ]: 968 : if (IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH)) {
1587 : 816 : *(uint32_t*) a = sz - 5;
1588 : 816 : memcpy((uint8_t*) a + 4, p, sz - 4);
1589 : :
1590 [ + + ]: 816 : if (stored)
1591 : 20 : *stored = (const uint8_t*) a + 4;
1592 : :
1593 [ + + ]: 152 : } else if (type == SD_BUS_TYPE_SIGNATURE) {
1594 : 8 : *(uint8_t*) a = sz - 2;
1595 : 8 : memcpy((uint8_t*) a + 1, p, sz - 1);
1596 : :
1597 [ - + ]: 8 : if (stored)
1598 : 0 : *stored = (const uint8_t*) a + 1;
1599 : : } else {
1600 : 144 : memcpy(a, p, sz);
1601 : :
1602 [ - + ]: 144 : if (stored)
1603 : 0 : *stored = a;
1604 : : }
1605 : : }
1606 : :
1607 [ + + ]: 1024 : if (type == SD_BUS_TYPE_UNIX_FD)
1608 : 4 : m->n_fds++;
1609 : :
1610 [ + + ]: 1024 : if (c->enclosing != SD_BUS_TYPE_ARRAY)
1611 : 884 : c->index++;
1612 : :
1613 : 1024 : fd = -1;
1614 : 1024 : return 0;
1615 : : }
1616 : :
1617 : 1004 : _public_ int sd_bus_message_append_basic(sd_bus_message *m, char type, const void *p) {
1618 : 1004 : return message_append_basic(m, type, p, NULL);
1619 : : }
1620 : :
1621 : 4 : _public_ int sd_bus_message_append_string_space(
1622 : : sd_bus_message *m,
1623 : : size_t size,
1624 : : char **s) {
1625 : :
1626 : : struct bus_container *c;
1627 : : void *a;
1628 : :
1629 [ - + - + ]: 4 : assert_return(m, -EINVAL);
1630 [ - + - + ]: 4 : assert_return(s, -EINVAL);
1631 [ - + - + ]: 4 : assert_return(!m->sealed, -EPERM);
1632 [ - + - + ]: 4 : assert_return(!m->poisoned, -ESTALE);
1633 : :
1634 : 4 : c = message_get_last_container(m);
1635 : :
1636 [ + - - + ]: 4 : if (c->signature && c->signature[c->index]) {
1637 : : /* Container signature is already set */
1638 : :
1639 [ # # ]: 0 : if (c->signature[c->index] != SD_BUS_TYPE_STRING)
1640 : 0 : return -ENXIO;
1641 : : } else {
1642 : : char *e;
1643 : :
1644 : : /* Maybe we can append to the signature? But only if this is the top-level container */
1645 [ - + ]: 4 : if (c->enclosing != 0)
1646 : 0 : return -ENXIO;
1647 : :
1648 : 4 : e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRING), NULL);
1649 [ - + ]: 4 : if (!e) {
1650 : 0 : m->poisoned = true;
1651 : 0 : return -ENOMEM;
1652 : : }
1653 : : }
1654 : :
1655 [ - + ]: 4 : if (BUS_MESSAGE_IS_GVARIANT(m)) {
1656 : 0 : a = message_extend_body(m, 1, size + 1, true, false);
1657 [ # # ]: 0 : if (!a)
1658 : 0 : return -ENOMEM;
1659 : :
1660 : 0 : *s = a;
1661 : : } else {
1662 : 4 : a = message_extend_body(m, 4, 4 + size + 1, false, false);
1663 [ - + ]: 4 : if (!a)
1664 : 0 : return -ENOMEM;
1665 : :
1666 : 4 : *(uint32_t*) a = size;
1667 : 4 : *s = (char*) a + 4;
1668 : : }
1669 : :
1670 : 4 : (*s)[size] = 0;
1671 : :
1672 [ + - ]: 4 : if (c->enclosing != SD_BUS_TYPE_ARRAY)
1673 : 4 : c->index++;
1674 : :
1675 : 4 : return 0;
1676 : : }
1677 : :
1678 : 0 : _public_ int sd_bus_message_append_string_iovec(
1679 : : sd_bus_message *m,
1680 : : const struct iovec *iov,
1681 : : unsigned n /* should be size_t, but is API now… 😞 */) {
1682 : :
1683 : : size_t size;
1684 : : unsigned i;
1685 : : char *p;
1686 : : int r;
1687 : :
1688 [ # # # # ]: 0 : assert_return(m, -EINVAL);
1689 [ # # # # ]: 0 : assert_return(!m->sealed, -EPERM);
1690 [ # # # # : 0 : assert_return(iov || n == 0, -EINVAL);
# # ]
1691 [ # # # # ]: 0 : assert_return(!m->poisoned, -ESTALE);
1692 : :
1693 : 0 : size = IOVEC_TOTAL_SIZE(iov, n);
1694 : :
1695 : 0 : r = sd_bus_message_append_string_space(m, size, &p);
1696 [ # # ]: 0 : if (r < 0)
1697 : 0 : return r;
1698 : :
1699 [ # # ]: 0 : for (i = 0; i < n; i++) {
1700 : :
1701 [ # # ]: 0 : if (iov[i].iov_base)
1702 : 0 : memcpy(p, iov[i].iov_base, iov[i].iov_len);
1703 : : else
1704 : 0 : memset(p, ' ', iov[i].iov_len);
1705 : :
1706 : 0 : p += iov[i].iov_len;
1707 : : }
1708 : :
1709 : 0 : return 0;
1710 : : }
1711 : :
1712 : 236 : static int bus_message_open_array(
1713 : : sd_bus_message *m,
1714 : : struct bus_container *c,
1715 : : const char *contents,
1716 : : uint32_t **array_size,
1717 : : size_t *begin,
1718 : : bool *need_offsets) {
1719 : :
1720 : : unsigned nindex;
1721 : : int alignment, r;
1722 : :
1723 [ - + ]: 236 : assert(m);
1724 [ - + ]: 236 : assert(c);
1725 [ - + ]: 236 : assert(contents);
1726 [ - + ]: 236 : assert(array_size);
1727 [ - + ]: 236 : assert(begin);
1728 [ - + ]: 236 : assert(need_offsets);
1729 : :
1730 [ - + ]: 236 : if (!signature_is_single(contents, true))
1731 : 0 : return -EINVAL;
1732 : :
1733 [ + + + + ]: 236 : if (c->signature && c->signature[c->index]) {
1734 : :
1735 : : /* Verify the existing signature */
1736 : :
1737 [ - + ]: 100 : if (c->signature[c->index] != SD_BUS_TYPE_ARRAY)
1738 : 0 : return -ENXIO;
1739 : :
1740 [ - + ]: 100 : if (!startswith(c->signature + c->index + 1, contents))
1741 : 0 : return -ENXIO;
1742 : :
1743 : 100 : nindex = c->index + 1 + strlen(contents);
1744 : : } else {
1745 : : char *e;
1746 : :
1747 [ - + ]: 136 : if (c->enclosing != 0)
1748 : 0 : return -ENXIO;
1749 : :
1750 : : /* Extend the existing signature */
1751 : :
1752 : 136 : e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_ARRAY), contents, NULL);
1753 [ - + ]: 136 : if (!e) {
1754 : 0 : m->poisoned = true;
1755 : 0 : return -ENOMEM;
1756 : : }
1757 : :
1758 : 136 : nindex = e - c->signature;
1759 : : }
1760 : :
1761 [ + + ]: 236 : if (BUS_MESSAGE_IS_GVARIANT(m)) {
1762 : 12 : alignment = bus_gvariant_get_alignment(contents);
1763 [ - + ]: 12 : if (alignment < 0)
1764 : 0 : return alignment;
1765 : :
1766 : : /* Add alignment padding and add to offset list */
1767 [ - + ]: 12 : if (!message_extend_body(m, alignment, 0, false, false))
1768 : 0 : return -ENOMEM;
1769 : :
1770 : 12 : r = bus_gvariant_is_fixed_size(contents);
1771 [ - + ]: 12 : if (r < 0)
1772 : 0 : return r;
1773 : :
1774 : 12 : *begin = m->body_size;
1775 : 12 : *need_offsets = r == 0;
1776 : : } else {
1777 : : void *a, *op;
1778 : : size_t os;
1779 : : struct bus_body_part *o;
1780 : :
1781 : 224 : alignment = bus_type_get_alignment(contents[0]);
1782 [ - + ]: 224 : if (alignment < 0)
1783 : 0 : return alignment;
1784 : :
1785 : 224 : a = message_extend_body(m, 4, 4, false, false);
1786 [ - + ]: 224 : if (!a)
1787 : 0 : return -ENOMEM;
1788 : :
1789 : 224 : o = m->body_end;
1790 : 224 : op = m->body_end->data;
1791 : 224 : os = m->body_end->size;
1792 : :
1793 : : /* Add alignment between size and first element */
1794 [ - + ]: 224 : if (!message_extend_body(m, alignment, 0, false, false))
1795 : 0 : return -ENOMEM;
1796 : :
1797 : : /* location of array size might have changed so let's readjust a */
1798 [ + - ]: 224 : if (o == m->body_end)
1799 : 224 : a = adjust_pointer(a, op, os, m->body_end->data);
1800 : :
1801 : 224 : *(uint32_t*) a = 0;
1802 : 224 : *array_size = a;
1803 : : }
1804 : :
1805 [ + - ]: 236 : if (c->enclosing != SD_BUS_TYPE_ARRAY)
1806 : 236 : c->index = nindex;
1807 : :
1808 : 236 : return 0;
1809 : : }
1810 : :
1811 : 164 : static int bus_message_open_variant(
1812 : : sd_bus_message *m,
1813 : : struct bus_container *c,
1814 : : const char *contents) {
1815 : :
1816 [ - + ]: 164 : assert(m);
1817 [ - + ]: 164 : assert(c);
1818 [ - + ]: 164 : assert(contents);
1819 : :
1820 [ - + ]: 164 : if (!signature_is_single(contents, false))
1821 : 0 : return -EINVAL;
1822 : :
1823 [ - + ]: 164 : if (*contents == SD_BUS_TYPE_DICT_ENTRY_BEGIN)
1824 : 0 : return -EINVAL;
1825 : :
1826 [ + + + + ]: 164 : if (c->signature && c->signature[c->index]) {
1827 : :
1828 [ - + ]: 140 : if (c->signature[c->index] != SD_BUS_TYPE_VARIANT)
1829 : 0 : return -ENXIO;
1830 : :
1831 : : } else {
1832 : : char *e;
1833 : :
1834 [ - + ]: 24 : if (c->enclosing != 0)
1835 : 0 : return -ENXIO;
1836 : :
1837 : 24 : e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_VARIANT), NULL);
1838 [ - + ]: 24 : if (!e) {
1839 : 0 : m->poisoned = true;
1840 : 0 : return -ENOMEM;
1841 : : }
1842 : : }
1843 : :
1844 [ + + ]: 164 : if (BUS_MESSAGE_IS_GVARIANT(m)) {
1845 : : /* Variants are always aligned to 8 */
1846 : :
1847 [ - + ]: 12 : if (!message_extend_body(m, 8, 0, false, false))
1848 : 0 : return -ENOMEM;
1849 : :
1850 : : } else {
1851 : : size_t l;
1852 : : void *a;
1853 : :
1854 : 152 : l = strlen(contents);
1855 : 152 : a = message_extend_body(m, 1, 1 + l + 1, false, false);
1856 [ - + ]: 152 : if (!a)
1857 : 0 : return -ENOMEM;
1858 : :
1859 : 152 : *(uint8_t*) a = l;
1860 : 152 : memcpy((uint8_t*) a + 1, contents, l + 1);
1861 : : }
1862 : :
1863 [ + - ]: 164 : if (c->enclosing != SD_BUS_TYPE_ARRAY)
1864 : 164 : c->index++;
1865 : :
1866 : 164 : return 0;
1867 : : }
1868 : :
1869 : 80 : static int bus_message_open_struct(
1870 : : sd_bus_message *m,
1871 : : struct bus_container *c,
1872 : : const char *contents,
1873 : : size_t *begin,
1874 : : bool *need_offsets) {
1875 : :
1876 : : size_t nindex;
1877 : : int r;
1878 : :
1879 [ - + ]: 80 : assert(m);
1880 [ - + ]: 80 : assert(c);
1881 [ - + ]: 80 : assert(contents);
1882 [ - + ]: 80 : assert(begin);
1883 [ - + ]: 80 : assert(need_offsets);
1884 : :
1885 [ - + ]: 80 : if (!signature_is_valid(contents, false))
1886 : 0 : return -EINVAL;
1887 : :
1888 [ + - + + ]: 80 : if (c->signature && c->signature[c->index]) {
1889 : : size_t l;
1890 : :
1891 : 64 : l = strlen(contents);
1892 : :
1893 [ + - + - ]: 128 : if (c->signature[c->index] != SD_BUS_TYPE_STRUCT_BEGIN ||
1894 : 64 : !startswith(c->signature + c->index + 1, contents) ||
1895 [ - + ]: 64 : c->signature[c->index + 1 + l] != SD_BUS_TYPE_STRUCT_END)
1896 : 0 : return -ENXIO;
1897 : :
1898 : 64 : nindex = c->index + 1 + l + 1;
1899 : : } else {
1900 : : char *e;
1901 : :
1902 [ - + ]: 16 : if (c->enclosing != 0)
1903 : 0 : return -ENXIO;
1904 : :
1905 : 16 : e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRUCT_BEGIN), contents, CHAR_TO_STR(SD_BUS_TYPE_STRUCT_END), NULL);
1906 [ - + ]: 16 : if (!e) {
1907 : 0 : m->poisoned = true;
1908 : 0 : return -ENOMEM;
1909 : : }
1910 : :
1911 : 16 : nindex = e - c->signature;
1912 : : }
1913 : :
1914 [ + + ]: 80 : if (BUS_MESSAGE_IS_GVARIANT(m)) {
1915 : : int alignment;
1916 : :
1917 : 32 : alignment = bus_gvariant_get_alignment(contents);
1918 [ - + ]: 32 : if (alignment < 0)
1919 : 0 : return alignment;
1920 : :
1921 [ - + ]: 32 : if (!message_extend_body(m, alignment, 0, false, false))
1922 : 0 : return -ENOMEM;
1923 : :
1924 : 32 : r = bus_gvariant_is_fixed_size(contents);
1925 [ - + ]: 32 : if (r < 0)
1926 : 0 : return r;
1927 : :
1928 : 32 : *begin = m->body_size;
1929 : 32 : *need_offsets = r == 0;
1930 : : } else {
1931 : : /* Align contents to 8 byte boundary */
1932 [ - + ]: 48 : if (!message_extend_body(m, 8, 0, false, false))
1933 : 0 : return -ENOMEM;
1934 : : }
1935 : :
1936 [ + + ]: 80 : if (c->enclosing != SD_BUS_TYPE_ARRAY)
1937 : 28 : c->index = nindex;
1938 : :
1939 : 80 : return 0;
1940 : : }
1941 : :
1942 : 224 : static int bus_message_open_dict_entry(
1943 : : sd_bus_message *m,
1944 : : struct bus_container *c,
1945 : : const char *contents,
1946 : : size_t *begin,
1947 : : bool *need_offsets) {
1948 : :
1949 : : int r;
1950 : :
1951 [ - + ]: 224 : assert(m);
1952 [ - + ]: 224 : assert(c);
1953 [ - + ]: 224 : assert(contents);
1954 [ - + ]: 224 : assert(begin);
1955 [ - + ]: 224 : assert(need_offsets);
1956 : :
1957 [ - + ]: 224 : if (!signature_is_pair(contents))
1958 : 0 : return -EINVAL;
1959 : :
1960 [ - + ]: 224 : if (c->enclosing != SD_BUS_TYPE_ARRAY)
1961 : 0 : return -ENXIO;
1962 : :
1963 [ + - + - ]: 448 : if (c->signature && c->signature[c->index]) {
1964 : : size_t l;
1965 : :
1966 : 224 : l = strlen(contents);
1967 : :
1968 [ + - + - ]: 448 : if (c->signature[c->index] != SD_BUS_TYPE_DICT_ENTRY_BEGIN ||
1969 : 224 : !startswith(c->signature + c->index + 1, contents) ||
1970 [ - + ]: 224 : c->signature[c->index + 1 + l] != SD_BUS_TYPE_DICT_ENTRY_END)
1971 : 0 : return -ENXIO;
1972 : : } else
1973 : 0 : return -ENXIO;
1974 : :
1975 [ - + ]: 224 : if (BUS_MESSAGE_IS_GVARIANT(m)) {
1976 : : int alignment;
1977 : :
1978 : 0 : alignment = bus_gvariant_get_alignment(contents);
1979 [ # # ]: 0 : if (alignment < 0)
1980 : 0 : return alignment;
1981 : :
1982 [ # # ]: 0 : if (!message_extend_body(m, alignment, 0, false, false))
1983 : 0 : return -ENOMEM;
1984 : :
1985 : 0 : r = bus_gvariant_is_fixed_size(contents);
1986 [ # # ]: 0 : if (r < 0)
1987 : 0 : return r;
1988 : :
1989 : 0 : *begin = m->body_size;
1990 : 0 : *need_offsets = r == 0;
1991 : : } else {
1992 : : /* Align contents to 8 byte boundary */
1993 [ - + ]: 224 : if (!message_extend_body(m, 8, 0, false, false))
1994 : 0 : return -ENOMEM;
1995 : : }
1996 : :
1997 : 224 : return 0;
1998 : : }
1999 : :
2000 : 704 : _public_ int sd_bus_message_open_container(
2001 : : sd_bus_message *m,
2002 : : char type,
2003 : : const char *contents) {
2004 : :
2005 : : struct bus_container *c;
2006 : 704 : uint32_t *array_size = NULL;
2007 : 704 : _cleanup_free_ char *signature = NULL;
2008 : 704 : size_t before, begin = 0;
2009 : 704 : bool need_offsets = false;
2010 : : int r;
2011 : :
2012 [ - + - + ]: 704 : assert_return(m, -EINVAL);
2013 [ - + - + ]: 704 : assert_return(!m->sealed, -EPERM);
2014 [ - + - + ]: 704 : assert_return(contents, -EINVAL);
2015 [ - + - + ]: 704 : assert_return(!m->poisoned, -ESTALE);
2016 : :
2017 : : /* Make sure we have space for one more container */
2018 [ - + ]: 704 : if (!GREEDY_REALLOC(m->containers, m->containers_allocated, m->n_containers + 1)) {
2019 : 0 : m->poisoned = true;
2020 : 0 : return -ENOMEM;
2021 : : }
2022 : :
2023 : 704 : c = message_get_last_container(m);
2024 : :
2025 : 704 : signature = strdup(contents);
2026 [ - + ]: 704 : if (!signature) {
2027 : 0 : m->poisoned = true;
2028 : 0 : return -ENOMEM;
2029 : : }
2030 : :
2031 : : /* Save old index in the parent container, in case we have to
2032 : : * abort this container */
2033 : 704 : c->saved_index = c->index;
2034 : 704 : before = m->body_size;
2035 : :
2036 [ + + ]: 704 : if (type == SD_BUS_TYPE_ARRAY)
2037 : 236 : r = bus_message_open_array(m, c, contents, &array_size, &begin, &need_offsets);
2038 [ + + ]: 468 : else if (type == SD_BUS_TYPE_VARIANT)
2039 : 164 : r = bus_message_open_variant(m, c, contents);
2040 [ + + ]: 304 : else if (type == SD_BUS_TYPE_STRUCT)
2041 : 80 : r = bus_message_open_struct(m, c, contents, &begin, &need_offsets);
2042 [ + - ]: 224 : else if (type == SD_BUS_TYPE_DICT_ENTRY)
2043 : 224 : r = bus_message_open_dict_entry(m, c, contents, &begin, &need_offsets);
2044 : : else
2045 : 0 : r = -EINVAL;
2046 [ - + ]: 704 : if (r < 0)
2047 : 0 : return r;
2048 : :
2049 : : /* OK, let's fill it in */
2050 : 1408 : m->containers[m->n_containers++] = (struct bus_container) {
2051 : : .enclosing = type,
2052 : 704 : .signature = TAKE_PTR(signature),
2053 : : .array_size = array_size,
2054 : : .before = before,
2055 : : .begin = begin,
2056 : : .need_offsets = need_offsets,
2057 : : };
2058 : :
2059 : 704 : return 0;
2060 : : }
2061 : :
2062 : 220 : static int bus_message_close_array(sd_bus_message *m, struct bus_container *c) {
2063 : :
2064 [ - + ]: 220 : assert(m);
2065 [ - + ]: 220 : assert(c);
2066 : :
2067 [ + + ]: 220 : if (!BUS_MESSAGE_IS_GVARIANT(m))
2068 : 208 : return 0;
2069 : :
2070 [ + - ]: 12 : if (c->need_offsets) {
2071 : : size_t payload, sz, i;
2072 : : uint8_t *a;
2073 : :
2074 : : /* Variable-width arrays */
2075 : :
2076 [ + + ]: 12 : payload = c->n_offsets > 0 ? c->offsets[c->n_offsets-1] - c->begin : 0;
2077 : 12 : sz = bus_gvariant_determine_word_size(payload, c->n_offsets);
2078 : :
2079 : 12 : a = message_extend_body(m, 1, sz * c->n_offsets, true, false);
2080 [ - + ]: 12 : if (!a)
2081 : 0 : return -ENOMEM;
2082 : :
2083 [ + + ]: 32 : for (i = 0; i < c->n_offsets; i++)
2084 : 20 : bus_gvariant_write_word_le(a + sz*i, sz, c->offsets[i] - c->begin);
2085 : : } else {
2086 : : void *a;
2087 : :
2088 : : /* Fixed-width or empty arrays */
2089 : :
2090 : 0 : a = message_extend_body(m, 1, 0, true, false); /* let's add offset to parent */
2091 [ # # ]: 0 : if (!a)
2092 : 0 : return -ENOMEM;
2093 : : }
2094 : :
2095 : 12 : return 0;
2096 : : }
2097 : :
2098 : 164 : static int bus_message_close_variant(sd_bus_message *m, struct bus_container *c) {
2099 : : uint8_t *a;
2100 : : size_t l;
2101 : :
2102 [ - + ]: 164 : assert(m);
2103 [ - + ]: 164 : assert(c);
2104 [ - + ]: 164 : assert(c->signature);
2105 : :
2106 [ + + ]: 164 : if (!BUS_MESSAGE_IS_GVARIANT(m))
2107 : 152 : return 0;
2108 : :
2109 : 12 : l = strlen(c->signature);
2110 : :
2111 : 12 : a = message_extend_body(m, 1, 1 + l, true, false);
2112 [ - + ]: 12 : if (!a)
2113 : 0 : return -ENOMEM;
2114 : :
2115 : 12 : a[0] = 0;
2116 : 12 : memcpy(a+1, c->signature, l);
2117 : :
2118 : 12 : return 0;
2119 : : }
2120 : :
2121 : 892 : static int bus_message_close_struct(sd_bus_message *m, struct bus_container *c, bool add_offset) {
2122 : 892 : bool fixed_size = true;
2123 : 892 : size_t n_variable = 0;
2124 : 892 : unsigned i = 0;
2125 : : const char *p;
2126 : : uint8_t *a;
2127 : : int r;
2128 : :
2129 [ - + ]: 892 : assert(m);
2130 [ - + ]: 892 : assert(c);
2131 : :
2132 [ + + ]: 892 : if (!BUS_MESSAGE_IS_GVARIANT(m))
2133 : 852 : return 0;
2134 : :
2135 : 40 : p = strempty(c->signature);
2136 [ + + ]: 120 : while (*p != 0) {
2137 : : size_t n;
2138 : :
2139 : 80 : r = signature_element_length(p, &n);
2140 [ - + ]: 80 : if (r < 0)
2141 : 0 : return r;
2142 : 80 : else {
2143 : 80 : char t[n+1];
2144 : :
2145 : 80 : memcpy(t, p, n);
2146 : 80 : t[n] = 0;
2147 : :
2148 : 80 : r = bus_gvariant_is_fixed_size(t);
2149 [ - + ]: 80 : if (r < 0)
2150 : 0 : return r;
2151 : : }
2152 : :
2153 [ + + - + ]: 80 : assert(!c->need_offsets || i <= c->n_offsets);
2154 : :
2155 : : /* We need to add an offset for each item that has a
2156 : : * variable size and that is not the last one in the
2157 : : * list */
2158 [ + + ]: 80 : if (r == 0)
2159 : 48 : fixed_size = false;
2160 [ + + + + ]: 80 : if (r == 0 && p[n] != 0)
2161 : 24 : n_variable++;
2162 : :
2163 : 80 : i++;
2164 : 80 : p += n;
2165 : : }
2166 : :
2167 [ + + - + ]: 40 : assert(!c->need_offsets || i == c->n_offsets);
2168 [ + + - + ]: 40 : assert(c->need_offsets || n_variable == 0);
2169 : :
2170 [ - + ]: 40 : if (isempty(c->signature)) {
2171 : : /* The unary type is encoded as fixed 1 byte padding */
2172 : 0 : a = message_extend_body(m, 1, 1, add_offset, false);
2173 [ # # ]: 0 : if (!a)
2174 : 0 : return -ENOMEM;
2175 : :
2176 : 0 : *a = 0;
2177 [ + + ]: 40 : } else if (n_variable <= 0) {
2178 : 16 : int alignment = 1;
2179 : :
2180 : : /* Structures with fixed-size members only have to be
2181 : : * fixed-size themselves. But gvariant requires all fixed-size
2182 : : * elements to be sized a multiple of their alignment. Hence,
2183 : : * we must *always* add final padding after the last member so
2184 : : * the overall size of the structure is properly aligned. */
2185 [ + + ]: 16 : if (fixed_size)
2186 : 4 : alignment = bus_gvariant_get_alignment(strempty(c->signature));
2187 : :
2188 [ - + ]: 16 : assert(alignment > 0);
2189 : :
2190 : 16 : a = message_extend_body(m, alignment, 0, add_offset, false);
2191 [ - + ]: 16 : if (!a)
2192 : 0 : return -ENOMEM;
2193 : : } else {
2194 : : size_t sz;
2195 : : unsigned j;
2196 : :
2197 [ - + ]: 24 : assert(c->offsets[c->n_offsets-1] == m->body_size);
2198 : :
2199 : 24 : sz = bus_gvariant_determine_word_size(m->body_size - c->begin, n_variable);
2200 : :
2201 : 24 : a = message_extend_body(m, 1, sz * n_variable, add_offset, false);
2202 [ - + ]: 24 : if (!a)
2203 : 0 : return -ENOMEM;
2204 : :
2205 : 24 : p = strempty(c->signature);
2206 [ + + ]: 84 : for (i = 0, j = 0; i < c->n_offsets; i++) {
2207 : : unsigned k;
2208 : : size_t n;
2209 : :
2210 : 60 : r = signature_element_length(p, &n);
2211 [ - + ]: 60 : if (r < 0)
2212 : 0 : return r;
2213 : 60 : else {
2214 : 60 : char t[n+1];
2215 : :
2216 : 60 : memcpy(t, p, n);
2217 : 60 : t[n] = 0;
2218 : :
2219 : 60 : p += n;
2220 : :
2221 : 60 : r = bus_gvariant_is_fixed_size(t);
2222 [ - + ]: 60 : if (r < 0)
2223 : 0 : return r;
2224 [ + + + + ]: 60 : if (r > 0 || p[0] == 0)
2225 : 36 : continue;
2226 : : }
2227 : :
2228 : 24 : k = n_variable - 1 - j;
2229 : :
2230 : 24 : bus_gvariant_write_word_le(a + k * sz, sz, c->offsets[i] - c->begin);
2231 : :
2232 : 24 : j++;
2233 : : }
2234 : : }
2235 : :
2236 : 40 : return 0;
2237 : : }
2238 : :
2239 : 688 : _public_ int sd_bus_message_close_container(sd_bus_message *m) {
2240 : : struct bus_container *c;
2241 : : int r;
2242 : :
2243 [ - + - + ]: 688 : assert_return(m, -EINVAL);
2244 [ - + - + ]: 688 : assert_return(!m->sealed, -EPERM);
2245 [ - + - + ]: 688 : assert_return(m->n_containers > 0, -EINVAL);
2246 [ - + - + ]: 688 : assert_return(!m->poisoned, -ESTALE);
2247 : :
2248 : 688 : c = message_get_last_container(m);
2249 : :
2250 [ + + ]: 688 : if (c->enclosing != SD_BUS_TYPE_ARRAY)
2251 [ + - - + ]: 468 : if (c->signature && c->signature[c->index] != 0)
2252 : 0 : return -EINVAL;
2253 : :
2254 : 688 : m->n_containers--;
2255 : :
2256 [ + + ]: 688 : if (c->enclosing == SD_BUS_TYPE_ARRAY)
2257 : 220 : r = bus_message_close_array(m, c);
2258 [ + + ]: 468 : else if (c->enclosing == SD_BUS_TYPE_VARIANT)
2259 : 164 : r = bus_message_close_variant(m, c);
2260 [ + - + - ]: 304 : else if (IN_SET(c->enclosing, SD_BUS_TYPE_STRUCT, SD_BUS_TYPE_DICT_ENTRY))
2261 : 304 : r = bus_message_close_struct(m, c, true);
2262 : : else
2263 : 0 : assert_not_reached("Unknown container type");
2264 : :
2265 : 688 : free(c->signature);
2266 : 688 : free(c->offsets);
2267 : :
2268 : 688 : return r;
2269 : : }
2270 : :
2271 : : typedef struct {
2272 : : const char *types;
2273 : : unsigned n_struct;
2274 : : unsigned n_array;
2275 : : } TypeStack;
2276 : :
2277 : 328 : static int type_stack_push(TypeStack *stack, unsigned max, unsigned *i, const char *types, unsigned n_struct, unsigned n_array) {
2278 [ - + ]: 328 : assert(stack);
2279 [ - + ]: 328 : assert(max > 0);
2280 : :
2281 [ - + ]: 328 : if (*i >= max)
2282 : 0 : return -EINVAL;
2283 : :
2284 : 328 : stack[*i].types = types;
2285 : 328 : stack[*i].n_struct = n_struct;
2286 : 328 : stack[*i].n_array = n_array;
2287 : 328 : (*i)++;
2288 : :
2289 : 328 : return 0;
2290 : : }
2291 : :
2292 : 1184 : static int type_stack_pop(TypeStack *stack, unsigned max, unsigned *i, const char **types, unsigned *n_struct, unsigned *n_array) {
2293 [ - + ]: 1184 : assert(stack);
2294 [ - + ]: 1184 : assert(max > 0);
2295 [ - + ]: 1184 : assert(types);
2296 [ - + ]: 1184 : assert(n_struct);
2297 [ - + ]: 1184 : assert(n_array);
2298 : :
2299 [ + + ]: 1184 : if (*i <= 0)
2300 : 856 : return 0;
2301 : :
2302 : 328 : (*i)--;
2303 : 328 : *types = stack[*i].types;
2304 : 328 : *n_struct = stack[*i].n_struct;
2305 : 328 : *n_array = stack[*i].n_array;
2306 : :
2307 : 328 : return 1;
2308 : : }
2309 : :
2310 : 588 : _public_ int sd_bus_message_appendv(
2311 : : sd_bus_message *m,
2312 : : const char *types,
2313 : : va_list ap) {
2314 : :
2315 : : unsigned n_array, n_struct;
2316 : : TypeStack stack[BUS_CONTAINER_DEPTH];
2317 : 588 : unsigned stack_ptr = 0;
2318 : : int r;
2319 : :
2320 [ - + - + ]: 588 : assert_return(m, -EINVAL);
2321 [ - + - + ]: 588 : assert_return(types, -EINVAL);
2322 [ - + - + ]: 588 : assert_return(!m->sealed, -EPERM);
2323 [ - + - + ]: 588 : assert_return(!m->poisoned, -ESTALE);
2324 : :
2325 : 588 : n_array = (unsigned) -1;
2326 : 588 : n_struct = strlen(types);
2327 : :
2328 : 1292 : for (;;) {
2329 : : const char *t;
2330 : :
2331 [ + + + + : 1880 : if (n_array == 0 || (n_array == (unsigned) -1 && n_struct == 0)) {
+ + ]
2332 : 836 : r = type_stack_pop(stack, ELEMENTSOF(stack), &stack_ptr, &types, &n_struct, &n_array);
2333 [ - + ]: 836 : if (r < 0)
2334 : 0 : return r;
2335 [ + + ]: 836 : if (r == 0)
2336 : 584 : break;
2337 : :
2338 : 252 : r = sd_bus_message_close_container(m);
2339 [ - + ]: 252 : if (r < 0)
2340 : 0 : return r;
2341 : :
2342 : 252 : continue;
2343 : : }
2344 : :
2345 : 1044 : t = types;
2346 [ + + ]: 1044 : if (n_array != (unsigned) -1)
2347 : 88 : n_array--;
2348 : : else {
2349 : 956 : types++;
2350 : 956 : n_struct--;
2351 : : }
2352 : :
2353 [ + + - + : 1044 : switch (*t) {
+ + + + +
- ]
2354 : :
2355 : 28 : case SD_BUS_TYPE_BYTE: {
2356 : : uint8_t x;
2357 : :
2358 : 28 : x = (uint8_t) va_arg(ap, int);
2359 : 28 : r = sd_bus_message_append_basic(m, *t, &x);
2360 : 28 : break;
2361 : : }
2362 : :
2363 : 52 : case SD_BUS_TYPE_BOOLEAN:
2364 : : case SD_BUS_TYPE_INT32:
2365 : : case SD_BUS_TYPE_UINT32:
2366 : : case SD_BUS_TYPE_UNIX_FD: {
2367 : : uint32_t x;
2368 : :
2369 : : /* We assume a boolean is the same as int32_t */
2370 : : assert_cc(sizeof(int32_t) == sizeof(int));
2371 : :
2372 : 52 : x = va_arg(ap, uint32_t);
2373 : 52 : r = sd_bus_message_append_basic(m, *t, &x);
2374 : 52 : break;
2375 : : }
2376 : :
2377 : 0 : case SD_BUS_TYPE_INT16:
2378 : : case SD_BUS_TYPE_UINT16: {
2379 : : uint16_t x;
2380 : :
2381 : 0 : x = (uint16_t) va_arg(ap, int);
2382 : 0 : r = sd_bus_message_append_basic(m, *t, &x);
2383 : 0 : break;
2384 : : }
2385 : :
2386 : 16 : case SD_BUS_TYPE_INT64:
2387 : : case SD_BUS_TYPE_UINT64: {
2388 : : uint64_t x;
2389 : :
2390 : 16 : x = va_arg(ap, uint64_t);
2391 : 16 : r = sd_bus_message_append_basic(m, *t, &x);
2392 : 16 : break;
2393 : : }
2394 : :
2395 : 4 : case SD_BUS_TYPE_DOUBLE: {
2396 : : double x;
2397 : :
2398 : 4 : x = va_arg(ap, double);
2399 : 4 : r = sd_bus_message_append_basic(m, *t, &x);
2400 : 4 : break;
2401 : : }
2402 : :
2403 : 688 : case SD_BUS_TYPE_STRING:
2404 : : case SD_BUS_TYPE_OBJECT_PATH:
2405 : : case SD_BUS_TYPE_SIGNATURE: {
2406 : : const char *x;
2407 : :
2408 : 688 : x = va_arg(ap, const char*);
2409 : 688 : r = sd_bus_message_append_basic(m, *t, x);
2410 : 688 : break;
2411 : : }
2412 : :
2413 : 104 : case SD_BUS_TYPE_ARRAY: {
2414 : : size_t k;
2415 : :
2416 : 104 : r = signature_element_length(t + 1, &k);
2417 [ - + ]: 104 : if (r < 0)
2418 : 0 : return r;
2419 : :
2420 : 104 : {
2421 : 104 : char s[k + 1];
2422 : 104 : memcpy(s, t + 1, k);
2423 : 104 : s[k] = 0;
2424 : :
2425 : 104 : r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, s);
2426 [ - + ]: 104 : if (r < 0)
2427 : 0 : return r;
2428 : : }
2429 : :
2430 [ + - ]: 104 : if (n_array == (unsigned) -1) {
2431 : 104 : types += k;
2432 : 104 : n_struct -= k;
2433 : : }
2434 : :
2435 : 104 : r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
2436 [ - + ]: 104 : if (r < 0)
2437 : 0 : return r;
2438 : :
2439 : 104 : types = t + 1;
2440 : 104 : n_struct = k;
2441 : 104 : n_array = va_arg(ap, unsigned);
2442 : :
2443 : 104 : break;
2444 : : }
2445 : :
2446 : 20 : case SD_BUS_TYPE_VARIANT: {
2447 : : const char *s;
2448 : :
2449 : 20 : s = va_arg(ap, const char*);
2450 [ - + ]: 20 : if (!s)
2451 : 0 : return -EINVAL;
2452 : :
2453 : 20 : r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT, s);
2454 [ - + ]: 20 : if (r < 0)
2455 : 0 : return r;
2456 : :
2457 : 20 : r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
2458 [ - + ]: 20 : if (r < 0)
2459 : 0 : return r;
2460 : :
2461 : 20 : types = s;
2462 : 20 : n_struct = strlen(s);
2463 : 20 : n_array = (unsigned) -1;
2464 : :
2465 : 20 : break;
2466 : : }
2467 : :
2468 : 132 : case SD_BUS_TYPE_STRUCT_BEGIN:
2469 : : case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
2470 : : size_t k;
2471 : :
2472 : 132 : r = signature_element_length(t, &k);
2473 [ + + ]: 132 : if (r < 0)
2474 : 4 : return r;
2475 : :
2476 : 128 : {
2477 : 128 : char s[k - 1];
2478 : :
2479 : 128 : memcpy(s, t + 1, k - 2);
2480 : 128 : s[k - 2] = 0;
2481 : :
2482 [ + + ]: 128 : r = sd_bus_message_open_container(m, *t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
2483 [ - + ]: 128 : if (r < 0)
2484 : 0 : return r;
2485 : : }
2486 : :
2487 [ + + ]: 128 : if (n_array == (unsigned) -1) {
2488 : 84 : types += k - 1;
2489 : 84 : n_struct -= k - 1;
2490 : : }
2491 : :
2492 : 128 : r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
2493 [ - + ]: 128 : if (r < 0)
2494 : 0 : return r;
2495 : :
2496 : 128 : types = t + 1;
2497 : 128 : n_struct = k - 2;
2498 : 128 : n_array = (unsigned) -1;
2499 : :
2500 : 128 : break;
2501 : : }
2502 : :
2503 : 0 : default:
2504 : 0 : r = -EINVAL;
2505 : : }
2506 : :
2507 [ - + ]: 1040 : if (r < 0)
2508 : 0 : return r;
2509 : : }
2510 : :
2511 : 584 : return 1;
2512 : : }
2513 : :
2514 : 440 : _public_ int sd_bus_message_append(sd_bus_message *m, const char *types, ...) {
2515 : : va_list ap;
2516 : : int r;
2517 : :
2518 : 440 : va_start(ap, types);
2519 : 440 : r = sd_bus_message_appendv(m, types, ap);
2520 : 440 : va_end(ap);
2521 : :
2522 : 440 : return r;
2523 : : }
2524 : :
2525 : 8 : _public_ int sd_bus_message_append_array_space(
2526 : : sd_bus_message *m,
2527 : : char type,
2528 : : size_t size,
2529 : : void **ptr) {
2530 : :
2531 : : ssize_t align, sz;
2532 : : void *a;
2533 : : int r;
2534 : :
2535 [ - + - + ]: 8 : assert_return(m, -EINVAL);
2536 [ - + - + ]: 8 : assert_return(!m->sealed, -EPERM);
2537 [ + - - + : 8 : assert_return(bus_type_is_trivial(type) && type != SD_BUS_TYPE_BOOLEAN, -EINVAL);
- + ]
2538 [ - + # # : 8 : assert_return(ptr || size == 0, -EINVAL);
- + ]
2539 [ - + - + ]: 8 : assert_return(!m->poisoned, -ESTALE);
2540 : :
2541 : : /* alignment and size of the trivial types (except bool) is
2542 : : * identical for gvariant and dbus1 marshalling */
2543 : 8 : align = bus_type_get_alignment(type);
2544 : 8 : sz = bus_type_get_size(type);
2545 : :
2546 [ - + ]: 8 : assert_se(align > 0);
2547 [ - + ]: 8 : assert_se(sz > 0);
2548 : :
2549 [ - + ]: 8 : if (size % sz != 0)
2550 : 0 : return -EINVAL;
2551 : :
2552 : 8 : r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type));
2553 [ - + ]: 8 : if (r < 0)
2554 : 0 : return r;
2555 : :
2556 : 8 : a = message_extend_body(m, align, size, false, false);
2557 [ - + ]: 8 : if (!a)
2558 : 0 : return -ENOMEM;
2559 : :
2560 : 8 : r = sd_bus_message_close_container(m);
2561 [ - + ]: 8 : if (r < 0)
2562 : 0 : return r;
2563 : :
2564 : 8 : *ptr = a;
2565 : 8 : return 0;
2566 : : }
2567 : :
2568 : 8 : _public_ int sd_bus_message_append_array(
2569 : : sd_bus_message *m,
2570 : : char type,
2571 : : const void *ptr,
2572 : : size_t size) {
2573 : : int r;
2574 : : void *p;
2575 : :
2576 [ - + - + ]: 8 : assert_return(m, -EINVAL);
2577 [ - + - + ]: 8 : assert_return(!m->sealed, -EPERM);
2578 [ - + - + ]: 8 : assert_return(bus_type_is_trivial(type), -EINVAL);
2579 [ + + - + : 8 : assert_return(ptr || size == 0, -EINVAL);
- + ]
2580 [ - + - + ]: 8 : assert_return(!m->poisoned, -ESTALE);
2581 : :
2582 : 8 : r = sd_bus_message_append_array_space(m, type, size, &p);
2583 [ - + ]: 8 : if (r < 0)
2584 : 0 : return r;
2585 : :
2586 : 8 : memcpy_safe(p, ptr, size);
2587 : :
2588 : 8 : return 0;
2589 : : }
2590 : :
2591 : 0 : _public_ int sd_bus_message_append_array_iovec(
2592 : : sd_bus_message *m,
2593 : : char type,
2594 : : const struct iovec *iov,
2595 : : unsigned n /* should be size_t, but is API now… 😞 */) {
2596 : :
2597 : : size_t size;
2598 : : unsigned i;
2599 : : void *p;
2600 : : int r;
2601 : :
2602 [ # # # # ]: 0 : assert_return(m, -EINVAL);
2603 [ # # # # ]: 0 : assert_return(!m->sealed, -EPERM);
2604 [ # # # # ]: 0 : assert_return(bus_type_is_trivial(type), -EINVAL);
2605 [ # # # # : 0 : assert_return(iov || n == 0, -EINVAL);
# # ]
2606 [ # # # # ]: 0 : assert_return(!m->poisoned, -ESTALE);
2607 : :
2608 : 0 : size = IOVEC_TOTAL_SIZE(iov, n);
2609 : :
2610 : 0 : r = sd_bus_message_append_array_space(m, type, size, &p);
2611 [ # # ]: 0 : if (r < 0)
2612 : 0 : return r;
2613 : :
2614 [ # # ]: 0 : for (i = 0; i < n; i++) {
2615 : :
2616 [ # # ]: 0 : if (iov[i].iov_base)
2617 : 0 : memcpy(p, iov[i].iov_base, iov[i].iov_len);
2618 : : else
2619 [ # # ]: 0 : memzero(p, iov[i].iov_len);
2620 : :
2621 : 0 : p = (uint8_t*) p + iov[i].iov_len;
2622 : : }
2623 : :
2624 : 0 : return 0;
2625 : : }
2626 : :
2627 : 0 : _public_ int sd_bus_message_append_array_memfd(
2628 : : sd_bus_message *m,
2629 : : char type,
2630 : : int memfd,
2631 : : uint64_t offset,
2632 : : uint64_t size) {
2633 : :
2634 : 0 : _cleanup_close_ int copy_fd = -1;
2635 : : struct bus_body_part *part;
2636 : : ssize_t align, sz;
2637 : : uint64_t real_size;
2638 : : void *a;
2639 : : int r;
2640 : :
2641 [ # # # # ]: 0 : assert_return(m, -EINVAL);
2642 [ # # # # ]: 0 : assert_return(memfd >= 0, -EBADF);
2643 [ # # # # ]: 0 : assert_return(bus_type_is_trivial(type), -EINVAL);
2644 [ # # # # ]: 0 : assert_return(size > 0, -EINVAL);
2645 [ # # # # ]: 0 : assert_return(!m->sealed, -EPERM);
2646 [ # # # # ]: 0 : assert_return(!m->poisoned, -ESTALE);
2647 : :
2648 : 0 : r = memfd_set_sealed(memfd);
2649 [ # # ]: 0 : if (r < 0)
2650 : 0 : return r;
2651 : :
2652 : 0 : copy_fd = fcntl(memfd, F_DUPFD_CLOEXEC, 3);
2653 [ # # ]: 0 : if (copy_fd < 0)
2654 : 0 : return copy_fd;
2655 : :
2656 : 0 : r = memfd_get_size(memfd, &real_size);
2657 [ # # ]: 0 : if (r < 0)
2658 : 0 : return r;
2659 : :
2660 [ # # # # ]: 0 : if (offset == 0 && size == (uint64_t) -1)
2661 : 0 : size = real_size;
2662 [ # # ]: 0 : else if (offset + size > real_size)
2663 : 0 : return -EMSGSIZE;
2664 : :
2665 : 0 : align = bus_type_get_alignment(type);
2666 : 0 : sz = bus_type_get_size(type);
2667 : :
2668 [ # # ]: 0 : assert_se(align > 0);
2669 [ # # ]: 0 : assert_se(sz > 0);
2670 : :
2671 [ # # ]: 0 : if (offset % align != 0)
2672 : 0 : return -EINVAL;
2673 : :
2674 [ # # ]: 0 : if (size % sz != 0)
2675 : 0 : return -EINVAL;
2676 : :
2677 [ # # ]: 0 : if (size > (uint64_t) (uint32_t) -1)
2678 : 0 : return -EINVAL;
2679 : :
2680 : 0 : r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type));
2681 [ # # ]: 0 : if (r < 0)
2682 : 0 : return r;
2683 : :
2684 : 0 : a = message_extend_body(m, align, 0, false, false);
2685 [ # # ]: 0 : if (!a)
2686 : 0 : return -ENOMEM;
2687 : :
2688 : 0 : part = message_append_part(m);
2689 [ # # ]: 0 : if (!part)
2690 : 0 : return -ENOMEM;
2691 : :
2692 : 0 : part->memfd = copy_fd;
2693 : 0 : part->memfd_offset = offset;
2694 : 0 : part->sealed = true;
2695 : 0 : part->size = size;
2696 : 0 : copy_fd = -1;
2697 : :
2698 : 0 : m->body_size += size;
2699 : 0 : message_extend_containers(m, size);
2700 : :
2701 : 0 : return sd_bus_message_close_container(m);
2702 : : }
2703 : :
2704 : 0 : _public_ int sd_bus_message_append_string_memfd(
2705 : : sd_bus_message *m,
2706 : : int memfd,
2707 : : uint64_t offset,
2708 : : uint64_t size) {
2709 : :
2710 : 0 : _cleanup_close_ int copy_fd = -1;
2711 : : struct bus_body_part *part;
2712 : : struct bus_container *c;
2713 : : uint64_t real_size;
2714 : : void *a;
2715 : : int r;
2716 : :
2717 [ # # # # ]: 0 : assert_return(m, -EINVAL);
2718 [ # # # # ]: 0 : assert_return(memfd >= 0, -EBADF);
2719 [ # # # # ]: 0 : assert_return(size > 0, -EINVAL);
2720 [ # # # # ]: 0 : assert_return(!m->sealed, -EPERM);
2721 [ # # # # ]: 0 : assert_return(!m->poisoned, -ESTALE);
2722 : :
2723 : 0 : r = memfd_set_sealed(memfd);
2724 [ # # ]: 0 : if (r < 0)
2725 : 0 : return r;
2726 : :
2727 : 0 : copy_fd = fcntl(memfd, FD_CLOEXEC, 3);
2728 [ # # ]: 0 : if (copy_fd < 0)
2729 : 0 : return copy_fd;
2730 : :
2731 : 0 : r = memfd_get_size(memfd, &real_size);
2732 [ # # ]: 0 : if (r < 0)
2733 : 0 : return r;
2734 : :
2735 [ # # # # ]: 0 : if (offset == 0 && size == (uint64_t) -1)
2736 : 0 : size = real_size;
2737 [ # # ]: 0 : else if (offset + size > real_size)
2738 : 0 : return -EMSGSIZE;
2739 : :
2740 : : /* We require this to be NUL terminated */
2741 [ # # ]: 0 : if (size == 0)
2742 : 0 : return -EINVAL;
2743 : :
2744 [ # # ]: 0 : if (size > (uint64_t) (uint32_t) -1)
2745 : 0 : return -EINVAL;
2746 : :
2747 : 0 : c = message_get_last_container(m);
2748 [ # # # # ]: 0 : if (c->signature && c->signature[c->index]) {
2749 : : /* Container signature is already set */
2750 : :
2751 [ # # ]: 0 : if (c->signature[c->index] != SD_BUS_TYPE_STRING)
2752 : 0 : return -ENXIO;
2753 : : } else {
2754 : : char *e;
2755 : :
2756 : : /* Maybe we can append to the signature? But only if this is the top-level container */
2757 [ # # ]: 0 : if (c->enclosing != 0)
2758 : 0 : return -ENXIO;
2759 : :
2760 : 0 : e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRING), NULL);
2761 [ # # ]: 0 : if (!e) {
2762 : 0 : m->poisoned = true;
2763 : 0 : return -ENOMEM;
2764 : : }
2765 : : }
2766 : :
2767 [ # # ]: 0 : if (!BUS_MESSAGE_IS_GVARIANT(m)) {
2768 : 0 : a = message_extend_body(m, 4, 4, false, false);
2769 [ # # ]: 0 : if (!a)
2770 : 0 : return -ENOMEM;
2771 : :
2772 : 0 : *(uint32_t*) a = size - 1;
2773 : : }
2774 : :
2775 : 0 : part = message_append_part(m);
2776 [ # # ]: 0 : if (!part)
2777 : 0 : return -ENOMEM;
2778 : :
2779 : 0 : part->memfd = copy_fd;
2780 : 0 : part->memfd_offset = offset;
2781 : 0 : part->sealed = true;
2782 : 0 : part->size = size;
2783 : 0 : copy_fd = -1;
2784 : :
2785 : 0 : m->body_size += size;
2786 : 0 : message_extend_containers(m, size);
2787 : :
2788 [ # # ]: 0 : if (BUS_MESSAGE_IS_GVARIANT(m)) {
2789 : 0 : r = message_add_offset(m, m->body_size);
2790 [ # # ]: 0 : if (r < 0) {
2791 : 0 : m->poisoned = true;
2792 : 0 : return -ENOMEM;
2793 : : }
2794 : : }
2795 : :
2796 [ # # ]: 0 : if (c->enclosing != SD_BUS_TYPE_ARRAY)
2797 : 0 : c->index++;
2798 : :
2799 : 0 : return 0;
2800 : : }
2801 : :
2802 : 4 : _public_ int sd_bus_message_append_strv(sd_bus_message *m, char **l) {
2803 : : char **i;
2804 : : int r;
2805 : :
2806 [ - + - + ]: 4 : assert_return(m, -EINVAL);
2807 [ - + - + ]: 4 : assert_return(!m->sealed, -EPERM);
2808 [ - + - + ]: 4 : assert_return(!m->poisoned, -ESTALE);
2809 : :
2810 : 4 : r = sd_bus_message_open_container(m, 'a', "s");
2811 [ - + ]: 4 : if (r < 0)
2812 : 0 : return r;
2813 : :
2814 [ + - + + ]: 8 : STRV_FOREACH(i, l) {
2815 : 4 : r = sd_bus_message_append_basic(m, 's', *i);
2816 [ - + ]: 4 : if (r < 0)
2817 : 0 : return r;
2818 : : }
2819 : :
2820 : 4 : return sd_bus_message_close_container(m);
2821 : : }
2822 : :
2823 : 588 : static int bus_message_close_header(sd_bus_message *m) {
2824 : :
2825 [ - + ]: 588 : assert(m);
2826 : :
2827 : : /* The actual user data is finished now, we just complete the
2828 : : variant and struct now (at least on gvariant). Remember
2829 : : this position, so that during parsing we know where to
2830 : : put the outer container end. */
2831 : 588 : m->user_body_size = m->body_size;
2832 : :
2833 [ + + ]: 588 : if (BUS_MESSAGE_IS_GVARIANT(m)) {
2834 : : const char *signature;
2835 : : size_t sz, l;
2836 : : void *d;
2837 : :
2838 : : /* Add offset table to end of fields array */
2839 [ + - ]: 8 : if (m->n_header_offsets >= 1) {
2840 : : uint8_t *a;
2841 : : unsigned i;
2842 : :
2843 [ - + ]: 8 : assert(m->fields_size == m->header_offsets[m->n_header_offsets-1]);
2844 : :
2845 : 8 : sz = bus_gvariant_determine_word_size(m->fields_size, m->n_header_offsets);
2846 : 8 : a = message_extend_fields(m, 1, sz * m->n_header_offsets, false);
2847 [ - + ]: 8 : if (!a)
2848 : 0 : return -ENOMEM;
2849 : :
2850 [ + + ]: 40 : for (i = 0; i < m->n_header_offsets; i++)
2851 : 32 : bus_gvariant_write_word_le(a + sz*i, sz, m->header_offsets[i]);
2852 : : }
2853 : :
2854 : : /* Add gvariant NUL byte plus signature to the end of
2855 : : * the body, followed by the final offset pointing to
2856 : : * the end of the fields array */
2857 : :
2858 : 8 : signature = strempty(m->root_container.signature);
2859 : 8 : l = strlen(signature);
2860 : :
2861 : 8 : sz = bus_gvariant_determine_word_size(sizeof(struct bus_header) + ALIGN8(m->fields_size) + m->body_size + 1 + l + 2, 1);
2862 : 8 : d = message_extend_body(m, 1, 1 + l + 2 + sz, false, true);
2863 [ - + ]: 8 : if (!d)
2864 : 0 : return -ENOMEM;
2865 : :
2866 : 8 : *(uint8_t*) d = 0;
2867 : 8 : *((uint8_t*) d + 1) = SD_BUS_TYPE_STRUCT_BEGIN;
2868 : 8 : memcpy((uint8_t*) d + 2, signature, l);
2869 : 8 : *((uint8_t*) d + 1 + l + 1) = SD_BUS_TYPE_STRUCT_END;
2870 : :
2871 : 8 : bus_gvariant_write_word_le((uint8_t*) d + 1 + l + 2, sz, sizeof(struct bus_header) + m->fields_size);
2872 : :
2873 : 8 : m->footer = d;
2874 : 8 : m->footer_accessible = 1 + l + 2 + sz;
2875 : : } else {
2876 : 580 : m->header->dbus1.fields_size = m->fields_size;
2877 : 580 : m->header->dbus1.body_size = m->body_size;
2878 : : }
2879 : :
2880 : 588 : return 0;
2881 : : }
2882 : :
2883 : 592 : _public_ int sd_bus_message_seal(sd_bus_message *m, uint64_t cookie, uint64_t timeout_usec) {
2884 : : struct bus_body_part *part;
2885 : : size_t a;
2886 : : unsigned i;
2887 : : int r;
2888 : :
2889 [ - + - + ]: 592 : assert_return(m, -EINVAL);
2890 : :
2891 [ - + ]: 592 : if (m->sealed)
2892 : 0 : return -EPERM;
2893 : :
2894 [ - + ]: 592 : if (m->n_containers > 0)
2895 : 0 : return -EBADMSG;
2896 : :
2897 [ - + ]: 592 : if (m->poisoned)
2898 : 0 : return -ESTALE;
2899 : :
2900 [ - + ]: 592 : if (cookie > 0xffffffffULL &&
2901 [ # # ]: 0 : !BUS_MESSAGE_IS_GVARIANT(m))
2902 : 0 : return -EOPNOTSUPP;
2903 : :
2904 : : /* In vtables the return signature of method calls is listed,
2905 : : * let's check if they match if this is a response */
2906 [ + + ]: 592 : if (m->header->type == SD_BUS_MESSAGE_METHOD_RETURN &&
2907 [ + + ]: 144 : m->enforced_reply_signature &&
2908 [ + + ]: 52 : !streq(strempty(m->root_container.signature), m->enforced_reply_signature))
2909 : 4 : return -ENOMSG;
2910 : :
2911 : : /* If gvariant marshalling is used we need to close the body structure */
2912 : 588 : r = bus_message_close_struct(m, &m->root_container, false);
2913 [ - + ]: 588 : if (r < 0)
2914 : 0 : return r;
2915 : :
2916 : : /* If there's a non-trivial signature set, then add it in
2917 : : * here, but only on dbus1 */
2918 [ + + + + ]: 588 : if (!isempty(m->root_container.signature) && !BUS_MESSAGE_IS_GVARIANT(m)) {
2919 : 240 : r = message_append_field_signature(m, BUS_MESSAGE_HEADER_SIGNATURE, m->root_container.signature, NULL);
2920 [ - + ]: 240 : if (r < 0)
2921 : 0 : return r;
2922 : : }
2923 : :
2924 [ + + ]: 588 : if (m->n_fds > 0) {
2925 : 4 : r = message_append_field_uint32(m, BUS_MESSAGE_HEADER_UNIX_FDS, m->n_fds);
2926 [ - + ]: 4 : if (r < 0)
2927 : 0 : return r;
2928 : : }
2929 : :
2930 : 588 : r = bus_message_close_header(m);
2931 [ - + ]: 588 : if (r < 0)
2932 : 0 : return r;
2933 : :
2934 [ + + ]: 588 : if (BUS_MESSAGE_IS_GVARIANT(m))
2935 : 8 : m->header->dbus2.cookie = cookie;
2936 : : else
2937 : 580 : m->header->dbus1.serial = (uint32_t) cookie;
2938 : :
2939 [ + + ]: 588 : m->timeout = m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED ? 0 : timeout_usec;
2940 : :
2941 : : /* Add padding at the end of the fields part, since we know
2942 : : * the body needs to start at an 8 byte alignment. We made
2943 : : * sure we allocated enough space for this, so all we need to
2944 : : * do here is to zero it out. */
2945 : 588 : a = ALIGN8(m->fields_size) - m->fields_size;
2946 [ + + ]: 588 : if (a > 0)
2947 [ + - ]: 440 : memzero((uint8_t*) BUS_MESSAGE_FIELDS(m) + m->fields_size, a);
2948 : :
2949 : : /* If this is something we can send as memfd, then let's seal
2950 : : the memfd now. Note that we can send memfds as payload only
2951 : : for directed messages, and not for broadcasts. */
2952 [ + + - + ]: 588 : if (m->destination && m->bus->use_memfd) {
2953 [ # # ]: 0 : MESSAGE_FOREACH_PART(part, i, m)
2954 [ # # ]: 0 : if (part->memfd >= 0 &&
2955 [ # # ]: 0 : !part->sealed &&
2956 [ # # # # ]: 0 : (part->size > MEMFD_MIN_SIZE || m->bus->use_memfd < 0) &&
2957 [ # # ]: 0 : part != m->body_end) { /* The last part may never be sent as memfd */
2958 : : uint64_t sz;
2959 : :
2960 : : /* Try to seal it if that makes
2961 : : * sense. First, unmap our own map to
2962 : : * make sure we don't keep it busy. */
2963 : 0 : bus_body_part_unmap(part);
2964 : :
2965 : : /* Then, sync up real memfd size */
2966 : 0 : sz = part->size;
2967 : 0 : r = memfd_set_size(part->memfd, sz);
2968 [ # # ]: 0 : if (r < 0)
2969 : 0 : return r;
2970 : :
2971 : : /* Finally, try to seal */
2972 [ # # ]: 0 : if (memfd_set_sealed(part->memfd) >= 0)
2973 : 0 : part->sealed = true;
2974 : : }
2975 : : }
2976 : :
2977 : 588 : m->root_container.end = m->user_body_size;
2978 : 588 : m->root_container.index = 0;
2979 : 588 : m->root_container.offset_index = 0;
2980 [ + + ]: 588 : m->root_container.item_size = m->root_container.n_offsets > 0 ? m->root_container.offsets[0] : 0;
2981 : :
2982 : 588 : m->sealed = true;
2983 : :
2984 : 588 : return 0;
2985 : : }
2986 : :
2987 : 12160 : int bus_body_part_map(struct bus_body_part *part) {
2988 : : void *p;
2989 : : size_t psz, shift;
2990 : :
2991 [ - + ]: 12160 : assert_se(part);
2992 : :
2993 [ + - ]: 12160 : if (part->data)
2994 : 12160 : return 0;
2995 : :
2996 [ # # ]: 0 : if (part->size <= 0)
2997 : 0 : return 0;
2998 : :
2999 : : /* For smaller zero parts (as used for padding) we don't need to map anything... */
3000 [ # # # # : 0 : if (part->memfd < 0 && part->is_zero && part->size < 8) {
# # ]
3001 : : static const uint8_t zeroes[7] = { };
3002 : 0 : part->data = (void*) zeroes;
3003 : 0 : return 0;
3004 : : }
3005 : :
3006 : 0 : shift = part->memfd_offset - ((part->memfd_offset / page_size()) * page_size());
3007 : 0 : psz = PAGE_ALIGN(part->size + shift);
3008 : :
3009 [ # # ]: 0 : if (part->memfd >= 0)
3010 : 0 : p = mmap(NULL, psz, PROT_READ, MAP_PRIVATE, part->memfd, part->memfd_offset - shift);
3011 [ # # ]: 0 : else if (part->is_zero)
3012 : 0 : p = mmap(NULL, psz, PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
3013 : : else
3014 : 0 : return -EINVAL;
3015 : :
3016 [ # # ]: 0 : if (p == MAP_FAILED)
3017 : 0 : return -errno;
3018 : :
3019 : 0 : part->mapped = psz;
3020 : 0 : part->mmap_begin = p;
3021 : 0 : part->data = (uint8_t*) p + shift;
3022 : 0 : part->munmap_this = true;
3023 : :
3024 : 0 : return 0;
3025 : : }
3026 : :
3027 : 0 : void bus_body_part_unmap(struct bus_body_part *part) {
3028 : :
3029 [ # # ]: 0 : assert_se(part);
3030 : :
3031 [ # # ]: 0 : if (part->memfd < 0)
3032 : 0 : return;
3033 : :
3034 [ # # ]: 0 : if (!part->mmap_begin)
3035 : 0 : return;
3036 : :
3037 [ # # ]: 0 : if (!part->munmap_this)
3038 : 0 : return;
3039 : :
3040 [ # # ]: 0 : assert_se(munmap(part->mmap_begin, part->mapped) == 0);
3041 : :
3042 : 0 : part->mmap_begin = NULL;
3043 : 0 : part->data = NULL;
3044 : 0 : part->mapped = 0;
3045 : 0 : part->munmap_this = false;
3046 : :
3047 : 0 : return;
3048 : : }
3049 : :
3050 : 9364 : static int buffer_peek(const void *p, uint32_t sz, size_t *rindex, size_t align, size_t nbytes, void **r) {
3051 : : size_t k, start, end;
3052 : :
3053 [ - + ]: 9364 : assert(rindex);
3054 [ - + ]: 9364 : assert(align > 0);
3055 : :
3056 : 9364 : start = ALIGN_TO((size_t) *rindex, align);
3057 : 9364 : end = start + nbytes;
3058 : :
3059 [ - + ]: 9364 : if (end > sz)
3060 : 0 : return -EBADMSG;
3061 : :
3062 : : /* Verify that padding is 0 */
3063 [ + + ]: 12963 : for (k = *rindex; k < start; k++)
3064 [ - + ]: 3599 : if (((const uint8_t*) p)[k] != 0)
3065 : 0 : return -EBADMSG;
3066 : :
3067 [ + - ]: 9364 : if (r)
3068 : 9364 : *r = (uint8_t*) p + start;
3069 : :
3070 : 9364 : *rindex = end;
3071 : :
3072 : 9364 : return 1;
3073 : : }
3074 : :
3075 : 7212 : static bool message_end_of_signature(sd_bus_message *m) {
3076 : : struct bus_container *c;
3077 : :
3078 [ - + ]: 7212 : assert(m);
3079 : :
3080 : 7212 : c = message_get_last_container(m);
3081 [ + - + + ]: 7212 : return !c->signature || c->signature[c->index] == 0;
3082 : : }
3083 : :
3084 : 6492 : static bool message_end_of_array(sd_bus_message *m, size_t index) {
3085 : : struct bus_container *c;
3086 : :
3087 [ - + ]: 6492 : assert(m);
3088 : :
3089 : 6492 : c = message_get_last_container(m);
3090 [ + + ]: 6492 : if (c->enclosing != SD_BUS_TYPE_ARRAY)
3091 : 4468 : return false;
3092 : :
3093 [ + + ]: 2024 : if (BUS_MESSAGE_IS_GVARIANT(m))
3094 : 100 : return index >= c->end;
3095 : : else {
3096 [ - + ]: 1924 : assert(c->array_size);
3097 : 1924 : return index >= c->begin + BUS_MESSAGE_BSWAP32(m, *c->array_size);
3098 : : }
3099 : : }
3100 : :
3101 : 0 : _public_ int sd_bus_message_at_end(sd_bus_message *m, int complete) {
3102 [ # # # # ]: 0 : assert_return(m, -EINVAL);
3103 [ # # # # ]: 0 : assert_return(m->sealed, -EPERM);
3104 : :
3105 [ # # # # ]: 0 : if (complete && m->n_containers > 0)
3106 : 0 : return false;
3107 : :
3108 [ # # ]: 0 : if (message_end_of_signature(m))
3109 : 0 : return true;
3110 : :
3111 [ # # ]: 0 : if (message_end_of_array(m, m->rindex))
3112 : 0 : return true;
3113 : :
3114 : 0 : return false;
3115 : : }
3116 : :
3117 : 11936 : static struct bus_body_part* find_part(sd_bus_message *m, size_t index, size_t sz, void **p) {
3118 : : struct bus_body_part *part;
3119 : : size_t begin;
3120 : : int r;
3121 : :
3122 [ - + ]: 11936 : assert(m);
3123 : :
3124 [ + + + - ]: 11936 : if (m->cached_rindex_part && index >= m->cached_rindex_part_begin) {
3125 : 11668 : part = m->cached_rindex_part;
3126 : 11668 : begin = m->cached_rindex_part_begin;
3127 : : } else {
3128 : 268 : part = &m->body;
3129 : 268 : begin = 0;
3130 : : }
3131 : :
3132 [ + - ]: 11936 : while (part) {
3133 [ - + ]: 11936 : if (index < begin)
3134 : 0 : return NULL;
3135 : :
3136 [ + - ]: 11936 : if (index + sz <= begin + part->size) {
3137 : :
3138 : 11936 : r = bus_body_part_map(part);
3139 [ - + ]: 11936 : if (r < 0)
3140 : 0 : return NULL;
3141 : :
3142 [ + - ]: 11936 : if (p)
3143 : 11936 : *p = (uint8_t*) part->data + index - begin;
3144 : :
3145 : 11936 : m->cached_rindex_part = part;
3146 : 11936 : m->cached_rindex_part_begin = begin;
3147 : :
3148 : 11936 : return part;
3149 : : }
3150 : :
3151 : 0 : begin += part->size;
3152 : 0 : part = part->next;
3153 : : }
3154 : :
3155 : 0 : return NULL;
3156 : : }
3157 : :
3158 : 1252 : static int container_next_item(sd_bus_message *m, struct bus_container *c, size_t *rindex) {
3159 : : int r;
3160 : :
3161 [ - + ]: 1252 : assert(m);
3162 [ - + ]: 1252 : assert(c);
3163 [ - + ]: 1252 : assert(rindex);
3164 : :
3165 [ + + ]: 1252 : if (!BUS_MESSAGE_IS_GVARIANT(m))
3166 : 1032 : return 0;
3167 : :
3168 [ + + ]: 220 : if (c->enclosing == SD_BUS_TYPE_ARRAY) {
3169 : : int sz;
3170 : :
3171 : 40 : sz = bus_gvariant_get_size(c->signature);
3172 [ + - ]: 40 : if (sz < 0) {
3173 : : int alignment;
3174 : :
3175 [ + + ]: 40 : if (c->offset_index+1 >= c->n_offsets)
3176 : 16 : goto end;
3177 : :
3178 : : /* Variable-size array */
3179 : :
3180 : 24 : alignment = bus_gvariant_get_alignment(c->signature);
3181 [ - + ]: 24 : assert(alignment > 0);
3182 : :
3183 : 24 : *rindex = ALIGN_TO(c->offsets[c->offset_index], alignment);
3184 [ - + ]: 24 : assert(c->offsets[c->offset_index+1] >= *rindex);
3185 : 24 : c->item_size = c->offsets[c->offset_index+1] - *rindex;
3186 : : } else {
3187 : :
3188 [ # # ]: 0 : if (c->offset_index+1 >= (c->end-c->begin)/sz)
3189 : 0 : goto end;
3190 : :
3191 : : /* Fixed-size array */
3192 : 0 : *rindex = c->begin + (c->offset_index+1) * sz;
3193 : 0 : c->item_size = sz;
3194 : : }
3195 : :
3196 : 24 : c->offset_index++;
3197 : :
3198 [ + + + + ]: 180 : } else if (IN_SET(c->enclosing, 0, SD_BUS_TYPE_STRUCT, SD_BUS_TYPE_DICT_ENTRY)) {
3199 : :
3200 : : int alignment;
3201 : : size_t n, j;
3202 : :
3203 [ + + ]: 156 : if (c->offset_index+1 >= c->n_offsets)
3204 : 76 : goto end;
3205 : :
3206 : 80 : r = signature_element_length(c->signature + c->index, &n);
3207 [ - + ]: 80 : if (r < 0)
3208 : 0 : return r;
3209 : :
3210 : 80 : r = signature_element_length(c->signature + c->index + n, &j);
3211 [ - + ]: 80 : if (r < 0)
3212 : 0 : return r;
3213 : 80 : else {
3214 : 80 : char t[j+1];
3215 : 80 : memcpy(t, c->signature + c->index + n, j);
3216 : 80 : t[j] = 0;
3217 : :
3218 : 80 : alignment = bus_gvariant_get_alignment(t);
3219 : : }
3220 : :
3221 [ - + ]: 80 : assert(alignment > 0);
3222 : :
3223 : 80 : *rindex = ALIGN_TO(c->offsets[c->offset_index], alignment);
3224 [ - + ]: 80 : assert(c->offsets[c->offset_index+1] >= *rindex);
3225 : 80 : c->item_size = c->offsets[c->offset_index+1] - *rindex;
3226 : :
3227 : 80 : c->offset_index++;
3228 : :
3229 [ + - ]: 24 : } else if (c->enclosing == SD_BUS_TYPE_VARIANT)
3230 : 24 : goto end;
3231 : : else
3232 : 0 : assert_not_reached("Unknown container type");
3233 : :
3234 : 104 : return 0;
3235 : :
3236 : 116 : end:
3237 : : /* Reached the end */
3238 : 116 : *rindex = c->end;
3239 : 116 : c->item_size = 0;
3240 : 116 : return 0;
3241 : : }
3242 : :
3243 : 5968 : static int message_peek_body(
3244 : : sd_bus_message *m,
3245 : : size_t *rindex,
3246 : : size_t align,
3247 : : size_t nbytes,
3248 : : void **ret) {
3249 : :
3250 : : size_t k, start, end, padding;
3251 : : struct bus_body_part *part;
3252 : : uint8_t *q;
3253 : :
3254 [ - + ]: 5968 : assert(m);
3255 [ - + ]: 5968 : assert(rindex);
3256 [ - + ]: 5968 : assert(align > 0);
3257 : :
3258 : 5968 : start = ALIGN_TO((size_t) *rindex, align);
3259 : 5968 : padding = start - *rindex;
3260 : 5968 : end = start + nbytes;
3261 : :
3262 [ - + ]: 5968 : if (end > m->user_body_size)
3263 : 0 : return -EBADMSG;
3264 : :
3265 : 5968 : part = find_part(m, *rindex, padding, (void**) &q);
3266 [ - + ]: 5968 : if (!part)
3267 : 0 : return -EBADMSG;
3268 : :
3269 [ + - ]: 5968 : if (q) {
3270 : : /* Verify padding */
3271 [ + + ]: 8984 : for (k = 0; k < padding; k++)
3272 [ - + ]: 3016 : if (q[k] != 0)
3273 : 0 : return -EBADMSG;
3274 : : }
3275 : :
3276 : 5968 : part = find_part(m, start, nbytes, (void**) &q);
3277 [ + - + + : 5968 : if (!part || (nbytes > 0 && !q))
- + ]
3278 : 0 : return -EBADMSG;
3279 : :
3280 : 5968 : *rindex = end;
3281 : :
3282 [ + + ]: 5968 : if (ret)
3283 : 5124 : *ret = q;
3284 : :
3285 : 5968 : return 0;
3286 : : }
3287 : :
3288 : 5547 : static bool validate_nul(const char *s, size_t l) {
3289 : :
3290 : : /* Check for NUL chars in the string */
3291 [ - + ]: 5547 : if (memchr(s, 0, l))
3292 : 0 : return false;
3293 : :
3294 : : /* Check for NUL termination */
3295 [ - + ]: 5547 : if (s[l] != 0)
3296 : 0 : return false;
3297 : :
3298 : 5547 : return true;
3299 : : }
3300 : :
3301 : 1512 : static bool validate_string(const char *s, size_t l) {
3302 : :
3303 [ - + ]: 1512 : if (!validate_nul(s, l))
3304 : 0 : return false;
3305 : :
3306 : : /* Check if valid UTF8 */
3307 [ - + ]: 1512 : if (!utf8_is_valid(s))
3308 : 0 : return false;
3309 : :
3310 : 1512 : return true;
3311 : : }
3312 : :
3313 : 2626 : static bool validate_signature(const char *s, size_t l) {
3314 : :
3315 [ - + ]: 2626 : if (!validate_nul(s, l))
3316 : 0 : return false;
3317 : :
3318 : : /* Check if valid signature */
3319 [ - + ]: 2626 : if (!signature_is_valid(s, true))
3320 : 0 : return false;
3321 : :
3322 : 2626 : return true;
3323 : : }
3324 : :
3325 : 56 : static bool validate_object_path(const char *s, size_t l) {
3326 : :
3327 [ - + ]: 56 : if (!validate_nul(s, l))
3328 : 0 : return false;
3329 : :
3330 [ - + ]: 56 : if (!object_path_is_valid(s))
3331 : 0 : return false;
3332 : :
3333 : 56 : return true;
3334 : : }
3335 : :
3336 : 2196 : _public_ int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) {
3337 : : struct bus_container *c;
3338 : : size_t rindex;
3339 : : void *q;
3340 : : int r;
3341 : :
3342 [ - + - + ]: 2196 : assert_return(m, -EINVAL);
3343 [ - + - + ]: 2196 : assert_return(m->sealed, -EPERM);
3344 [ - + - + ]: 2196 : assert_return(bus_type_is_basic(type), -EINVAL);
3345 : :
3346 [ - + ]: 2196 : if (message_end_of_signature(m))
3347 : 0 : return -ENXIO;
3348 : :
3349 [ + + ]: 2196 : if (message_end_of_array(m, m->rindex))
3350 : 16 : return 0;
3351 : :
3352 : 2180 : c = message_get_last_container(m);
3353 [ - + ]: 2180 : if (c->signature[c->index] != type)
3354 : 0 : return -ENXIO;
3355 : :
3356 : 2180 : rindex = m->rindex;
3357 : :
3358 [ + + ]: 2180 : if (BUS_MESSAGE_IS_GVARIANT(m)) {
3359 : :
3360 [ + + + + ]: 112 : if (IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH, SD_BUS_TYPE_SIGNATURE)) {
3361 : : bool ok;
3362 : :
3363 : : /* D-Bus spec: The marshalling formats for the string-like types all end
3364 : : * with a single zero (NUL) byte, but that byte is not considered to be part
3365 : : * of the text. */
3366 [ - + ]: 48 : if (c->item_size == 0)
3367 : 0 : return -EBADMSG;
3368 : :
3369 : 48 : r = message_peek_body(m, &rindex, 1, c->item_size, &q);
3370 [ - + ]: 48 : if (r < 0)
3371 : 0 : return r;
3372 : :
3373 [ + - ]: 48 : if (type == SD_BUS_TYPE_STRING)
3374 : 48 : ok = validate_string(q, c->item_size-1);
3375 [ # # ]: 0 : else if (type == SD_BUS_TYPE_OBJECT_PATH)
3376 : 0 : ok = validate_object_path(q, c->item_size-1);
3377 : : else
3378 : 0 : ok = validate_signature(q, c->item_size-1);
3379 : :
3380 [ - + ]: 48 : if (!ok)
3381 : 0 : return -EBADMSG;
3382 : :
3383 [ + - ]: 48 : if (p)
3384 : 48 : *(const char**) p = q;
3385 : : } else {
3386 : : int sz, align;
3387 : :
3388 : 64 : sz = bus_gvariant_get_size(CHAR_TO_STR(type));
3389 [ - + ]: 64 : assert(sz > 0);
3390 [ - + ]: 64 : if ((size_t) sz != c->item_size)
3391 : 0 : return -EBADMSG;
3392 : :
3393 : 64 : align = bus_gvariant_get_alignment(CHAR_TO_STR(type));
3394 [ - + ]: 64 : assert(align > 0);
3395 : :
3396 : 64 : r = message_peek_body(m, &rindex, align, c->item_size, &q);
3397 [ - + ]: 64 : if (r < 0)
3398 : 0 : return r;
3399 : :
3400 [ - - - + : 64 : switch (type) {
+ - - ]
3401 : :
3402 : 0 : case SD_BUS_TYPE_BYTE:
3403 [ # # ]: 0 : if (p)
3404 : 0 : *(uint8_t*) p = *(uint8_t*) q;
3405 : 0 : break;
3406 : :
3407 : 0 : case SD_BUS_TYPE_BOOLEAN:
3408 [ # # ]: 0 : if (p)
3409 : 0 : *(int*) p = !!*(uint8_t*) q;
3410 : 0 : break;
3411 : :
3412 : 0 : case SD_BUS_TYPE_INT16:
3413 : : case SD_BUS_TYPE_UINT16:
3414 [ # # ]: 0 : if (p)
3415 : 0 : *(uint16_t*) p = BUS_MESSAGE_BSWAP16(m, *(uint16_t*) q);
3416 : 0 : break;
3417 : :
3418 : 56 : case SD_BUS_TYPE_INT32:
3419 : : case SD_BUS_TYPE_UINT32:
3420 [ + - ]: 56 : if (p)
3421 : 56 : *(uint32_t*) p = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
3422 : 56 : break;
3423 : :
3424 : 8 : case SD_BUS_TYPE_INT64:
3425 : : case SD_BUS_TYPE_UINT64:
3426 : : case SD_BUS_TYPE_DOUBLE:
3427 [ + - ]: 8 : if (p)
3428 : 8 : *(uint64_t*) p = BUS_MESSAGE_BSWAP64(m, *(uint64_t*) q);
3429 : 8 : break;
3430 : :
3431 : 0 : case SD_BUS_TYPE_UNIX_FD: {
3432 : : uint32_t j;
3433 : :
3434 : 0 : j = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
3435 [ # # ]: 0 : if (j >= m->n_fds)
3436 : 0 : return -EBADMSG;
3437 : :
3438 [ # # ]: 0 : if (p)
3439 : 0 : *(int*) p = m->fds[j];
3440 : :
3441 : 0 : break;
3442 : : }
3443 : :
3444 : 0 : default:
3445 : 0 : assert_not_reached("unexpected type");
3446 : : }
3447 : : }
3448 : :
3449 : 112 : r = container_next_item(m, c, &rindex);
3450 [ - + ]: 112 : if (r < 0)
3451 : 0 : return r;
3452 : : } else {
3453 : :
3454 [ + + + + ]: 2068 : if (IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH)) {
3455 : : uint32_t l;
3456 : : bool ok;
3457 : :
3458 : 1520 : r = message_peek_body(m, &rindex, 4, 4, &q);
3459 [ - + ]: 1520 : if (r < 0)
3460 : 0 : return r;
3461 : :
3462 : 1520 : l = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
3463 [ - + ]: 1520 : if (l == UINT32_MAX)
3464 : : /* avoid overflow right below */
3465 : 0 : return -EBADMSG;
3466 : :
3467 : 1520 : r = message_peek_body(m, &rindex, 1, l+1, &q);
3468 [ - + ]: 1520 : if (r < 0)
3469 : 0 : return r;
3470 : :
3471 [ + + ]: 1520 : if (type == SD_BUS_TYPE_OBJECT_PATH)
3472 : 56 : ok = validate_object_path(q, l);
3473 : : else
3474 : 1464 : ok = validate_string(q, l);
3475 [ - + ]: 1520 : if (!ok)
3476 : 0 : return -EBADMSG;
3477 : :
3478 [ + + ]: 1520 : if (p)
3479 : 1364 : *(const char**) p = q;
3480 : :
3481 [ + + ]: 548 : } else if (type == SD_BUS_TYPE_SIGNATURE) {
3482 : : uint8_t l;
3483 : :
3484 : 32 : r = message_peek_body(m, &rindex, 1, 1, &q);
3485 [ - + ]: 32 : if (r < 0)
3486 : 0 : return r;
3487 : :
3488 : 32 : l = *(uint8_t*) q;
3489 [ - + ]: 32 : if (l == UINT8_MAX)
3490 : : /* avoid overflow right below */
3491 : 0 : return -EBADMSG;
3492 : :
3493 : 32 : r = message_peek_body(m, &rindex, 1, l+1, &q);
3494 [ - + ]: 32 : if (r < 0)
3495 : 0 : return r;
3496 : :
3497 [ - + ]: 32 : if (!validate_signature(q, l))
3498 : 0 : return -EBADMSG;
3499 : :
3500 [ + + ]: 32 : if (p)
3501 : 28 : *(const char**) p = q;
3502 : :
3503 : : } else {
3504 : : ssize_t sz, align;
3505 : :
3506 : 516 : align = bus_type_get_alignment(type);
3507 [ - + ]: 516 : assert(align > 0);
3508 : :
3509 : 516 : sz = bus_type_get_size(type);
3510 [ - + ]: 516 : assert(sz > 0);
3511 : :
3512 : 516 : r = message_peek_body(m, &rindex, align, sz, &q);
3513 [ - + ]: 516 : if (r < 0)
3514 : 0 : return r;
3515 : :
3516 [ + + - + : 516 : switch (type) {
+ + - ]
3517 : :
3518 : 224 : case SD_BUS_TYPE_BYTE:
3519 [ + + ]: 224 : if (p)
3520 : 196 : *(uint8_t*) p = *(uint8_t*) q;
3521 : 224 : break;
3522 : :
3523 : 32 : case SD_BUS_TYPE_BOOLEAN:
3524 [ + - ]: 32 : if (p)
3525 : 32 : *(int*) p = !!*(uint32_t*) q;
3526 : 32 : break;
3527 : :
3528 : 0 : case SD_BUS_TYPE_INT16:
3529 : : case SD_BUS_TYPE_UINT16:
3530 [ # # ]: 0 : if (p)
3531 : 0 : *(uint16_t*) p = BUS_MESSAGE_BSWAP16(m, *(uint16_t*) q);
3532 : 0 : break;
3533 : :
3534 : 136 : case SD_BUS_TYPE_INT32:
3535 : : case SD_BUS_TYPE_UINT32:
3536 [ + - ]: 136 : if (p)
3537 : 136 : *(uint32_t*) p = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
3538 : 136 : break;
3539 : :
3540 : 120 : case SD_BUS_TYPE_INT64:
3541 : : case SD_BUS_TYPE_UINT64:
3542 : : case SD_BUS_TYPE_DOUBLE:
3543 [ + + ]: 120 : if (p)
3544 : 112 : *(uint64_t*) p = BUS_MESSAGE_BSWAP64(m, *(uint64_t*) q);
3545 : 120 : break;
3546 : :
3547 : 4 : case SD_BUS_TYPE_UNIX_FD: {
3548 : : uint32_t j;
3549 : :
3550 : 4 : j = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
3551 [ - + ]: 4 : if (j >= m->n_fds)
3552 : 0 : return -EBADMSG;
3553 : :
3554 [ + - ]: 4 : if (p)
3555 : 4 : *(int*) p = m->fds[j];
3556 : 4 : break;
3557 : : }
3558 : :
3559 : 0 : default:
3560 : 0 : assert_not_reached("Unknown basic type...");
3561 : : }
3562 : : }
3563 : : }
3564 : :
3565 : 2180 : m->rindex = rindex;
3566 : :
3567 [ + + ]: 2180 : if (c->enclosing != SD_BUS_TYPE_ARRAY)
3568 : 1724 : c->index++;
3569 : :
3570 : 2180 : return 1;
3571 : : }
3572 : :
3573 : 404 : static int bus_message_enter_array(
3574 : : sd_bus_message *m,
3575 : : struct bus_container *c,
3576 : : const char *contents,
3577 : : uint32_t **array_size,
3578 : : size_t *item_size,
3579 : : size_t **offsets,
3580 : : size_t *n_offsets) {
3581 : :
3582 : : size_t rindex;
3583 : : void *q;
3584 : : int r;
3585 : :
3586 [ - + ]: 404 : assert(m);
3587 [ - + ]: 404 : assert(c);
3588 [ - + ]: 404 : assert(contents);
3589 [ - + ]: 404 : assert(array_size);
3590 [ - + ]: 404 : assert(item_size);
3591 [ - + ]: 404 : assert(offsets);
3592 [ - + ]: 404 : assert(n_offsets);
3593 : :
3594 [ - + ]: 404 : if (!signature_is_single(contents, true))
3595 : 0 : return -EINVAL;
3596 : :
3597 [ + - - + ]: 404 : if (!c->signature || c->signature[c->index] == 0)
3598 : 0 : return -ENXIO;
3599 : :
3600 [ - + ]: 404 : if (c->signature[c->index] != SD_BUS_TYPE_ARRAY)
3601 : 0 : return -ENXIO;
3602 : :
3603 [ - + ]: 404 : if (!startswith(c->signature + c->index + 1, contents))
3604 : 0 : return -ENXIO;
3605 : :
3606 : 404 : rindex = m->rindex;
3607 : :
3608 [ + + ]: 404 : if (!BUS_MESSAGE_IS_GVARIANT(m)) {
3609 : : /* dbus1 */
3610 : : int alignment;
3611 : :
3612 : 384 : r = message_peek_body(m, &rindex, 4, 4, &q);
3613 [ - + ]: 384 : if (r < 0)
3614 : 0 : return r;
3615 : :
3616 [ - + ]: 384 : if (BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q) > BUS_ARRAY_MAX_SIZE)
3617 : 0 : return -EBADMSG;
3618 : :
3619 : 384 : alignment = bus_type_get_alignment(contents[0]);
3620 [ - + ]: 384 : if (alignment < 0)
3621 : 0 : return alignment;
3622 : :
3623 : 384 : r = message_peek_body(m, &rindex, alignment, 0, NULL);
3624 [ - + ]: 384 : if (r < 0)
3625 : 0 : return r;
3626 : :
3627 : 384 : *array_size = (uint32_t*) q;
3628 : :
3629 [ + + ]: 20 : } else if (c->item_size <= 0) {
3630 : :
3631 : : /* gvariant: empty array */
3632 : 4 : *item_size = 0;
3633 : 4 : *offsets = NULL;
3634 : 4 : *n_offsets = 0;
3635 : :
3636 [ - + ]: 16 : } else if (bus_gvariant_is_fixed_size(contents)) {
3637 : :
3638 : : /* gvariant: fixed length array */
3639 : 0 : *item_size = bus_gvariant_get_size(contents);
3640 : 0 : *offsets = NULL;
3641 : 0 : *n_offsets = 0;
3642 : :
3643 : : } else {
3644 : 16 : size_t where, previous = 0, framing, sz;
3645 : : int alignment;
3646 : : unsigned i;
3647 : :
3648 : : /* gvariant: variable length array */
3649 : 16 : sz = bus_gvariant_determine_word_size(c->item_size, 0);
3650 : :
3651 : 16 : where = rindex + c->item_size - sz;
3652 : 16 : r = message_peek_body(m, &where, 1, sz, &q);
3653 [ - + ]: 16 : if (r < 0)
3654 : 0 : return r;
3655 : :
3656 : 16 : framing = bus_gvariant_read_word_le(q, sz);
3657 [ - + ]: 16 : if (framing > c->item_size - sz)
3658 : 0 : return -EBADMSG;
3659 [ - + ]: 16 : if ((c->item_size - framing) % sz != 0)
3660 : 0 : return -EBADMSG;
3661 : :
3662 : 16 : *n_offsets = (c->item_size - framing) / sz;
3663 : :
3664 : 16 : where = rindex + framing;
3665 : 16 : r = message_peek_body(m, &where, 1, *n_offsets * sz, &q);
3666 [ - + ]: 16 : if (r < 0)
3667 : 0 : return r;
3668 : :
3669 : 16 : *offsets = new(size_t, *n_offsets);
3670 [ - + ]: 16 : if (!*offsets)
3671 : 0 : return -ENOMEM;
3672 : :
3673 : 16 : alignment = bus_gvariant_get_alignment(c->signature);
3674 [ - + ]: 16 : assert(alignment > 0);
3675 : :
3676 [ + + ]: 56 : for (i = 0; i < *n_offsets; i++) {
3677 : : size_t x, start;
3678 : :
3679 : 40 : start = ALIGN_TO(previous, alignment);
3680 : :
3681 : 40 : x = bus_gvariant_read_word_le((uint8_t*) q + i * sz, sz);
3682 [ - + ]: 40 : if (x > c->item_size - sz)
3683 : 0 : return -EBADMSG;
3684 [ - + ]: 40 : if (x < start)
3685 : 0 : return -EBADMSG;
3686 : :
3687 : 40 : (*offsets)[i] = rindex + x;
3688 : 40 : previous = x;
3689 : : }
3690 : :
3691 : 16 : *item_size = (*offsets)[0] - rindex;
3692 : : }
3693 : :
3694 : 404 : m->rindex = rindex;
3695 : :
3696 [ + - ]: 404 : if (c->enclosing != SD_BUS_TYPE_ARRAY)
3697 : 404 : c->index += 1 + strlen(contents);
3698 : :
3699 : 404 : return 1;
3700 : : }
3701 : :
3702 : 224 : static int bus_message_enter_variant(
3703 : : sd_bus_message *m,
3704 : : struct bus_container *c,
3705 : : const char *contents,
3706 : : size_t *item_size) {
3707 : :
3708 : : size_t rindex;
3709 : : uint8_t l;
3710 : : void *q;
3711 : : int r;
3712 : :
3713 [ - + ]: 224 : assert(m);
3714 [ - + ]: 224 : assert(c);
3715 [ - + ]: 224 : assert(contents);
3716 [ - + ]: 224 : assert(item_size);
3717 : :
3718 [ - + ]: 224 : if (!signature_is_single(contents, false))
3719 : 0 : return -EINVAL;
3720 : :
3721 [ - + ]: 224 : if (*contents == SD_BUS_TYPE_DICT_ENTRY_BEGIN)
3722 : 0 : return -EINVAL;
3723 : :
3724 [ + - - + ]: 224 : if (!c->signature || c->signature[c->index] == 0)
3725 : 0 : return -ENXIO;
3726 : :
3727 [ - + ]: 224 : if (c->signature[c->index] != SD_BUS_TYPE_VARIANT)
3728 : 0 : return -ENXIO;
3729 : :
3730 : 224 : rindex = m->rindex;
3731 : :
3732 [ + + ]: 224 : if (BUS_MESSAGE_IS_GVARIANT(m)) {
3733 : : size_t k, where;
3734 : :
3735 : 24 : k = strlen(contents);
3736 [ - + ]: 24 : if (1+k > c->item_size)
3737 : 0 : return -EBADMSG;
3738 : :
3739 : 24 : where = rindex + c->item_size - (1+k);
3740 : 24 : r = message_peek_body(m, &where, 1, 1+k, &q);
3741 [ - + ]: 24 : if (r < 0)
3742 : 0 : return r;
3743 : :
3744 [ - + ]: 24 : if (*(char*) q != 0)
3745 : 0 : return -EBADMSG;
3746 : :
3747 [ - + ]: 24 : if (memcmp((uint8_t*) q+1, contents, k))
3748 : 0 : return -ENXIO;
3749 : :
3750 : 24 : *item_size = c->item_size - (1+k);
3751 : :
3752 : : } else {
3753 : 200 : r = message_peek_body(m, &rindex, 1, 1, &q);
3754 [ - + ]: 200 : if (r < 0)
3755 : 0 : return r;
3756 : :
3757 : 200 : l = *(uint8_t*) q;
3758 [ - + ]: 200 : if (l == UINT8_MAX)
3759 : : /* avoid overflow right below */
3760 : 0 : return -EBADMSG;
3761 : :
3762 : 200 : r = message_peek_body(m, &rindex, 1, l+1, &q);
3763 [ - + ]: 200 : if (r < 0)
3764 : 0 : return r;
3765 : :
3766 [ - + ]: 200 : if (!validate_signature(q, l))
3767 : 0 : return -EBADMSG;
3768 : :
3769 [ - + ]: 200 : if (!streq(q, contents))
3770 : 0 : return -ENXIO;
3771 : : }
3772 : :
3773 : 224 : m->rindex = rindex;
3774 : :
3775 [ + - ]: 224 : if (c->enclosing != SD_BUS_TYPE_ARRAY)
3776 : 224 : c->index++;
3777 : :
3778 : 224 : return 1;
3779 : : }
3780 : :
3781 : 68 : static int build_struct_offsets(
3782 : : sd_bus_message *m,
3783 : : const char *signature,
3784 : : size_t size,
3785 : : size_t *item_size,
3786 : : size_t **offsets,
3787 : : size_t *n_offsets) {
3788 : :
3789 : 68 : unsigned n_variable = 0, n_total = 0, v;
3790 : : size_t previous, where;
3791 : : const char *p;
3792 : : size_t sz;
3793 : : void *q;
3794 : : int r;
3795 : :
3796 [ - + ]: 68 : assert(m);
3797 [ - + ]: 68 : assert(item_size);
3798 [ - + ]: 68 : assert(offsets);
3799 [ - + ]: 68 : assert(n_offsets);
3800 : :
3801 [ - + ]: 68 : if (isempty(signature)) {
3802 : : /* Unary type is encoded as *fixed* 1 byte padding */
3803 : 0 : r = message_peek_body(m, &m->rindex, 1, 1, &q);
3804 [ # # ]: 0 : if (r < 0)
3805 : 0 : return r;
3806 : :
3807 [ # # ]: 0 : if (*(uint8_t *) q != 0)
3808 : 0 : return -EBADMSG;
3809 : :
3810 : 0 : *item_size = 0;
3811 : 0 : *offsets = NULL;
3812 : 0 : *n_offsets = 0;
3813 : 0 : return 0;
3814 : : }
3815 : :
3816 : 68 : sz = bus_gvariant_determine_word_size(size, 0);
3817 [ - + ]: 68 : if (sz <= 0)
3818 : 0 : return -EBADMSG;
3819 : :
3820 : : /* First, loop over signature and count variable elements and
3821 : : * elements in general. We use this to know how large the
3822 : : * offset array is at the end of the structure. Note that
3823 : : * GVariant only stores offsets for all variable size elements
3824 : : * that are not the last item. */
3825 : :
3826 : 68 : p = signature;
3827 [ + + ]: 216 : while (*p != 0) {
3828 : : size_t n;
3829 : :
3830 : 148 : r = signature_element_length(p, &n);
3831 [ - + ]: 148 : if (r < 0)
3832 : 0 : return r;
3833 : 148 : else {
3834 : 148 : char t[n+1];
3835 : :
3836 : 148 : memcpy(t, p, n);
3837 : 148 : t[n] = 0;
3838 : :
3839 : 148 : r = bus_gvariant_is_fixed_size(t);
3840 : : }
3841 : :
3842 [ - + ]: 148 : if (r < 0)
3843 : 0 : return r;
3844 [ + + + + ]: 148 : if (r == 0 && p[n] != 0) /* except the last item */
3845 : 48 : n_variable++;
3846 : 148 : n_total++;
3847 : :
3848 : 148 : p += n;
3849 : : }
3850 : :
3851 [ - + ]: 68 : if (size < n_variable * sz)
3852 : 0 : return -EBADMSG;
3853 : :
3854 : 68 : where = m->rindex + size - (n_variable * sz);
3855 : 68 : r = message_peek_body(m, &where, 1, n_variable * sz, &q);
3856 [ - + ]: 68 : if (r < 0)
3857 : 0 : return r;
3858 : :
3859 : 68 : v = n_variable;
3860 : :
3861 : 68 : *offsets = new(size_t, n_total);
3862 [ - + ]: 68 : if (!*offsets)
3863 : 0 : return -ENOMEM;
3864 : :
3865 : 68 : *n_offsets = 0;
3866 : :
3867 : : /* Second, loop again and build an offset table */
3868 : 68 : p = signature;
3869 : 68 : previous = m->rindex;
3870 [ + + ]: 216 : while (*p != 0) {
3871 : : size_t n, offset;
3872 : : int k;
3873 : :
3874 : 148 : r = signature_element_length(p, &n);
3875 [ - + ]: 148 : if (r < 0)
3876 : 0 : return r;
3877 : 148 : else {
3878 : 148 : char t[n+1];
3879 : :
3880 : 148 : memcpy(t, p, n);
3881 : 148 : t[n] = 0;
3882 : :
3883 : 148 : size_t align = bus_gvariant_get_alignment(t);
3884 [ - + ]: 148 : assert(align > 0);
3885 : :
3886 : : /* The possible start of this member after including alignment */
3887 : 148 : size_t start = ALIGN_TO(previous, align);
3888 : :
3889 : 148 : k = bus_gvariant_get_size(t);
3890 [ + + ]: 148 : if (k < 0) {
3891 : : size_t x;
3892 : :
3893 : : /* Variable size */
3894 [ + + ]: 84 : if (v > 0) {
3895 : 48 : v--;
3896 : :
3897 : 48 : x = bus_gvariant_read_word_le((uint8_t*) q + v*sz, sz);
3898 [ - + ]: 48 : if (x >= size)
3899 : 0 : return -EBADMSG;
3900 : : } else
3901 : : /* The last item's end is determined
3902 : : * from the start of the offset array */
3903 : 36 : x = size - (n_variable * sz);
3904 : :
3905 : 84 : offset = m->rindex + x;
3906 [ - + ]: 84 : if (offset < start)
3907 [ # # ]: 0 : return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG),
3908 : : "For type %s with alignment %zu, message specifies offset %zu which is smaller than previous end %zu + alignment = %zu",
3909 : : t, align,
3910 : : offset,
3911 : : previous,
3912 : : start);
3913 : : } else
3914 : : /* Fixed size */
3915 : 64 : offset = start + k;
3916 : : }
3917 : :
3918 : 148 : previous = (*offsets)[(*n_offsets)++] = offset;
3919 : 148 : p += n;
3920 : : }
3921 : :
3922 [ - + ]: 68 : assert(v == 0);
3923 [ - + ]: 68 : assert(*n_offsets == n_total);
3924 : :
3925 : 68 : *item_size = (*offsets)[0] - m->rindex;
3926 : 68 : return 0;
3927 : : }
3928 : :
3929 : 524 : static int enter_struct_or_dict_entry(
3930 : : sd_bus_message *m,
3931 : : struct bus_container *c,
3932 : : const char *contents,
3933 : : size_t *item_size,
3934 : : size_t **offsets,
3935 : : size_t *n_offsets) {
3936 : :
3937 : : int r;
3938 : :
3939 [ - + ]: 524 : assert(m);
3940 [ - + ]: 524 : assert(c);
3941 [ - + ]: 524 : assert(contents);
3942 [ - + ]: 524 : assert(item_size);
3943 [ - + ]: 524 : assert(offsets);
3944 [ - + ]: 524 : assert(n_offsets);
3945 : :
3946 [ + + ]: 524 : if (!BUS_MESSAGE_IS_GVARIANT(m)) {
3947 : :
3948 : : /* dbus1 */
3949 : 460 : r = message_peek_body(m, &m->rindex, 8, 0, NULL);
3950 [ - + ]: 460 : if (r < 0)
3951 : 0 : return r;
3952 : :
3953 : : } else
3954 : : /* gvariant with contents */
3955 : 64 : return build_struct_offsets(m, contents, c->item_size, item_size, offsets, n_offsets);
3956 : :
3957 : 460 : return 0;
3958 : : }
3959 : :
3960 : 252 : static int bus_message_enter_struct(
3961 : : sd_bus_message *m,
3962 : : struct bus_container *c,
3963 : : const char *contents,
3964 : : size_t *item_size,
3965 : : size_t **offsets,
3966 : : size_t *n_offsets) {
3967 : :
3968 : : size_t l;
3969 : : int r;
3970 : :
3971 [ - + ]: 252 : assert(m);
3972 [ - + ]: 252 : assert(c);
3973 [ - + ]: 252 : assert(contents);
3974 [ - + ]: 252 : assert(item_size);
3975 [ - + ]: 252 : assert(offsets);
3976 [ - + ]: 252 : assert(n_offsets);
3977 : :
3978 [ - + ]: 252 : if (!signature_is_valid(contents, false))
3979 : 0 : return -EINVAL;
3980 : :
3981 [ + - - + ]: 252 : if (!c->signature || c->signature[c->index] == 0)
3982 : 0 : return -ENXIO;
3983 : :
3984 : 252 : l = strlen(contents);
3985 : :
3986 [ + - + - ]: 504 : if (c->signature[c->index] != SD_BUS_TYPE_STRUCT_BEGIN ||
3987 : 252 : !startswith(c->signature + c->index + 1, contents) ||
3988 [ - + ]: 252 : c->signature[c->index + 1 + l] != SD_BUS_TYPE_STRUCT_END)
3989 : 0 : return -ENXIO;
3990 : :
3991 : 252 : r = enter_struct_or_dict_entry(m, c, contents, item_size, offsets, n_offsets);
3992 [ - + ]: 252 : if (r < 0)
3993 : 0 : return r;
3994 : :
3995 [ + + ]: 252 : if (c->enclosing != SD_BUS_TYPE_ARRAY)
3996 : 88 : c->index += 1 + l + 1;
3997 : :
3998 : 252 : return 1;
3999 : : }
4000 : :
4001 : 272 : static int bus_message_enter_dict_entry(
4002 : : sd_bus_message *m,
4003 : : struct bus_container *c,
4004 : : const char *contents,
4005 : : size_t *item_size,
4006 : : size_t **offsets,
4007 : : size_t *n_offsets) {
4008 : :
4009 : : size_t l;
4010 : : int r;
4011 : :
4012 [ - + ]: 272 : assert(m);
4013 [ - + ]: 272 : assert(c);
4014 [ - + ]: 272 : assert(contents);
4015 : :
4016 [ - + ]: 272 : if (!signature_is_pair(contents))
4017 : 0 : return -EINVAL;
4018 : :
4019 [ - + ]: 272 : if (c->enclosing != SD_BUS_TYPE_ARRAY)
4020 : 0 : return -ENXIO;
4021 : :
4022 [ + - - + ]: 272 : if (!c->signature || c->signature[c->index] == 0)
4023 : 0 : return 0;
4024 : :
4025 : 272 : l = strlen(contents);
4026 : :
4027 [ + - + - ]: 544 : if (c->signature[c->index] != SD_BUS_TYPE_DICT_ENTRY_BEGIN ||
4028 : 272 : !startswith(c->signature + c->index + 1, contents) ||
4029 [ - + ]: 272 : c->signature[c->index + 1 + l] != SD_BUS_TYPE_DICT_ENTRY_END)
4030 : 0 : return -ENXIO;
4031 : :
4032 : 272 : r = enter_struct_or_dict_entry(m, c, contents, item_size, offsets, n_offsets);
4033 [ - + ]: 272 : if (r < 0)
4034 : 0 : return r;
4035 : :
4036 [ - + ]: 272 : if (c->enclosing != SD_BUS_TYPE_ARRAY)
4037 : 0 : c->index += 1 + l + 1;
4038 : :
4039 : 272 : return 1;
4040 : : }
4041 : :
4042 : 1160 : _public_ int sd_bus_message_enter_container(sd_bus_message *m,
4043 : : char type,
4044 : : const char *contents) {
4045 : : struct bus_container *c;
4046 : 1160 : uint32_t *array_size = NULL;
4047 : 1160 : _cleanup_free_ char *signature = NULL;
4048 : : size_t before, end;
4049 : 1160 : _cleanup_free_ size_t *offsets = NULL;
4050 : 1160 : size_t n_offsets = 0, item_size = 0;
4051 : : int r;
4052 : :
4053 [ - + - + ]: 1160 : assert_return(m, -EINVAL);
4054 [ - + - + ]: 1160 : assert_return(m->sealed, -EPERM);
4055 [ + + - + : 1160 : assert_return(type != 0 || !contents, -EINVAL);
- + ]
4056 : :
4057 [ + + - + ]: 1160 : if (type == 0 || !contents) {
4058 : : const char *cc;
4059 : : char tt;
4060 : :
4061 : : /* Allow entering into anonymous containers */
4062 : 4 : r = sd_bus_message_peek_type(m, &tt, &cc);
4063 [ - + ]: 4 : if (r < 0)
4064 : 0 : return r;
4065 : :
4066 [ - + # # ]: 4 : if (type != 0 && type != tt)
4067 : 0 : return -ENXIO;
4068 : :
4069 [ - + # # ]: 4 : if (contents && !streq(contents, cc))
4070 : 0 : return -ENXIO;
4071 : :
4072 : 4 : type = tt;
4073 : 4 : contents = cc;
4074 : : }
4075 : :
4076 : : /*
4077 : : * We enforce a global limit on container depth, that is much
4078 : : * higher than the 32 structs and 32 arrays the specification
4079 : : * mandates. This is simpler to implement for us, and we need
4080 : : * this only to ensure our container array doesn't grow
4081 : : * without bounds. We are happy to return any data from a
4082 : : * message as long as the data itself is valid, even if the
4083 : : * overall message might be not.
4084 : : *
4085 : : * Note that the message signature is validated when
4086 : : * parsing the headers, and that validation does check the
4087 : : * 32/32 limit.
4088 : : *
4089 : : * Note that the specification defines no limits on the depth
4090 : : * of stacked variants, but we do.
4091 : : */
4092 [ - + ]: 1160 : if (m->n_containers >= BUS_CONTAINER_DEPTH)
4093 : 0 : return -EBADMSG;
4094 : :
4095 [ - + ]: 1160 : if (!GREEDY_REALLOC(m->containers, m->containers_allocated, m->n_containers + 1))
4096 : 0 : return -ENOMEM;
4097 : :
4098 [ - + ]: 1160 : if (message_end_of_signature(m))
4099 : 0 : return -ENXIO;
4100 : :
4101 [ + + ]: 1160 : if (message_end_of_array(m, m->rindex))
4102 : 8 : return 0;
4103 : :
4104 : 1152 : c = message_get_last_container(m);
4105 : :
4106 : 1152 : signature = strdup(contents);
4107 [ - + ]: 1152 : if (!signature)
4108 : 0 : return -ENOMEM;
4109 : :
4110 : 1152 : c->saved_index = c->index;
4111 : 1152 : before = m->rindex;
4112 : :
4113 [ + + ]: 1152 : if (type == SD_BUS_TYPE_ARRAY)
4114 : 404 : r = bus_message_enter_array(m, c, contents, &array_size, &item_size, &offsets, &n_offsets);
4115 [ + + ]: 748 : else if (type == SD_BUS_TYPE_VARIANT)
4116 : 224 : r = bus_message_enter_variant(m, c, contents, &item_size);
4117 [ + + ]: 524 : else if (type == SD_BUS_TYPE_STRUCT)
4118 : 252 : r = bus_message_enter_struct(m, c, contents, &item_size, &offsets, &n_offsets);
4119 [ + - ]: 272 : else if (type == SD_BUS_TYPE_DICT_ENTRY)
4120 : 272 : r = bus_message_enter_dict_entry(m, c, contents, &item_size, &offsets, &n_offsets);
4121 : : else
4122 : 0 : r = -EINVAL;
4123 [ - + ]: 1152 : if (r <= 0)
4124 : 0 : return r;
4125 : :
4126 : : /* OK, let's fill it in */
4127 [ + + + + ]: 1152 : if (BUS_MESSAGE_IS_GVARIANT(m) &&
4128 [ - + ]: 64 : type == SD_BUS_TYPE_STRUCT &&
4129 : 64 : isempty(signature))
4130 : 0 : end = m->rindex + 0;
4131 : : else
4132 : 1152 : end = m->rindex + c->item_size;
4133 : :
4134 : 3456 : m->containers[m->n_containers++] = (struct bus_container) {
4135 : : .enclosing = type,
4136 : 1152 : .signature = TAKE_PTR(signature),
4137 : :
4138 : : .before = before,
4139 : 1152 : .begin = m->rindex,
4140 : : /* Unary type has fixed size of 1, but virtual size of 0 */
4141 : : .end = end,
4142 : : .array_size = array_size,
4143 : : .item_size = item_size,
4144 : 1152 : .offsets = TAKE_PTR(offsets),
4145 : : .n_offsets = n_offsets,
4146 : : };
4147 : :
4148 : 1152 : return 1;
4149 : : }
4150 : :
4151 : 1140 : _public_ int sd_bus_message_exit_container(sd_bus_message *m) {
4152 : : struct bus_container *c;
4153 : : unsigned saved;
4154 : : int r;
4155 : :
4156 [ - + - + ]: 1140 : assert_return(m, -EINVAL);
4157 [ - + - + ]: 1140 : assert_return(m->sealed, -EPERM);
4158 [ - + - + ]: 1140 : assert_return(m->n_containers > 0, -ENXIO);
4159 : :
4160 : 1140 : c = message_get_last_container(m);
4161 : :
4162 [ + + ]: 1140 : if (c->enclosing != SD_BUS_TYPE_ARRAY) {
4163 [ + - - + ]: 736 : if (c->signature && c->signature[c->index] != 0)
4164 : 0 : return -EBUSY;
4165 : : }
4166 : :
4167 [ + + ]: 1140 : if (BUS_MESSAGE_IS_GVARIANT(m)) {
4168 [ - + ]: 108 : if (m->rindex < c->end)
4169 : 0 : return -EBUSY;
4170 : :
4171 [ + + ]: 1032 : } else if (c->enclosing == SD_BUS_TYPE_ARRAY) {
4172 : : uint32_t l;
4173 : :
4174 : 384 : l = BUS_MESSAGE_BSWAP32(m, *c->array_size);
4175 [ - + ]: 384 : if (c->begin + l != m->rindex)
4176 : 0 : return -EBUSY;
4177 : : }
4178 : :
4179 : 1140 : message_free_last_container(m);
4180 : :
4181 : 1140 : c = message_get_last_container(m);
4182 : 1140 : saved = c->index;
4183 : 1140 : c->index = c->saved_index;
4184 : 1140 : r = container_next_item(m, c, &m->rindex);
4185 : 1140 : c->index = saved;
4186 [ - + ]: 1140 : if (r < 0)
4187 : 0 : return r;
4188 : :
4189 : 1140 : return 1;
4190 : : }
4191 : :
4192 : 0 : static void message_quit_container(sd_bus_message *m) {
4193 : : struct bus_container *c;
4194 : :
4195 [ # # ]: 0 : assert(m);
4196 [ # # ]: 0 : assert(m->sealed);
4197 [ # # ]: 0 : assert(m->n_containers > 0);
4198 : :
4199 : : /* Undo seeks */
4200 : 0 : c = message_get_last_container(m);
4201 [ # # ]: 0 : assert(m->rindex >= c->before);
4202 : 0 : m->rindex = c->before;
4203 : :
4204 : : /* Free container */
4205 : 0 : message_free_last_container(m);
4206 : :
4207 : : /* Correct index of new top-level container */
4208 : 0 : c = message_get_last_container(m);
4209 : 0 : c->index = c->saved_index;
4210 : 0 : }
4211 : :
4212 : 3752 : _public_ int sd_bus_message_peek_type(sd_bus_message *m, char *type, const char **contents) {
4213 : : struct bus_container *c;
4214 : : int r;
4215 : :
4216 [ - + - + ]: 3752 : assert_return(m, -EINVAL);
4217 [ - + - + ]: 3752 : assert_return(m->sealed, -EPERM);
4218 : :
4219 [ + + ]: 3752 : if (message_end_of_signature(m))
4220 : 720 : goto eof;
4221 : :
4222 [ + + ]: 3032 : if (message_end_of_array(m, m->rindex))
4223 : 348 : goto eof;
4224 : :
4225 : 2684 : c = message_get_last_container(m);
4226 : :
4227 [ + + ]: 2684 : if (bus_type_is_basic(c->signature[c->index])) {
4228 [ + - ]: 1640 : if (contents)
4229 : 1640 : *contents = NULL;
4230 [ + - ]: 1640 : if (type)
4231 : 1640 : *type = c->signature[c->index];
4232 : 1640 : return 1;
4233 : : }
4234 : :
4235 [ + + ]: 1044 : if (c->signature[c->index] == SD_BUS_TYPE_ARRAY) {
4236 : :
4237 [ + - ]: 376 : if (contents) {
4238 : : size_t l;
4239 : :
4240 : 376 : r = signature_element_length(c->signature+c->index+1, &l);
4241 [ - + ]: 376 : if (r < 0)
4242 : 0 : return r;
4243 : :
4244 : : /* signature_element_length does verification internally */
4245 : :
4246 : : /* The array element must not be empty */
4247 [ - + ]: 376 : assert(l >= 1);
4248 [ - + ]: 376 : if (free_and_strndup(&c->peeked_signature,
4249 : 376 : c->signature + c->index + 1, l) < 0)
4250 : 0 : return -ENOMEM;
4251 : :
4252 : 376 : *contents = c->peeked_signature;
4253 : : }
4254 : :
4255 [ + - ]: 376 : if (type)
4256 : 376 : *type = SD_BUS_TYPE_ARRAY;
4257 : :
4258 : 376 : return 1;
4259 : : }
4260 : :
4261 [ + + + + ]: 668 : if (IN_SET(c->signature[c->index], SD_BUS_TYPE_STRUCT_BEGIN, SD_BUS_TYPE_DICT_ENTRY_BEGIN)) {
4262 : :
4263 [ + - ]: 464 : if (contents) {
4264 : : size_t l;
4265 : :
4266 : 464 : r = signature_element_length(c->signature+c->index, &l);
4267 [ - + ]: 464 : if (r < 0)
4268 : 0 : return r;
4269 : :
4270 [ - + ]: 464 : assert(l >= 3);
4271 [ - + ]: 464 : if (free_and_strndup(&c->peeked_signature,
4272 : 464 : c->signature + c->index + 1, l - 2) < 0)
4273 : 0 : return -ENOMEM;
4274 : :
4275 : 464 : *contents = c->peeked_signature;
4276 : : }
4277 : :
4278 [ + - ]: 464 : if (type)
4279 [ + + ]: 464 : *type = c->signature[c->index] == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY;
4280 : :
4281 : 464 : return 1;
4282 : : }
4283 : :
4284 [ + - ]: 204 : if (c->signature[c->index] == SD_BUS_TYPE_VARIANT) {
4285 [ + - ]: 204 : if (contents) {
4286 : : void *q;
4287 : :
4288 [ + + ]: 204 : if (BUS_MESSAGE_IS_GVARIANT(m)) {
4289 : : size_t k;
4290 : :
4291 [ - + ]: 24 : if (c->item_size < 2)
4292 : 0 : return -EBADMSG;
4293 : :
4294 : : /* Look for the NUL delimiter that
4295 : : separates the payload from the
4296 : : signature. Since the body might be
4297 : : in a different part that then the
4298 : : signature we map byte by byte. */
4299 : :
4300 [ + - ]: 120 : for (k = 2; k <= c->item_size; k++) {
4301 : : size_t where;
4302 : :
4303 : 120 : where = m->rindex + c->item_size - k;
4304 : 120 : r = message_peek_body(m, &where, 1, k, &q);
4305 [ - + ]: 120 : if (r < 0)
4306 : 0 : return r;
4307 : :
4308 [ + + ]: 120 : if (*(char*) q == 0)
4309 : 24 : break;
4310 : : }
4311 : :
4312 [ - + ]: 24 : if (k > c->item_size)
4313 : 0 : return -EBADMSG;
4314 : :
4315 [ - + ]: 24 : if (free_and_strndup(&c->peeked_signature,
4316 : 24 : (char*) q + 1, k - 1) < 0)
4317 : 0 : return -ENOMEM;
4318 : :
4319 [ - + ]: 24 : if (!signature_is_valid(c->peeked_signature, true))
4320 : 0 : return -EBADMSG;
4321 : :
4322 : 24 : *contents = c->peeked_signature;
4323 : : } else {
4324 : : size_t rindex, l;
4325 : :
4326 : 180 : rindex = m->rindex;
4327 : 180 : r = message_peek_body(m, &rindex, 1, 1, &q);
4328 [ - + ]: 180 : if (r < 0)
4329 : 0 : return r;
4330 : :
4331 : 180 : l = *(uint8_t*) q;
4332 [ - + ]: 180 : if (l == UINT8_MAX)
4333 : : /* avoid overflow right below */
4334 : 0 : return -EBADMSG;
4335 : :
4336 : 180 : r = message_peek_body(m, &rindex, 1, l+1, &q);
4337 [ - + ]: 180 : if (r < 0)
4338 : 0 : return r;
4339 : :
4340 [ - + ]: 180 : if (!validate_signature(q, l))
4341 : 0 : return -EBADMSG;
4342 : :
4343 : 180 : *contents = q;
4344 : : }
4345 : : }
4346 : :
4347 [ + - ]: 204 : if (type)
4348 : 204 : *type = SD_BUS_TYPE_VARIANT;
4349 : :
4350 : 204 : return 1;
4351 : : }
4352 : :
4353 : 0 : return -EINVAL;
4354 : :
4355 : 1068 : eof:
4356 [ + + ]: 1068 : if (type)
4357 : 1064 : *type = 0;
4358 [ + + ]: 1068 : if (contents)
4359 : 1064 : *contents = NULL;
4360 : 1068 : return 0;
4361 : : }
4362 : :
4363 : 527 : _public_ int sd_bus_message_rewind(sd_bus_message *m, int complete) {
4364 : : struct bus_container *c;
4365 : :
4366 [ - + - + ]: 527 : assert_return(m, -EINVAL);
4367 [ - + - + ]: 527 : assert_return(m->sealed, -EPERM);
4368 : :
4369 [ + - ]: 527 : if (complete) {
4370 : 527 : message_reset_containers(m);
4371 : 527 : m->rindex = 0;
4372 : :
4373 : 527 : c = message_get_last_container(m);
4374 : : } else {
4375 : 0 : c = message_get_last_container(m);
4376 : :
4377 : 0 : c->index = 0;
4378 : 0 : m->rindex = c->begin;
4379 : : }
4380 : :
4381 : 527 : c->offset_index = 0;
4382 [ + + ]: 527 : c->item_size = (c->n_offsets > 0 ? c->offsets[0] : c->end) - c->begin;
4383 : :
4384 : 527 : return !isempty(c->signature);
4385 : : }
4386 : :
4387 : 280 : _public_ int sd_bus_message_readv(
4388 : : sd_bus_message *m,
4389 : : const char *types,
4390 : : va_list ap) {
4391 : :
4392 : : unsigned n_array, n_struct;
4393 : : TypeStack stack[BUS_CONTAINER_DEPTH];
4394 : 280 : unsigned stack_ptr = 0;
4395 : 280 : unsigned n_loop = 0;
4396 : : int r;
4397 : :
4398 [ - + - + ]: 280 : assert_return(m, -EINVAL);
4399 [ - + - + ]: 280 : assert_return(m->sealed, -EPERM);
4400 [ - + - + ]: 280 : assert_return(types, -EINVAL);
4401 : :
4402 [ - + ]: 280 : if (isempty(types))
4403 : 0 : return 0;
4404 : :
4405 : : /* Ideally, we'd just call ourselves recursively on every
4406 : : * complex type. However, the state of a va_list that is
4407 : : * passed to a function is undefined after that function
4408 : : * returns. This means we need to decode the va_list linearly
4409 : : * in a single stackframe. We hence implement our own
4410 : : * home-grown stack in an array. */
4411 : :
4412 : 280 : n_array = (unsigned) -1; /* length of current array entries */
4413 : 280 : n_struct = strlen(types); /* length of current struct contents signature */
4414 : :
4415 : 576 : for (;;) {
4416 : : const char *t;
4417 : :
4418 : 856 : n_loop++;
4419 : :
4420 [ + + + + : 856 : if (n_array == 0 || (n_array == (unsigned) -1 && n_struct == 0)) {
+ + ]
4421 : 348 : r = type_stack_pop(stack, ELEMENTSOF(stack), &stack_ptr, &types, &n_struct, &n_array);
4422 [ - + ]: 348 : if (r < 0)
4423 : 0 : return r;
4424 [ + + ]: 348 : if (r == 0)
4425 : 272 : break;
4426 : :
4427 : 76 : r = sd_bus_message_exit_container(m);
4428 [ - + ]: 76 : if (r < 0)
4429 : 0 : return r;
4430 : :
4431 : 76 : continue;
4432 : : }
4433 : :
4434 : 508 : t = types;
4435 [ + + ]: 508 : if (n_array != (unsigned) -1)
4436 : 60 : n_array--;
4437 : : else {
4438 : 448 : types++;
4439 : 448 : n_struct--;
4440 : : }
4441 : :
4442 [ + + + + : 508 : switch (*t) {
- ]
4443 : :
4444 : 424 : case SD_BUS_TYPE_BYTE:
4445 : : case SD_BUS_TYPE_BOOLEAN:
4446 : : case SD_BUS_TYPE_INT16:
4447 : : case SD_BUS_TYPE_UINT16:
4448 : : case SD_BUS_TYPE_INT32:
4449 : : case SD_BUS_TYPE_UINT32:
4450 : : case SD_BUS_TYPE_INT64:
4451 : : case SD_BUS_TYPE_UINT64:
4452 : : case SD_BUS_TYPE_DOUBLE:
4453 : : case SD_BUS_TYPE_STRING:
4454 : : case SD_BUS_TYPE_OBJECT_PATH:
4455 : : case SD_BUS_TYPE_SIGNATURE:
4456 : : case SD_BUS_TYPE_UNIX_FD: {
4457 : : void *p;
4458 : :
4459 : 424 : p = va_arg(ap, void*);
4460 : 424 : r = sd_bus_message_read_basic(m, *t, p);
4461 [ - + ]: 424 : if (r < 0)
4462 : 0 : return r;
4463 [ - + ]: 424 : if (r == 0) {
4464 [ # # ]: 0 : if (n_loop <= 1)
4465 : 0 : return 0;
4466 : :
4467 : 0 : return -ENXIO;
4468 : : }
4469 : :
4470 : 424 : break;
4471 : : }
4472 : :
4473 : 24 : case SD_BUS_TYPE_ARRAY: {
4474 : : size_t k;
4475 : :
4476 : 24 : r = signature_element_length(t + 1, &k);
4477 [ - + ]: 24 : if (r < 0)
4478 : 0 : return r;
4479 : :
4480 : 24 : {
4481 : 24 : char s[k + 1];
4482 : 24 : memcpy(s, t + 1, k);
4483 : 24 : s[k] = 0;
4484 : :
4485 : 24 : r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, s);
4486 [ - + ]: 24 : if (r < 0)
4487 : 0 : return r;
4488 [ - + ]: 24 : if (r == 0) {
4489 [ # # ]: 0 : if (n_loop <= 1)
4490 : 0 : return 0;
4491 : :
4492 : 0 : return -ENXIO;
4493 : : }
4494 : : }
4495 : :
4496 [ + - ]: 24 : if (n_array == (unsigned) -1) {
4497 : 24 : types += k;
4498 : 24 : n_struct -= k;
4499 : : }
4500 : :
4501 : 24 : r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
4502 [ - + ]: 24 : if (r < 0)
4503 : 0 : return r;
4504 : :
4505 : 24 : types = t + 1;
4506 : 24 : n_struct = k;
4507 : 24 : n_array = va_arg(ap, unsigned);
4508 : :
4509 : 24 : break;
4510 : : }
4511 : :
4512 : 8 : case SD_BUS_TYPE_VARIANT: {
4513 : : const char *s;
4514 : :
4515 : 8 : s = va_arg(ap, const char *);
4516 [ - + ]: 8 : if (!s)
4517 : 0 : return -EINVAL;
4518 : :
4519 : 8 : r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, s);
4520 [ - + ]: 8 : if (r < 0)
4521 : 0 : return r;
4522 [ - + ]: 8 : if (r == 0) {
4523 [ # # ]: 0 : if (n_loop <= 1)
4524 : 0 : return 0;
4525 : :
4526 : 0 : return -ENXIO;
4527 : : }
4528 : :
4529 : 8 : r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
4530 [ - + ]: 8 : if (r < 0)
4531 : 0 : return r;
4532 : :
4533 : 8 : types = s;
4534 : 8 : n_struct = strlen(s);
4535 : 8 : n_array = (unsigned) -1;
4536 : :
4537 : 8 : break;
4538 : : }
4539 : :
4540 : 52 : case SD_BUS_TYPE_STRUCT_BEGIN:
4541 : : case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
4542 : : size_t k;
4543 : :
4544 : 52 : r = signature_element_length(t, &k);
4545 [ + + ]: 52 : if (r < 0)
4546 : 8 : return r;
4547 : :
4548 : 48 : {
4549 : 48 : char s[k - 1];
4550 : 48 : memcpy(s, t + 1, k - 2);
4551 : 48 : s[k - 2] = 0;
4552 : :
4553 [ + + ]: 48 : r = sd_bus_message_enter_container(m, *t == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
4554 [ - + ]: 48 : if (r < 0)
4555 : 0 : return r;
4556 [ + + ]: 48 : if (r == 0) {
4557 [ + - ]: 4 : if (n_loop <= 1)
4558 : 4 : return 0;
4559 : 0 : return -ENXIO;
4560 : : }
4561 : : }
4562 : :
4563 [ + + ]: 44 : if (n_array == (unsigned) -1) {
4564 : 20 : types += k - 1;
4565 : 20 : n_struct -= k - 1;
4566 : : }
4567 : :
4568 : 44 : r = type_stack_push(stack, ELEMENTSOF(stack), &stack_ptr, types, n_struct, n_array);
4569 [ - + ]: 44 : if (r < 0)
4570 : 0 : return r;
4571 : :
4572 : 44 : types = t + 1;
4573 : 44 : n_struct = k - 2;
4574 : 44 : n_array = (unsigned) -1;
4575 : :
4576 : 44 : break;
4577 : : }
4578 : :
4579 : 0 : default:
4580 : 0 : return -EINVAL;
4581 : : }
4582 : : }
4583 : :
4584 : 272 : return 1;
4585 : : }
4586 : :
4587 : 280 : _public_ int sd_bus_message_read(sd_bus_message *m, const char *types, ...) {
4588 : : va_list ap;
4589 : : int r;
4590 : :
4591 : 280 : va_start(ap, types);
4592 : 280 : r = sd_bus_message_readv(m, types, ap);
4593 : 280 : va_end(ap);
4594 : :
4595 : 280 : return r;
4596 : : }
4597 : :
4598 : 420 : _public_ int sd_bus_message_skip(sd_bus_message *m, const char *types) {
4599 : : int r;
4600 : :
4601 [ - + - + ]: 420 : assert_return(m, -EINVAL);
4602 [ - + - + ]: 420 : assert_return(m->sealed, -EPERM);
4603 : :
4604 : : /* If types is NULL, read exactly one element */
4605 [ + + ]: 420 : if (!types) {
4606 : : struct bus_container *c;
4607 : : size_t l;
4608 : :
4609 [ - + ]: 104 : if (message_end_of_signature(m))
4610 : 0 : return -ENXIO;
4611 : :
4612 [ - + ]: 104 : if (message_end_of_array(m, m->rindex))
4613 : 0 : return 0;
4614 : :
4615 : 104 : c = message_get_last_container(m);
4616 : :
4617 : 104 : r = signature_element_length(c->signature + c->index, &l);
4618 [ - + ]: 104 : if (r < 0)
4619 : 0 : return r;
4620 : :
4621 : 104 : types = strndupa(c->signature + c->index, l);
4622 : : }
4623 : :
4624 [ + + + + : 420 : switch (*types) {
+ - ]
4625 : :
4626 : 176 : case 0: /* Nothing to drop */
4627 : 176 : return 0;
4628 : :
4629 : 204 : case SD_BUS_TYPE_BYTE:
4630 : : case SD_BUS_TYPE_BOOLEAN:
4631 : : case SD_BUS_TYPE_INT16:
4632 : : case SD_BUS_TYPE_UINT16:
4633 : : case SD_BUS_TYPE_INT32:
4634 : : case SD_BUS_TYPE_UINT32:
4635 : : case SD_BUS_TYPE_INT64:
4636 : : case SD_BUS_TYPE_UINT64:
4637 : : case SD_BUS_TYPE_DOUBLE:
4638 : : case SD_BUS_TYPE_STRING:
4639 : : case SD_BUS_TYPE_OBJECT_PATH:
4640 : : case SD_BUS_TYPE_SIGNATURE:
4641 : : case SD_BUS_TYPE_UNIX_FD:
4642 : :
4643 : 204 : r = sd_bus_message_read_basic(m, *types, NULL);
4644 [ + + ]: 204 : if (r <= 0)
4645 : 8 : return r;
4646 : :
4647 : 196 : r = sd_bus_message_skip(m, types + 1);
4648 [ - + ]: 196 : if (r < 0)
4649 : 0 : return r;
4650 : :
4651 : 196 : return 1;
4652 : :
4653 : 12 : case SD_BUS_TYPE_ARRAY: {
4654 : : size_t k;
4655 : :
4656 : 12 : r = signature_element_length(types + 1, &k);
4657 [ - + ]: 12 : if (r < 0)
4658 : 0 : return r;
4659 : :
4660 : 12 : {
4661 : 12 : char s[k+1];
4662 : 12 : memcpy(s, types+1, k);
4663 : 12 : s[k] = 0;
4664 : :
4665 : 12 : r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, s);
4666 [ - + ]: 12 : if (r <= 0)
4667 : 0 : return r;
4668 : :
4669 : : for (;;) {
4670 : 48 : r = sd_bus_message_skip(m, s);
4671 [ - + ]: 48 : if (r < 0)
4672 : 0 : return r;
4673 [ + + ]: 48 : if (r == 0)
4674 : 12 : break;
4675 : : }
4676 : :
4677 : 12 : r = sd_bus_message_exit_container(m);
4678 [ - + ]: 12 : if (r < 0)
4679 : 0 : return r;
4680 : : }
4681 : :
4682 : 12 : r = sd_bus_message_skip(m, types + 1 + k);
4683 [ - + ]: 12 : if (r < 0)
4684 : 0 : return r;
4685 : :
4686 : 12 : return 1;
4687 : : }
4688 : :
4689 : 8 : case SD_BUS_TYPE_VARIANT: {
4690 : : const char *contents;
4691 : : char x;
4692 : :
4693 : 8 : r = sd_bus_message_peek_type(m, &x, &contents);
4694 [ - + ]: 8 : if (r <= 0)
4695 : 0 : return r;
4696 : :
4697 [ - + ]: 8 : if (x != SD_BUS_TYPE_VARIANT)
4698 : 0 : return -ENXIO;
4699 : :
4700 : 8 : r = sd_bus_message_enter_container(m, SD_BUS_TYPE_VARIANT, contents);
4701 [ - + ]: 8 : if (r <= 0)
4702 : 0 : return r;
4703 : :
4704 : 8 : r = sd_bus_message_skip(m, contents);
4705 [ - + ]: 8 : if (r < 0)
4706 : 0 : return r;
4707 [ - + ]: 8 : assert(r != 0);
4708 : :
4709 : 8 : r = sd_bus_message_exit_container(m);
4710 [ - + ]: 8 : if (r < 0)
4711 : 0 : return r;
4712 : :
4713 : 8 : r = sd_bus_message_skip(m, types + 1);
4714 [ - + ]: 8 : if (r < 0)
4715 : 0 : return r;
4716 : :
4717 : 8 : return 1;
4718 : : }
4719 : :
4720 : 20 : case SD_BUS_TYPE_STRUCT_BEGIN:
4721 : : case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
4722 : : size_t k;
4723 : :
4724 : 20 : r = signature_element_length(types, &k);
4725 [ - + ]: 20 : if (r < 0)
4726 : 0 : return r;
4727 : :
4728 : 20 : {
4729 : 20 : char s[k-1];
4730 : 20 : memcpy(s, types+1, k-2);
4731 : 20 : s[k-2] = 0;
4732 : :
4733 [ + + ]: 20 : r = sd_bus_message_enter_container(m, *types == SD_BUS_TYPE_STRUCT_BEGIN ? SD_BUS_TYPE_STRUCT : SD_BUS_TYPE_DICT_ENTRY, s);
4734 [ + + ]: 20 : if (r <= 0)
4735 : 4 : return r;
4736 : :
4737 : 16 : r = sd_bus_message_skip(m, s);
4738 [ - + ]: 16 : if (r < 0)
4739 : 0 : return r;
4740 : :
4741 : 16 : r = sd_bus_message_exit_container(m);
4742 [ - + ]: 16 : if (r < 0)
4743 : 0 : return r;
4744 : : }
4745 : :
4746 : 16 : r = sd_bus_message_skip(m, types + k);
4747 [ - + ]: 16 : if (r < 0)
4748 : 0 : return r;
4749 : :
4750 : 16 : return 1;
4751 : : }
4752 : :
4753 : 0 : default:
4754 : 0 : return -EINVAL;
4755 : : }
4756 : : }
4757 : :
4758 : 8 : _public_ int sd_bus_message_read_array(
4759 : : sd_bus_message *m,
4760 : : char type,
4761 : : const void **ptr,
4762 : : size_t *size) {
4763 : :
4764 : : struct bus_container *c;
4765 : : void *p;
4766 : : size_t sz;
4767 : : ssize_t align;
4768 : : int r;
4769 : :
4770 [ - + - + ]: 8 : assert_return(m, -EINVAL);
4771 [ - + - + ]: 8 : assert_return(m->sealed, -EPERM);
4772 [ - + - + ]: 8 : assert_return(bus_type_is_trivial(type), -EINVAL);
4773 [ - + - + ]: 8 : assert_return(ptr, -EINVAL);
4774 [ - + - + ]: 8 : assert_return(size, -EINVAL);
4775 [ - + - + ]: 8 : assert_return(!BUS_MESSAGE_NEED_BSWAP(m), -EOPNOTSUPP);
4776 : :
4777 : 8 : r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type));
4778 [ - + ]: 8 : if (r <= 0)
4779 : 0 : return r;
4780 : :
4781 : 8 : c = message_get_last_container(m);
4782 : :
4783 [ - + ]: 8 : if (BUS_MESSAGE_IS_GVARIANT(m)) {
4784 : 0 : align = bus_gvariant_get_alignment(CHAR_TO_STR(type));
4785 [ # # ]: 0 : if (align < 0)
4786 : 0 : return align;
4787 : :
4788 : 0 : sz = c->end - c->begin;
4789 : : } else {
4790 : 8 : align = bus_type_get_alignment(type);
4791 [ - + ]: 8 : if (align < 0)
4792 : 0 : return align;
4793 : :
4794 : 8 : sz = BUS_MESSAGE_BSWAP32(m, *c->array_size);
4795 : : }
4796 : :
4797 [ + + ]: 8 : if (sz == 0)
4798 : : /* Zero length array, let's return some aligned
4799 : : * pointer that is not NULL */
4800 : 4 : p = (uint8_t*) align;
4801 : : else {
4802 : 4 : r = message_peek_body(m, &m->rindex, align, sz, &p);
4803 [ - + ]: 4 : if (r < 0)
4804 : 0 : goto fail;
4805 : : }
4806 : :
4807 : 8 : r = sd_bus_message_exit_container(m);
4808 [ - + ]: 8 : if (r < 0)
4809 : 0 : goto fail;
4810 : :
4811 : 8 : *ptr = (const void*) p;
4812 : 8 : *size = sz;
4813 : :
4814 : 8 : return 1;
4815 : :
4816 : 0 : fail:
4817 : 0 : message_quit_container(m);
4818 : 0 : return r;
4819 : : }
4820 : :
4821 : 9364 : static int message_peek_fields(
4822 : : sd_bus_message *m,
4823 : : size_t *rindex,
4824 : : size_t align,
4825 : : size_t nbytes,
4826 : : void **ret) {
4827 : :
4828 [ - + ]: 9364 : assert(m);
4829 [ - + ]: 9364 : assert(rindex);
4830 [ - + ]: 9364 : assert(align > 0);
4831 : :
4832 : 9364 : return buffer_peek(BUS_MESSAGE_FIELDS(m), m->fields_size, rindex, align, nbytes, ret);
4833 : : }
4834 : :
4835 : 1624 : static int message_peek_field_uint32(
4836 : : sd_bus_message *m,
4837 : : size_t *ri,
4838 : : size_t item_size,
4839 : : uint32_t *ret) {
4840 : :
4841 : : int r;
4842 : : void *q;
4843 : :
4844 [ - + ]: 1624 : assert(m);
4845 [ - + ]: 1624 : assert(ri);
4846 : :
4847 [ - + # # ]: 1624 : if (BUS_MESSAGE_IS_GVARIANT(m) && item_size != 4)
4848 : 0 : return -EBADMSG;
4849 : :
4850 : : /* identical for gvariant and dbus1 */
4851 : :
4852 : 1624 : r = message_peek_fields(m, ri, 4, 4, &q);
4853 [ - + ]: 1624 : if (r < 0)
4854 : 0 : return r;
4855 : :
4856 [ + - ]: 1624 : if (ret)
4857 : 1624 : *ret = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q);
4858 : :
4859 : 1624 : return 0;
4860 : : }
4861 : :
4862 : 0 : static int message_peek_field_uint64(
4863 : : sd_bus_message *m,
4864 : : size_t *ri,
4865 : : size_t item_size,
4866 : : uint64_t *ret) {
4867 : :
4868 : : int r;
4869 : : void *q;
4870 : :
4871 [ # # ]: 0 : assert(m);
4872 [ # # ]: 0 : assert(ri);
4873 : :
4874 [ # # # # ]: 0 : if (BUS_MESSAGE_IS_GVARIANT(m) && item_size != 8)
4875 : 0 : return -EBADMSG;
4876 : :
4877 : : /* identical for gvariant and dbus1 */
4878 : :
4879 : 0 : r = message_peek_fields(m, ri, 8, 8, &q);
4880 [ # # ]: 0 : if (r < 0)
4881 : 0 : return r;
4882 : :
4883 [ # # ]: 0 : if (ret)
4884 : 0 : *ret = BUS_MESSAGE_BSWAP64(m, *(uint64_t*) q);
4885 : :
4886 : 0 : return 0;
4887 : : }
4888 : :
4889 : 1353 : static int message_peek_field_string(
4890 : : sd_bus_message *m,
4891 : : bool (*validate)(const char *p),
4892 : : size_t *ri,
4893 : : size_t item_size,
4894 : : const char **ret) {
4895 : :
4896 : : uint32_t l;
4897 : : int r;
4898 : : void *q;
4899 : :
4900 [ - + ]: 1353 : assert(m);
4901 [ - + ]: 1353 : assert(ri);
4902 : :
4903 [ + + ]: 1353 : if (BUS_MESSAGE_IS_GVARIANT(m)) {
4904 : :
4905 [ - + ]: 16 : if (item_size <= 0)
4906 : 0 : return -EBADMSG;
4907 : :
4908 : 16 : r = message_peek_fields(m, ri, 1, item_size, &q);
4909 [ - + ]: 16 : if (r < 0)
4910 : 0 : return r;
4911 : :
4912 : 16 : l = item_size - 1;
4913 : : } else {
4914 : 1337 : r = message_peek_field_uint32(m, ri, 4, &l);
4915 [ - + ]: 1337 : if (r < 0)
4916 : 0 : return r;
4917 : :
4918 [ - + ]: 1337 : if (l == UINT32_MAX)
4919 : : /* avoid overflow right below */
4920 : 0 : return -EBADMSG;
4921 : :
4922 : 1337 : r = message_peek_fields(m, ri, 1, l+1, &q);
4923 [ - + ]: 1337 : if (r < 0)
4924 : 0 : return r;
4925 : : }
4926 : :
4927 [ + - ]: 1353 : if (validate) {
4928 [ - + ]: 1353 : if (!validate_nul(q, l))
4929 : 0 : return -EBADMSG;
4930 : :
4931 [ - + ]: 1353 : if (!validate(q))
4932 : 0 : return -EBADMSG;
4933 : : } else {
4934 [ # # ]: 0 : if (!validate_string(q, l))
4935 : 0 : return -EBADMSG;
4936 : : }
4937 : :
4938 [ + - ]: 1353 : if (ret)
4939 : 1353 : *ret = q;
4940 : :
4941 : 1353 : return 0;
4942 : : }
4943 : :
4944 : 2214 : static int message_peek_field_signature(
4945 : : sd_bus_message *m,
4946 : : size_t *ri,
4947 : : size_t item_size,
4948 : : const char **ret) {
4949 : :
4950 : : size_t l;
4951 : : int r;
4952 : : void *q;
4953 : :
4954 [ - + ]: 2214 : assert(m);
4955 [ - + ]: 2214 : assert(ri);
4956 : :
4957 [ - + ]: 2214 : if (BUS_MESSAGE_IS_GVARIANT(m)) {
4958 : :
4959 [ # # ]: 0 : if (item_size <= 0)
4960 : 0 : return -EBADMSG;
4961 : :
4962 : 0 : r = message_peek_fields(m, ri, 1, item_size, &q);
4963 [ # # ]: 0 : if (r < 0)
4964 : 0 : return r;
4965 : :
4966 : 0 : l = item_size - 1;
4967 : : } else {
4968 : 2214 : r = message_peek_fields(m, ri, 1, 1, &q);
4969 [ - + ]: 2214 : if (r < 0)
4970 : 0 : return r;
4971 : :
4972 : 2214 : l = *(uint8_t*) q;
4973 [ - + ]: 2214 : if (l == UINT8_MAX)
4974 : : /* avoid overflow right below */
4975 : 0 : return -EBADMSG;
4976 : :
4977 : 2214 : r = message_peek_fields(m, ri, 1, l+1, &q);
4978 [ - + ]: 2214 : if (r < 0)
4979 : 0 : return r;
4980 : : }
4981 : :
4982 [ - + ]: 2214 : if (!validate_signature(q, l))
4983 : 0 : return -EBADMSG;
4984 : :
4985 [ + - ]: 2214 : if (ret)
4986 : 2214 : *ret = q;
4987 : :
4988 : 2214 : return 0;
4989 : : }
4990 : :
4991 : 0 : static int message_skip_fields(
4992 : : sd_bus_message *m,
4993 : : size_t *ri,
4994 : : uint32_t array_size,
4995 : : const char **signature) {
4996 : :
4997 : : size_t original_index;
4998 : : int r;
4999 : :
5000 [ # # ]: 0 : assert(m);
5001 [ # # ]: 0 : assert(ri);
5002 [ # # ]: 0 : assert(signature);
5003 [ # # ]: 0 : assert(!BUS_MESSAGE_IS_GVARIANT(m));
5004 : :
5005 : 0 : original_index = *ri;
5006 : :
5007 : 0 : for (;;) {
5008 : : char t;
5009 : : size_t l;
5010 : :
5011 [ # # ]: 0 : if (array_size != (uint32_t) -1 &&
5012 [ # # ]: 0 : array_size <= *ri - original_index)
5013 : 0 : return 0;
5014 : :
5015 : 0 : t = **signature;
5016 [ # # ]: 0 : if (!t)
5017 : 0 : return 0;
5018 : :
5019 [ # # ]: 0 : if (t == SD_BUS_TYPE_STRING) {
5020 : :
5021 : 0 : r = message_peek_field_string(m, NULL, ri, 0, NULL);
5022 [ # # ]: 0 : if (r < 0)
5023 : 0 : return r;
5024 : :
5025 : 0 : (*signature)++;
5026 : :
5027 [ # # ]: 0 : } else if (t == SD_BUS_TYPE_OBJECT_PATH) {
5028 : :
5029 : 0 : r = message_peek_field_string(m, object_path_is_valid, ri, 0, NULL);
5030 [ # # ]: 0 : if (r < 0)
5031 : 0 : return r;
5032 : :
5033 : 0 : (*signature)++;
5034 : :
5035 [ # # ]: 0 : } else if (t == SD_BUS_TYPE_SIGNATURE) {
5036 : :
5037 : 0 : r = message_peek_field_signature(m, ri, 0, NULL);
5038 [ # # ]: 0 : if (r < 0)
5039 : 0 : return r;
5040 : :
5041 : 0 : (*signature)++;
5042 : :
5043 [ # # ]: 0 : } else if (bus_type_is_basic(t)) {
5044 : : ssize_t align, k;
5045 : :
5046 : 0 : align = bus_type_get_alignment(t);
5047 : 0 : k = bus_type_get_size(t);
5048 [ # # # # ]: 0 : assert(align > 0 && k > 0);
5049 : :
5050 : 0 : r = message_peek_fields(m, ri, align, k, NULL);
5051 [ # # ]: 0 : if (r < 0)
5052 : 0 : return r;
5053 : :
5054 : 0 : (*signature)++;
5055 : :
5056 [ # # ]: 0 : } else if (t == SD_BUS_TYPE_ARRAY) {
5057 : :
5058 : 0 : r = signature_element_length(*signature + 1, &l);
5059 [ # # ]: 0 : if (r < 0)
5060 : 0 : return r;
5061 : :
5062 [ # # ]: 0 : assert(l >= 1);
5063 : 0 : {
5064 : 0 : char sig[l + 1], *s = sig;
5065 : : uint32_t nas;
5066 : : int alignment;
5067 : :
5068 : 0 : strncpy(sig, *signature + 1, l);
5069 : 0 : sig[l] = '\0';
5070 : :
5071 : 0 : alignment = bus_type_get_alignment(sig[0]);
5072 [ # # ]: 0 : if (alignment < 0)
5073 : 0 : return alignment;
5074 : :
5075 : 0 : r = message_peek_field_uint32(m, ri, 0, &nas);
5076 [ # # ]: 0 : if (r < 0)
5077 : 0 : return r;
5078 [ # # ]: 0 : if (nas > BUS_ARRAY_MAX_SIZE)
5079 : 0 : return -EBADMSG;
5080 : :
5081 : 0 : r = message_peek_fields(m, ri, alignment, 0, NULL);
5082 [ # # ]: 0 : if (r < 0)
5083 : 0 : return r;
5084 : :
5085 : 0 : r = message_skip_fields(m, ri, nas, (const char**) &s);
5086 [ # # ]: 0 : if (r < 0)
5087 : 0 : return r;
5088 : : }
5089 : :
5090 : 0 : (*signature) += 1 + l;
5091 : :
5092 [ # # ]: 0 : } else if (t == SD_BUS_TYPE_VARIANT) {
5093 : : const char *s;
5094 : :
5095 : 0 : r = message_peek_field_signature(m, ri, 0, &s);
5096 [ # # ]: 0 : if (r < 0)
5097 : 0 : return r;
5098 : :
5099 : 0 : r = message_skip_fields(m, ri, (uint32_t) -1, (const char**) &s);
5100 [ # # ]: 0 : if (r < 0)
5101 : 0 : return r;
5102 : :
5103 : 0 : (*signature)++;
5104 : :
5105 [ # # # # ]: 0 : } else if (IN_SET(t, SD_BUS_TYPE_STRUCT, SD_BUS_TYPE_DICT_ENTRY)) {
5106 : :
5107 : 0 : r = signature_element_length(*signature, &l);
5108 [ # # ]: 0 : if (r < 0)
5109 : 0 : return r;
5110 : :
5111 [ # # ]: 0 : assert(l >= 2);
5112 : 0 : {
5113 : 0 : char sig[l + 1], *s = sig;
5114 : 0 : strncpy(sig, *signature + 1, l);
5115 : 0 : sig[l] = '\0';
5116 : :
5117 : 0 : r = message_skip_fields(m, ri, (uint32_t) -1, (const char**) &s);
5118 [ # # ]: 0 : if (r < 0)
5119 : 0 : return r;
5120 : : }
5121 : :
5122 : 0 : *signature += l;
5123 : : } else
5124 : 0 : return -EBADMSG;
5125 : : }
5126 : : }
5127 : :
5128 : 534 : int bus_message_parse_fields(sd_bus_message *m) {
5129 : : size_t ri;
5130 : : int r;
5131 : 534 : uint32_t unix_fds = 0;
5132 : 534 : bool unix_fds_set = false;
5133 : 534 : void *offsets = NULL;
5134 : 534 : unsigned n_offsets = 0;
5135 : 534 : size_t sz = 0;
5136 : 534 : unsigned i = 0;
5137 : :
5138 [ - + ]: 534 : assert(m);
5139 : :
5140 [ + + ]: 534 : if (BUS_MESSAGE_IS_GVARIANT(m)) {
5141 : : char *p;
5142 : :
5143 : : /* Read the signature from the end of the body variant first */
5144 : 4 : sz = bus_gvariant_determine_word_size(BUS_MESSAGE_SIZE(m), 0);
5145 [ - + ]: 4 : if (m->footer_accessible < 1 + sz)
5146 : 0 : return -EBADMSG;
5147 : :
5148 : 4 : p = (char*) m->footer + m->footer_accessible - (1 + sz);
5149 : : for (;;) {
5150 [ - + ]: 36 : if (p < (char*) m->footer)
5151 : 0 : return -EBADMSG;
5152 : :
5153 [ + + ]: 36 : if (*p == 0) {
5154 [ - + ]: 4 : _cleanup_free_ char *k = NULL;
5155 : : size_t l;
5156 : :
5157 : : /* We found the beginning of the signature
5158 : : * string, yay! We require the body to be a
5159 : : * structure, so verify it and then strip the
5160 : : * opening/closing brackets. */
5161 : :
5162 : 4 : l = (char*) m->footer + m->footer_accessible - p - (1 + sz);
5163 [ + - ]: 4 : if (l < 2 ||
5164 [ + - ]: 4 : p[1] != SD_BUS_TYPE_STRUCT_BEGIN ||
5165 [ - + ]: 4 : p[1 + l - 1] != SD_BUS_TYPE_STRUCT_END)
5166 : 0 : return -EBADMSG;
5167 : :
5168 : 4 : k = memdup_suffix0(p + 1 + 1, l - 2);
5169 [ - + ]: 4 : if (!k)
5170 : 0 : return -ENOMEM;
5171 : :
5172 [ - + ]: 4 : if (!signature_is_valid(k, true))
5173 : 0 : return -EBADMSG;
5174 : :
5175 : 4 : free_and_replace(m->root_container.signature, k);
5176 : 4 : break;
5177 : : }
5178 : :
5179 : 32 : p--;
5180 : : }
5181 : :
5182 : : /* Calculate the actual user body size, by removing
5183 : : * the trailing variant signature and struct offset
5184 : : * table */
5185 : 4 : m->user_body_size = m->body_size - ((char*) m->footer + m->footer_accessible - p);
5186 : :
5187 : : /* Pull out the offset table for the fields array */
5188 : 4 : sz = bus_gvariant_determine_word_size(m->fields_size, 0);
5189 [ + - ]: 4 : if (sz > 0) {
5190 : : size_t framing;
5191 : : void *q;
5192 : :
5193 : 4 : ri = m->fields_size - sz;
5194 : 4 : r = message_peek_fields(m, &ri, 1, sz, &q);
5195 [ - + ]: 4 : if (r < 0)
5196 : 0 : return r;
5197 : :
5198 : 4 : framing = bus_gvariant_read_word_le(q, sz);
5199 [ - + ]: 4 : if (framing >= m->fields_size - sz)
5200 : 0 : return -EBADMSG;
5201 [ - + ]: 4 : if ((m->fields_size - framing) % sz != 0)
5202 : 0 : return -EBADMSG;
5203 : :
5204 : 4 : ri = framing;
5205 : 4 : r = message_peek_fields(m, &ri, 1, m->fields_size - framing, &offsets);
5206 [ - + ]: 4 : if (r < 0)
5207 : 0 : return r;
5208 : :
5209 : 4 : n_offsets = (m->fields_size - framing) / sz;
5210 : : }
5211 : : } else
5212 : 530 : m->user_body_size = m->body_size;
5213 : :
5214 : 534 : ri = 0;
5215 [ + + ]: 2469 : while (ri < m->fields_size) {
5216 [ + + - ]: 1939 : _cleanup_free_ char *sig = NULL;
5217 : : const char *signature;
5218 : : uint64_t field_type;
5219 : 1939 : size_t item_size = (size_t) -1;
5220 : :
5221 [ + + ]: 1939 : if (BUS_MESSAGE_IS_GVARIANT(m)) {
5222 : : uint64_t *u64;
5223 : :
5224 [ + + ]: 20 : if (i >= n_offsets)
5225 : 4 : break;
5226 : :
5227 [ + + ]: 16 : if (i == 0)
5228 : 4 : ri = 0;
5229 : : else
5230 : 12 : ri = ALIGN_TO(bus_gvariant_read_word_le((uint8_t*) offsets + (i-1)*sz, sz), 8);
5231 : :
5232 : 16 : r = message_peek_fields(m, &ri, 8, 8, (void**) &u64);
5233 [ - + ]: 16 : if (r < 0)
5234 : 0 : return r;
5235 : :
5236 : 16 : field_type = BUS_MESSAGE_BSWAP64(m, *u64);
5237 : : } else {
5238 : : uint8_t *u8;
5239 : :
5240 : 1919 : r = message_peek_fields(m, &ri, 8, 1, (void**) &u8);
5241 [ - + ]: 1919 : if (r < 0)
5242 : 0 : return r;
5243 : :
5244 : 1919 : field_type = *u8;
5245 : : }
5246 : :
5247 [ + + ]: 1935 : if (BUS_MESSAGE_IS_GVARIANT(m)) {
5248 : : size_t where, end;
5249 : : char *b;
5250 : : void *q;
5251 : :
5252 : 16 : end = bus_gvariant_read_word_le((uint8_t*) offsets + i*sz, sz);
5253 : :
5254 [ - + ]: 16 : if (end < ri)
5255 : 0 : return -EBADMSG;
5256 : :
5257 : 16 : where = ri = ALIGN_TO(ri, 8);
5258 : 16 : item_size = end - ri;
5259 : 16 : r = message_peek_fields(m, &where, 1, item_size, &q);
5260 [ - + ]: 16 : if (r < 0)
5261 : 0 : return r;
5262 : :
5263 : 16 : b = memrchr(q, 0, item_size);
5264 [ - + ]: 16 : if (!b)
5265 : 0 : return -EBADMSG;
5266 : :
5267 : 16 : sig = memdup_suffix0(b+1, item_size - (b+1-(char*) q));
5268 [ - + ]: 16 : if (!sig)
5269 : 0 : return -ENOMEM;
5270 : :
5271 : 16 : signature = sig;
5272 : 16 : item_size = b - (char*) q;
5273 : : } else {
5274 : 1919 : r = message_peek_field_signature(m, &ri, 0, &signature);
5275 [ - + ]: 1919 : if (r < 0)
5276 : 0 : return r;
5277 : : }
5278 : :
5279 [ - + + + : 1935 : switch (field_type) {
+ + + + +
+ - ]
5280 : :
5281 : 0 : case _BUS_MESSAGE_HEADER_INVALID:
5282 : 0 : return -EBADMSG;
5283 : :
5284 : 251 : case BUS_MESSAGE_HEADER_PATH:
5285 : :
5286 [ - + ]: 251 : if (m->path)
5287 : 0 : return -EBADMSG;
5288 : :
5289 [ - + ]: 251 : if (!streq(signature, "o"))
5290 : 0 : return -EBADMSG;
5291 : :
5292 : 251 : r = message_peek_field_string(m, object_path_is_valid, &ri, item_size, &m->path);
5293 : 251 : break;
5294 : :
5295 : 251 : case BUS_MESSAGE_HEADER_INTERFACE:
5296 : :
5297 [ - + ]: 251 : if (m->interface)
5298 : 0 : return -EBADMSG;
5299 : :
5300 [ - + ]: 251 : if (!streq(signature, "s"))
5301 : 0 : return -EBADMSG;
5302 : :
5303 : 251 : r = message_peek_field_string(m, interface_name_is_valid, &ri, item_size, &m->interface);
5304 : 251 : break;
5305 : :
5306 : 251 : case BUS_MESSAGE_HEADER_MEMBER:
5307 : :
5308 [ - + ]: 251 : if (m->member)
5309 : 0 : return -EBADMSG;
5310 : :
5311 [ - + ]: 251 : if (!streq(signature, "s"))
5312 : 0 : return -EBADMSG;
5313 : :
5314 : 251 : r = message_peek_field_string(m, member_name_is_valid, &ri, item_size, &m->member);
5315 : 251 : break;
5316 : :
5317 : 16 : case BUS_MESSAGE_HEADER_ERROR_NAME:
5318 : :
5319 [ - + ]: 16 : if (m->error.name)
5320 : 0 : return -EBADMSG;
5321 : :
5322 [ - + ]: 16 : if (!streq(signature, "s"))
5323 : 0 : return -EBADMSG;
5324 : :
5325 : 16 : r = message_peek_field_string(m, error_name_is_valid, &ri, item_size, &m->error.name);
5326 [ + - ]: 16 : if (r >= 0)
5327 : 16 : m->error._need_free = -1;
5328 : :
5329 : 16 : break;
5330 : :
5331 : 354 : case BUS_MESSAGE_HEADER_DESTINATION:
5332 : :
5333 [ - + ]: 354 : if (m->destination)
5334 : 0 : return -EBADMSG;
5335 : :
5336 [ - + ]: 354 : if (!streq(signature, "s"))
5337 : 0 : return -EBADMSG;
5338 : :
5339 : 354 : r = message_peek_field_string(m, service_name_is_valid, &ri, item_size, &m->destination);
5340 : 354 : break;
5341 : :
5342 : 230 : case BUS_MESSAGE_HEADER_SENDER:
5343 : :
5344 [ - + ]: 230 : if (m->sender)
5345 : 0 : return -EBADMSG;
5346 : :
5347 [ - + ]: 230 : if (!streq(signature, "s"))
5348 : 0 : return -EBADMSG;
5349 : :
5350 : 230 : r = message_peek_field_string(m, service_name_is_valid, &ri, item_size, &m->sender);
5351 : :
5352 [ + - + + : 230 : if (r >= 0 && m->sender[0] == ':' && m->bus->bus_client) {
+ - ]
5353 : 48 : m->creds.unique_name = (char*) m->sender;
5354 : 48 : m->creds.mask |= SD_BUS_CREDS_UNIQUE_NAME & m->bus->creds_mask;
5355 : : }
5356 : :
5357 : 230 : break;
5358 : :
5359 : 295 : case BUS_MESSAGE_HEADER_SIGNATURE: {
5360 : : const char *s;
5361 : : char *c;
5362 : :
5363 [ - + ]: 295 : if (BUS_MESSAGE_IS_GVARIANT(m)) /* only applies to dbus1 */
5364 : 0 : return -EBADMSG;
5365 : :
5366 [ - + ]: 295 : if (m->root_container.signature)
5367 : 0 : return -EBADMSG;
5368 : :
5369 [ - + ]: 295 : if (!streq(signature, "g"))
5370 : 0 : return -EBADMSG;
5371 : :
5372 : 295 : r = message_peek_field_signature(m, &ri, item_size, &s);
5373 [ - + ]: 295 : if (r < 0)
5374 : 0 : return r;
5375 : :
5376 : 295 : c = strdup(s);
5377 [ - + ]: 295 : if (!c)
5378 : 0 : return -ENOMEM;
5379 : :
5380 : 295 : free_and_replace(m->root_container.signature, c);
5381 : 295 : break;
5382 : : }
5383 : :
5384 : 283 : case BUS_MESSAGE_HEADER_REPLY_SERIAL:
5385 : :
5386 [ - + ]: 283 : if (m->reply_cookie != 0)
5387 : 0 : return -EBADMSG;
5388 : :
5389 [ - + ]: 283 : if (BUS_MESSAGE_IS_GVARIANT(m)) {
5390 : : /* 64bit on dbus2 */
5391 : :
5392 [ # # ]: 0 : if (!streq(signature, "t"))
5393 : 0 : return -EBADMSG;
5394 : :
5395 : 0 : r = message_peek_field_uint64(m, &ri, item_size, &m->reply_cookie);
5396 [ # # ]: 0 : if (r < 0)
5397 : 0 : return r;
5398 : 0 : } else {
5399 : : /* 32bit on dbus1 */
5400 : : uint32_t serial;
5401 : :
5402 [ - + ]: 283 : if (!streq(signature, "u"))
5403 : 0 : return -EBADMSG;
5404 : :
5405 : 283 : r = message_peek_field_uint32(m, &ri, item_size, &serial);
5406 [ - + ]: 283 : if (r < 0)
5407 : 0 : return r;
5408 : :
5409 : 283 : m->reply_cookie = serial;
5410 : : }
5411 : :
5412 [ - + ]: 283 : if (m->reply_cookie == 0)
5413 : 0 : return -EBADMSG;
5414 : :
5415 : 283 : break;
5416 : :
5417 : 4 : case BUS_MESSAGE_HEADER_UNIX_FDS:
5418 [ - + ]: 4 : if (unix_fds_set)
5419 : 0 : return -EBADMSG;
5420 : :
5421 [ - + ]: 4 : if (!streq(signature, "u"))
5422 : 0 : return -EBADMSG;
5423 : :
5424 : 4 : r = message_peek_field_uint32(m, &ri, item_size, &unix_fds);
5425 [ - + ]: 4 : if (r < 0)
5426 : 0 : return -EBADMSG;
5427 : :
5428 : 4 : unix_fds_set = true;
5429 : 4 : break;
5430 : :
5431 : 0 : default:
5432 [ # # ]: 0 : if (!BUS_MESSAGE_IS_GVARIANT(m))
5433 : 0 : r = message_skip_fields(m, &ri, (uint32_t) -1, (const char **) &signature);
5434 : : }
5435 : :
5436 [ - + ]: 1935 : if (r < 0)
5437 : 0 : return r;
5438 : :
5439 : 1935 : i++;
5440 : : }
5441 : :
5442 [ - + ]: 534 : if (m->n_fds != unix_fds)
5443 : 0 : return -EBADMSG;
5444 : :
5445 [ + + + + : 534 : switch (m->header->type) {
- ]
5446 : :
5447 : 75 : case SD_BUS_MESSAGE_SIGNAL:
5448 [ + - + - : 75 : if (!m->path || !m->interface || !m->member)
- + ]
5449 : 0 : return -EBADMSG;
5450 : :
5451 [ - + ]: 75 : if (m->reply_cookie != 0)
5452 : 0 : return -EBADMSG;
5453 : :
5454 : 75 : break;
5455 : :
5456 : 176 : case SD_BUS_MESSAGE_METHOD_CALL:
5457 : :
5458 [ + - - + ]: 176 : if (!m->path || !m->member)
5459 : 0 : return -EBADMSG;
5460 : :
5461 [ - + ]: 176 : if (m->reply_cookie != 0)
5462 : 0 : return -EBADMSG;
5463 : :
5464 : 176 : break;
5465 : :
5466 : 267 : case SD_BUS_MESSAGE_METHOD_RETURN:
5467 : :
5468 [ - + ]: 267 : if (m->reply_cookie == 0)
5469 : 0 : return -EBADMSG;
5470 : 267 : break;
5471 : :
5472 : 16 : case SD_BUS_MESSAGE_METHOD_ERROR:
5473 : :
5474 [ + - - + ]: 16 : if (m->reply_cookie == 0 || !m->error.name)
5475 : 0 : return -EBADMSG;
5476 : 16 : break;
5477 : : }
5478 : :
5479 : : /* Refuse non-local messages that claim they are local */
5480 [ - + ]: 534 : if (streq_ptr(m->path, "/org/freedesktop/DBus/Local"))
5481 : 0 : return -EBADMSG;
5482 [ - + ]: 534 : if (streq_ptr(m->interface, "org.freedesktop.DBus.Local"))
5483 : 0 : return -EBADMSG;
5484 [ - + ]: 534 : if (streq_ptr(m->sender, "org.freedesktop.DBus.Local"))
5485 : 0 : return -EBADMSG;
5486 : :
5487 : 534 : m->root_container.end = m->user_body_size;
5488 : :
5489 [ + + ]: 534 : if (BUS_MESSAGE_IS_GVARIANT(m)) {
5490 : 8 : r = build_struct_offsets(
5491 : : m,
5492 : 4 : m->root_container.signature,
5493 : : m->user_body_size,
5494 : : &m->root_container.item_size,
5495 : : &m->root_container.offsets,
5496 : : &m->root_container.n_offsets);
5497 [ - + ]: 4 : if (r == -EINVAL)
5498 : 0 : return -EBADMSG;
5499 [ - + ]: 4 : if (r < 0)
5500 : 0 : return r;
5501 : : }
5502 : :
5503 : : /* Try to read the error message, but if we can't it's a non-issue */
5504 [ + + ]: 534 : if (m->header->type == SD_BUS_MESSAGE_METHOD_ERROR)
5505 : 16 : (void) sd_bus_message_read(m, "s", &m->error.message);
5506 : :
5507 : 534 : return 0;
5508 : : }
5509 : :
5510 : 0 : _public_ int sd_bus_message_set_destination(sd_bus_message *m, const char *destination) {
5511 [ # # # # ]: 0 : assert_return(m, -EINVAL);
5512 [ # # # # ]: 0 : assert_return(destination, -EINVAL);
5513 [ # # # # ]: 0 : assert_return(service_name_is_valid(destination), -EINVAL);
5514 [ # # # # ]: 0 : assert_return(!m->sealed, -EPERM);
5515 [ # # # # ]: 0 : assert_return(!m->destination, -EEXIST);
5516 : :
5517 : 0 : return message_append_field_string(m, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, destination, &m->destination);
5518 : : }
5519 : :
5520 : 0 : _public_ int sd_bus_message_set_sender(sd_bus_message *m, const char *sender) {
5521 [ # # # # ]: 0 : assert_return(m, -EINVAL);
5522 [ # # # # ]: 0 : assert_return(sender, -EINVAL);
5523 [ # # # # ]: 0 : assert_return(service_name_is_valid(sender), -EINVAL);
5524 [ # # # # ]: 0 : assert_return(!m->sealed, -EPERM);
5525 [ # # # # ]: 0 : assert_return(!m->sender, -EEXIST);
5526 : :
5527 : 0 : return message_append_field_string(m, BUS_MESSAGE_HEADER_SENDER, SD_BUS_TYPE_STRING, sender, &m->sender);
5528 : : }
5529 : :
5530 : 8 : int bus_message_get_blob(sd_bus_message *m, void **buffer, size_t *sz) {
5531 : : size_t total;
5532 : : void *p, *e;
5533 : : size_t i;
5534 : : struct bus_body_part *part;
5535 : :
5536 [ - + ]: 8 : assert(m);
5537 [ - + ]: 8 : assert(buffer);
5538 [ - + ]: 8 : assert(sz);
5539 : :
5540 : 8 : total = BUS_MESSAGE_SIZE(m);
5541 : :
5542 : 8 : p = malloc(total);
5543 [ - + ]: 8 : if (!p)
5544 : 0 : return -ENOMEM;
5545 : :
5546 : 8 : e = mempcpy(p, m->header, BUS_MESSAGE_BODY_BEGIN(m));
5547 [ + + ]: 16 : MESSAGE_FOREACH_PART(part, i, m)
5548 : 8 : e = mempcpy(e, part->data, part->size);
5549 : :
5550 [ - + ]: 8 : assert(total == (size_t) ((uint8_t*) e - (uint8_t*) p));
5551 : :
5552 : 8 : *buffer = p;
5553 : 8 : *sz = total;
5554 : :
5555 : 8 : return 0;
5556 : : }
5557 : :
5558 : 8 : int bus_message_read_strv_extend(sd_bus_message *m, char ***l) {
5559 : : const char *s;
5560 : : int r;
5561 : :
5562 [ - + ]: 8 : assert(m);
5563 [ - + ]: 8 : assert(l);
5564 : :
5565 : 8 : r = sd_bus_message_enter_container(m, 'a', "s");
5566 [ - + ]: 8 : if (r <= 0)
5567 : 0 : return r;
5568 : :
5569 [ + + ]: 32 : while ((r = sd_bus_message_read_basic(m, 's', &s)) > 0) {
5570 : 24 : r = strv_extend(l, s);
5571 [ - + ]: 24 : if (r < 0)
5572 : 0 : return r;
5573 : : }
5574 [ - + ]: 8 : if (r < 0)
5575 : 0 : return r;
5576 : :
5577 : 8 : r = sd_bus_message_exit_container(m);
5578 [ - + ]: 8 : if (r < 0)
5579 : 0 : return r;
5580 : :
5581 : 8 : return 1;
5582 : : }
5583 : :
5584 : 8 : _public_ int sd_bus_message_read_strv(sd_bus_message *m, char ***l) {
5585 : 8 : _cleanup_strv_free_ char **strv = NULL;
5586 : : int r;
5587 : :
5588 [ - + - + ]: 8 : assert_return(m, -EINVAL);
5589 [ - + - + ]: 8 : assert_return(m->sealed, -EPERM);
5590 [ - + - + ]: 8 : assert_return(l, -EINVAL);
5591 : :
5592 : 8 : r = bus_message_read_strv_extend(m, &strv);
5593 [ - + ]: 8 : if (r <= 0)
5594 : 0 : return r;
5595 : :
5596 : 8 : *l = TAKE_PTR(strv);
5597 : 8 : return 1;
5598 : : }
5599 : :
5600 : 44 : static int bus_message_get_arg_skip(
5601 : : sd_bus_message *m,
5602 : : unsigned i,
5603 : : char *_type,
5604 : : const char **_contents) {
5605 : :
5606 : : unsigned j;
5607 : : int r;
5608 : :
5609 : 44 : r = sd_bus_message_rewind(m, true);
5610 [ - + ]: 44 : if (r < 0)
5611 : 0 : return r;
5612 : :
5613 : 148 : for (j = 0;; j++) {
5614 : : const char *contents;
5615 : : char type;
5616 : :
5617 : 148 : r = sd_bus_message_peek_type(m, &type, &contents);
5618 [ - + ]: 148 : if (r < 0)
5619 : 44 : return r;
5620 [ - + ]: 148 : if (r == 0)
5621 : 0 : return -ENXIO;
5622 : :
5623 : : /* Don't match against arguments after the first one we don't understand */
5624 [ + + + + ]: 148 : if (!IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH, SD_BUS_TYPE_SIGNATURE) &&
5625 [ + - - + ]: 16 : !(type == SD_BUS_TYPE_ARRAY && STR_IN_SET(contents, "s", "o", "g")))
5626 : 0 : return -ENXIO;
5627 : :
5628 [ + + ]: 148 : if (j >= i) {
5629 [ + + ]: 44 : if (_contents)
5630 : 8 : *_contents = contents;
5631 [ + - ]: 44 : if (_type)
5632 : 44 : *_type = type;
5633 : 44 : return 0;
5634 : : }
5635 : :
5636 : 104 : r = sd_bus_message_skip(m, NULL);
5637 [ - + ]: 104 : if (r < 0)
5638 : 0 : return r;
5639 : : }
5640 : :
5641 : : }
5642 : :
5643 : 36 : int bus_message_get_arg(sd_bus_message *m, unsigned i, const char **str) {
5644 : : char type;
5645 : : int r;
5646 : :
5647 [ - + ]: 36 : assert(m);
5648 [ - + ]: 36 : assert(str);
5649 : :
5650 : 36 : r = bus_message_get_arg_skip(m, i, &type, NULL);
5651 [ - + ]: 36 : if (r < 0)
5652 : 0 : return r;
5653 : :
5654 [ + + + + ]: 36 : if (!IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH, SD_BUS_TYPE_SIGNATURE))
5655 : 8 : return -ENXIO;
5656 : :
5657 : 28 : return sd_bus_message_read_basic(m, type, str);
5658 : : }
5659 : :
5660 : 8 : int bus_message_get_arg_strv(sd_bus_message *m, unsigned i, char ***strv) {
5661 : : const char *contents;
5662 : : char type;
5663 : : int r;
5664 : :
5665 [ - + ]: 8 : assert(m);
5666 [ - + ]: 8 : assert(strv);
5667 : :
5668 : 8 : r = bus_message_get_arg_skip(m, i, &type, &contents);
5669 [ - + ]: 8 : if (r < 0)
5670 : 0 : return r;
5671 : :
5672 [ - + ]: 8 : if (type != SD_BUS_TYPE_ARRAY)
5673 : 0 : return -ENXIO;
5674 [ - + ]: 8 : if (!STR_IN_SET(contents, "s", "o", "g"))
5675 : 0 : return -ENXIO;
5676 : :
5677 : 8 : return sd_bus_message_read_strv(m, strv);
5678 : : }
5679 : :
5680 : 100 : _public_ int sd_bus_message_get_errno(sd_bus_message *m) {
5681 [ - + - + ]: 100 : assert_return(m, EINVAL);
5682 : :
5683 [ + + ]: 100 : if (m->header->type != SD_BUS_MESSAGE_METHOD_ERROR)
5684 : 96 : return 0;
5685 : :
5686 : 4 : return sd_bus_error_get_errno(&m->error);
5687 : : }
5688 : :
5689 : 80 : _public_ const char* sd_bus_message_get_signature(sd_bus_message *m, int complete) {
5690 : : struct bus_container *c;
5691 : :
5692 [ - + - + ]: 80 : assert_return(m, NULL);
5693 : :
5694 [ + - ]: 80 : c = complete ? &m->root_container : message_get_last_container(m);
5695 : 80 : return strempty(c->signature);
5696 : : }
5697 : :
5698 : 0 : _public_ int sd_bus_message_is_empty(sd_bus_message *m) {
5699 [ # # # # ]: 0 : assert_return(m, -EINVAL);
5700 : :
5701 : 0 : return isempty(m->root_container.signature);
5702 : : }
5703 : :
5704 : 0 : _public_ int sd_bus_message_has_signature(sd_bus_message *m, const char *signature) {
5705 [ # # # # ]: 0 : assert_return(m, -EINVAL);
5706 : :
5707 : 0 : return streq(strempty(m->root_container.signature), strempty(signature));
5708 : : }
5709 : :
5710 : 76 : _public_ int sd_bus_message_copy(sd_bus_message *m, sd_bus_message *source, int all) {
5711 : 76 : bool done_something = false;
5712 : : int r;
5713 : :
5714 [ - + - + ]: 76 : assert_return(m, -EINVAL);
5715 [ - + - + ]: 76 : assert_return(source, -EINVAL);
5716 [ - + - + ]: 76 : assert_return(!m->sealed, -EPERM);
5717 [ - + - + ]: 76 : assert_return(source->sealed, -EPERM);
5718 : :
5719 : : do {
5720 : : const char *contents;
5721 : : char type;
5722 : : union {
5723 : : uint8_t u8;
5724 : : uint16_t u16;
5725 : : int16_t s16;
5726 : : uint32_t u32;
5727 : : int32_t s32;
5728 : : uint64_t u64;
5729 : : int64_t s64;
5730 : : double d64;
5731 : : const char *string;
5732 : : int i;
5733 : : } basic;
5734 : :
5735 : 316 : r = sd_bus_message_peek_type(source, &type, &contents);
5736 [ - + ]: 316 : if (r < 0)
5737 : 0 : return r;
5738 [ + + ]: 316 : if (r == 0)
5739 : 76 : break;
5740 : :
5741 : 240 : done_something = true;
5742 : :
5743 [ + + ]: 240 : if (bus_type_is_container(type) > 0) {
5744 : :
5745 : 72 : r = sd_bus_message_enter_container(source, type, contents);
5746 [ - + ]: 72 : if (r < 0)
5747 : 0 : return r;
5748 : :
5749 : 72 : r = sd_bus_message_open_container(m, type, contents);
5750 [ - + ]: 72 : if (r < 0)
5751 : 0 : return r;
5752 : :
5753 : 72 : r = sd_bus_message_copy(m, source, true);
5754 [ - + ]: 72 : if (r < 0)
5755 : 0 : return r;
5756 : :
5757 : 72 : r = sd_bus_message_close_container(m);
5758 [ - + ]: 72 : if (r < 0)
5759 : 0 : return r;
5760 : :
5761 : 72 : r = sd_bus_message_exit_container(source);
5762 [ - + ]: 72 : if (r < 0)
5763 : 0 : return r;
5764 : :
5765 : 72 : continue;
5766 : : }
5767 : :
5768 : 168 : r = sd_bus_message_read_basic(source, type, &basic);
5769 [ - + ]: 168 : if (r < 0)
5770 : 0 : return r;
5771 : :
5772 [ - + ]: 168 : assert(r > 0);
5773 : :
5774 [ + + + + ]: 168 : if (IN_SET(type, SD_BUS_TYPE_OBJECT_PATH, SD_BUS_TYPE_SIGNATURE, SD_BUS_TYPE_STRING))
5775 : 100 : r = sd_bus_message_append_basic(m, type, basic.string);
5776 : : else
5777 : 68 : r = sd_bus_message_append_basic(m, type, &basic);
5778 : :
5779 [ - + ]: 168 : if (r < 0)
5780 : 0 : return r;
5781 : :
5782 [ + - ]: 240 : } while (all);
5783 : :
5784 : 76 : return done_something;
5785 : : }
5786 : :
5787 : 20 : _public_ int sd_bus_message_verify_type(sd_bus_message *m, char type, const char *contents) {
5788 : : const char *c;
5789 : : char t;
5790 : : int r;
5791 : :
5792 [ - + - + ]: 20 : assert_return(m, -EINVAL);
5793 [ - + - + ]: 20 : assert_return(m->sealed, -EPERM);
5794 [ + - - + : 20 : assert_return(!type || bus_type_is_valid(type), -EINVAL);
- + ]
5795 [ + + - + : 20 : assert_return(!contents || signature_is_valid(contents, true), -EINVAL);
- + ]
5796 [ - + # # : 20 : assert_return(type || contents, -EINVAL);
- + ]
5797 [ + + - + : 20 : assert_return(!contents || !type || bus_type_is_container(type), -EINVAL);
+ + - + -
+ ]
5798 : :
5799 : 20 : r = sd_bus_message_peek_type(m, &t, &c);
5800 [ - + ]: 20 : if (r <= 0)
5801 : 0 : return r;
5802 : :
5803 [ + - - + ]: 20 : if (type != 0 && type != t)
5804 : 0 : return 0;
5805 : :
5806 [ + + - + ]: 20 : if (contents && !streq_ptr(contents, c))
5807 : 0 : return 0;
5808 : :
5809 : 20 : return 1;
5810 : : }
5811 : :
5812 : 40 : _public_ sd_bus *sd_bus_message_get_bus(sd_bus_message *m) {
5813 [ - + - + ]: 40 : assert_return(m, NULL);
5814 : :
5815 : 40 : return m->bus;
5816 : : }
5817 : :
5818 : 0 : int bus_message_remarshal(sd_bus *bus, sd_bus_message **m) {
5819 : 0 : _cleanup_(sd_bus_message_unrefp) sd_bus_message *n = NULL;
5820 : : usec_t timeout;
5821 : : int r;
5822 : :
5823 [ # # ]: 0 : assert(bus);
5824 [ # # ]: 0 : assert(m);
5825 [ # # ]: 0 : assert(*m);
5826 : :
5827 [ # # # # ]: 0 : switch ((*m)->header->type) {
5828 : :
5829 : 0 : case SD_BUS_MESSAGE_SIGNAL:
5830 : 0 : r = sd_bus_message_new_signal(bus, &n, (*m)->path, (*m)->interface, (*m)->member);
5831 [ # # ]: 0 : if (r < 0)
5832 : 0 : return r;
5833 : :
5834 : 0 : break;
5835 : :
5836 : 0 : case SD_BUS_MESSAGE_METHOD_CALL:
5837 : 0 : r = sd_bus_message_new_method_call(bus, &n, (*m)->destination, (*m)->path, (*m)->interface, (*m)->member);
5838 [ # # ]: 0 : if (r < 0)
5839 : 0 : return r;
5840 : :
5841 : 0 : break;
5842 : :
5843 : 0 : case SD_BUS_MESSAGE_METHOD_RETURN:
5844 : : case SD_BUS_MESSAGE_METHOD_ERROR:
5845 : :
5846 : 0 : r = sd_bus_message_new(bus, &n, (*m)->header->type);
5847 [ # # ]: 0 : if (r < 0)
5848 : 0 : return -ENOMEM;
5849 : :
5850 [ # # ]: 0 : assert(n);
5851 : :
5852 : 0 : n->reply_cookie = (*m)->reply_cookie;
5853 : :
5854 : 0 : r = message_append_reply_cookie(n, n->reply_cookie);
5855 [ # # ]: 0 : if (r < 0)
5856 : 0 : return r;
5857 : :
5858 [ # # # # ]: 0 : if ((*m)->header->type == SD_BUS_MESSAGE_METHOD_ERROR && (*m)->error.name) {
5859 : 0 : r = message_append_field_string(n, BUS_MESSAGE_HEADER_ERROR_NAME, SD_BUS_TYPE_STRING, (*m)->error.name, &n->error.message);
5860 [ # # ]: 0 : if (r < 0)
5861 : 0 : return r;
5862 : :
5863 : 0 : n->error._need_free = -1;
5864 : : }
5865 : :
5866 : 0 : break;
5867 : :
5868 : 0 : default:
5869 : 0 : return -EINVAL;
5870 : : }
5871 : :
5872 [ # # # # ]: 0 : if ((*m)->destination && !n->destination) {
5873 : 0 : r = message_append_field_string(n, BUS_MESSAGE_HEADER_DESTINATION, SD_BUS_TYPE_STRING, (*m)->destination, &n->destination);
5874 [ # # ]: 0 : if (r < 0)
5875 : 0 : return r;
5876 : : }
5877 : :
5878 [ # # # # ]: 0 : if ((*m)->sender && !n->sender) {
5879 : 0 : r = message_append_field_string(n, BUS_MESSAGE_HEADER_SENDER, SD_BUS_TYPE_STRING, (*m)->sender, &n->sender);
5880 [ # # ]: 0 : if (r < 0)
5881 : 0 : return r;
5882 : : }
5883 : :
5884 : 0 : n->header->flags |= (*m)->header->flags & (BUS_MESSAGE_NO_REPLY_EXPECTED|BUS_MESSAGE_NO_AUTO_START);
5885 : :
5886 : 0 : r = sd_bus_message_copy(n, *m, true);
5887 [ # # ]: 0 : if (r < 0)
5888 : 0 : return r;
5889 : :
5890 : 0 : timeout = (*m)->timeout;
5891 [ # # # # ]: 0 : if (timeout == 0 && !((*m)->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED)) {
5892 : 0 : r = sd_bus_get_method_call_timeout(bus, &timeout);
5893 [ # # ]: 0 : if (r < 0)
5894 : 0 : return r;
5895 : : }
5896 : :
5897 : 0 : r = sd_bus_message_seal(n, BUS_MESSAGE_COOKIE(*m), timeout);
5898 [ # # ]: 0 : if (r < 0)
5899 : 0 : return r;
5900 : :
5901 : 0 : sd_bus_message_unref(*m);
5902 : 0 : *m = TAKE_PTR(n);
5903 : :
5904 : 0 : return 0;
5905 : : }
5906 : :
5907 : 0 : _public_ int sd_bus_message_get_priority(sd_bus_message *m, int64_t *priority) {
5908 [ # # # # ]: 0 : assert_return(m, -EINVAL);
5909 [ # # # # ]: 0 : assert_return(priority, -EINVAL);
5910 : :
5911 : 0 : *priority = m->priority;
5912 : 0 : return 0;
5913 : : }
5914 : :
5915 : 0 : _public_ int sd_bus_message_set_priority(sd_bus_message *m, int64_t priority) {
5916 [ # # # # ]: 0 : assert_return(m, -EINVAL);
5917 [ # # # # ]: 0 : assert_return(!m->sealed, -EPERM);
5918 : :
5919 : 0 : m->priority = priority;
5920 : 0 : return 0;
5921 : : }
|