Coverage Report

Created: 2026-01-17 06:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dbus-broker/src/dbus/message.c
Line
Count
Source
1
/*
2
 * D-Bus Messages
3
 *
4
 * This encapsulates incoming and outgoing D-Bus messages. This is used to hold the
5
 * message data, the attached FDs and optional the cached metadata.
6
 */
7
8
#include <c-dvar.h>
9
#include <c-dvar-type.h>
10
#include <c-stdaux.h>
11
#include <endian.h>
12
#include <stdlib.h>
13
#include "dbus/message.h"
14
#include "dbus/protocol.h"
15
#include "util/error.h"
16
#include "util/fdlist.h"
17
#include "util/log.h"
18
19
static_assert(_DBUS_MESSAGE_FIELD_N <= 8 * sizeof(unsigned int), "Header fields exceed bitmap");
20
21
3.18k
static int message_new(Message **messagep, bool big_endian, size_t n_extra) {
22
3.18k
        _c_cleanup_(message_unrefp) Message *message = NULL;
23
24
3.18k
        static_assert(alignof(message->extra) >= 8,
25
3.18k
                      "Message payload has insufficient alignment");
26
27
3.18k
        message = malloc(sizeof(*message) + c_align_to(n_extra, 8));
28
3.18k
        if (!message)
29
0
                return error_origin(-ENOMEM);
30
31
3.18k
        *message = (Message)MESSAGE_INIT(big_endian);
32
33
3.18k
        *messagep = message;
34
3.18k
        message = NULL;
35
3.18k
        return 0;
36
3.18k
}
37
38
/**
39
 * message_new_incoming() - create new incoming message object
40
 * @messagep:           output pointer to new message object
41
 * @header:             header of new message
42
 *
43
 * This creates a new message object in @messagep, to hold an incoming message with
44
 * header @header. Only the header is initialized, the backing memory for the message
45
 * payload is allocated, but not yet initialized.
46
 *
47
 * Return: 0 on success, MESSAGE_E_CORRUPT_HEADER if unknown endianness,
48
 *         MESSAGE_E_TOO_LARGE if the declared message size violates the spec,
49
 *         or a negative error code on failure.
50
 */
51
3.21k
int message_new_incoming(Message **messagep, MessageHeader header) {
52
3.21k
        _c_cleanup_(message_unrefp) Message *message = NULL;
53
3.21k
        uint64_t n_header, n_body, n_data;
54
3.21k
        int r;
55
56
3.21k
        if (_c_likely_(header.endian == 'l')) {
57
2.44k
                n_header = sizeof(header) + (uint64_t)le32toh(header.n_fields);
58
2.44k
                n_body = (uint64_t)le32toh(header.n_body);
59
2.44k
        } else if (header.endian == 'B') {
60
754
                n_header = sizeof(header) + (uint64_t)be32toh(header.n_fields);
61
754
                n_body = (uint64_t)be32toh(header.n_body);
62
754
        } else {
63
20
                return MESSAGE_E_CORRUPT_HEADER;
64
20
        }
65
66
3.19k
        n_data = c_align_to(n_header, 8) + n_body;
67
3.19k
        if (n_data > MESSAGE_SIZE_MAX)
68
9
                return MESSAGE_E_TOO_LARGE;
69
70
3.18k
        r = message_new(&message, (header.endian == 'B'), n_data);
71
3.18k
        if (r)
72
0
                return error_trace(r);
73
74
3.18k
        message->n_data = n_data;
75
3.18k
        message->n_header = n_header;
76
3.18k
        message->n_body = n_body;
77
3.18k
        message->data = message->extra;
78
3.18k
        message->header = (void *)message->data;
79
3.18k
        message->body = message->data + c_align_to(n_header, 8);
80
3.18k
        message->vecs[0] = (struct iovec){ message->header, c_align_to(n_header, 8) };
81
3.18k
        message->vecs[1] = (struct iovec){ NULL, 0 };
82
3.18k
        message->vecs[2] = (struct iovec){ NULL, 0 };
83
3.18k
        message->vecs[3] = (struct iovec){ message->body, n_body };
84
85
3.18k
        message->n_copied += sizeof(header);
86
3.18k
        c_memcpy(message->data, &header, sizeof(header));
87
88
3.18k
        *messagep = message;
89
3.18k
        message = NULL;
90
3.18k
        return 0;
91
3.18k
}
92
93
/**
94
 * message_new_outgoing() - create a new outgoing message object
95
 * @messagep:           return pointer to new message object
96
 * @data:               the message contents
97
 * @n_data:             the size of the message contents
98
 *
99
 * The consumes the provided @data, which must be a valid D-Bus message and
100
 * creates an outgoing message representing it.
101
 *
102
 * Return: 0 on success, or a negative error code on failure.
103
 */
104
0
int message_new_outgoing(Message **messagep, void *data, size_t n_data) {
105
0
        _c_cleanup_(message_unrefp) Message *message = NULL;
106
0
        MessageHeader *header = data;
107
0
        uint64_t n_header, n_body;
108
0
        int r;
109
110
0
        c_assert(n_data >= sizeof(MessageHeader));
111
0
        c_assert(!((unsigned long)data & 0x7));
112
0
        c_assert((header->endian == 'B') == (__BYTE_ORDER == __BIG_ENDIAN) &&
113
0
               (header->endian == 'l') == (__BYTE_ORDER == __LITTLE_ENDIAN));
114
0
        c_assert(n_data >= sizeof(MessageHeader) + c_align_to(header->n_fields, 8));
115
116
0
        n_header = sizeof(MessageHeader) + header->n_fields;
117
0
        n_body = n_data - c_align_to(n_header, 8);
118
119
0
        header->n_body = n_data - sizeof(MessageHeader) - c_align_to(header->n_fields, 8);
120
121
0
        r = message_new(&message, (header->endian == 'B'), 0);
122
0
        if (r)
123
0
                return error_trace(r);
124
125
0
        message->allocated_data = true;
126
0
        message->n_data = n_data;
127
0
        message->n_header = n_header;
128
0
        message->n_body = n_body;
129
0
        message->data = data;
130
0
        message->header = (void *)message->data;
131
0
        message->body = message->data + c_align_to(n_header, 8);
132
0
        message->vecs[0] = (struct iovec){ message->header, c_align_to(n_header, 8) };
133
0
        message->vecs[1] = (struct iovec){ NULL, 0 };
134
0
        message->vecs[2] = (struct iovec){ NULL, 0 };
135
0
        message->vecs[3] = (struct iovec){ message->body, n_body };
136
137
0
        *messagep = message;
138
0
        message = NULL;
139
0
        return 0;
140
0
}
141
142
/* internal callback for message_unref() */
143
3.18k
void message_free(_Atomic unsigned long *n_refs, void *userdata) {
144
3.18k
        Message *message = c_container_of(n_refs, Message, n_refs);
145
146
3.18k
        if (message->allocated_data)
147
0
                free(message->data);
148
3.18k
        fdlist_free(message->fds);
149
3.18k
        free(message);
150
3.18k
}
151
152
3.11k
static int message_parse_header(Message *message, MessageMetadata *metadata) {
153
3.11k
        static const CDVarType type[] = {
154
3.11k
                C_DVAR_T_INIT(
155
3.11k
                        C_DVAR_T_TUPLE7(
156
3.11k
                                C_DVAR_T_y,
157
3.11k
                                C_DVAR_T_y,
158
3.11k
                                C_DVAR_T_y,
159
3.11k
                                C_DVAR_T_y,
160
3.11k
                                C_DVAR_T_u,
161
3.11k
                                C_DVAR_T_u,
162
3.11k
                                C_DVAR_T_ARRAY(
163
3.11k
                                        C_DVAR_T_TUPLE2(
164
3.11k
                                                C_DVAR_T_y,
165
3.11k
                                                C_DVAR_T_v
166
3.11k
                                        )
167
3.11k
                                )
168
3.11k
                        )
169
3.11k
                ), /* (yyyyuua(yv)) */
170
3.11k
        };
171
3.11k
        _c_cleanup_(c_dvar_deinit) CDVar v = C_DVAR_INIT;
172
3.11k
        unsigned int mask;
173
3.11k
        uint8_t field;
174
3.11k
        int r;
175
176
3.11k
        c_dvar_begin_read(&v, message->big_endian, type, 1, message->header, message->n_header);
177
178
        /*
179
         * Validate static header fields. Byte-order and body-length are part
180
         * of the stream-validation, and skipped here. The others are:
181
         *   type:
182
         *       Anything but "INVALID" is accepted.
183
         *   flags:
184
         *       Anything is accepted.
185
         *   version:
186
         *       Must be '1'.
187
         *   serial:
188
         *       Anything but 0 is accepted.
189
         */
190
191
3.11k
        c_dvar_read(&v, "(yyyyuu[",
192
3.11k
                    NULL,
193
3.11k
                    &metadata->header.type,
194
3.11k
                    &metadata->header.flags,
195
3.11k
                    &metadata->header.version,
196
3.11k
                    NULL,
197
3.11k
                    &metadata->header.serial);
198
199
3.11k
        if (metadata->header.type == DBUS_MESSAGE_TYPE_INVALID)
200
1
                return MESSAGE_E_INVALID_HEADER;
201
3.11k
        if (metadata->header.version != 1)
202
12
                return MESSAGE_E_INVALID_HEADER;
203
3.10k
        if (!metadata->header.serial)
204
2
                return MESSAGE_E_INVALID_HEADER;
205
206
        /*
207
         * Validate header fields one-by-one. We follow exactly what
208
         * dbus-daemon(1) does:
209
         *   - Unknown fields are ignored
210
         *   - Duplicates are rejected (except if they are unknown)
211
         *   - Types must match expected types
212
         *
213
         * Additionally, each header field has some restrictions on its own
214
         * validity.
215
         */
216
217
10.6k
        while (c_dvar_more(&v)) {
218
8.61k
                c_dvar_read(&v, "(y", &field);
219
220
8.61k
                if (field >= _DBUS_MESSAGE_FIELD_N) {
221
6.71k
                        c_dvar_skip(&v, "*)");
222
6.71k
                        continue;
223
6.71k
                }
224
225
1.89k
                if (metadata->fields.available & (1U << field))
226
2
                        return MESSAGE_E_INVALID_HEADER;
227
228
1.89k
                metadata->fields.available |= 1U << field;
229
230
1.89k
                switch (field) {
231
128
                case DBUS_MESSAGE_FIELD_INVALID:
232
128
                        return MESSAGE_E_INVALID_HEADER;
233
234
176
                case DBUS_MESSAGE_FIELD_PATH:
235
176
                        c_dvar_read(&v, "<o>)", c_dvar_type_o, &metadata->fields.path);
236
237
176
                        if (!strcmp(metadata->fields.path, "/org/freedesktop/DBus/Local"))
238
1
                                return MESSAGE_E_INVALID_HEADER;
239
240
175
                        break;
241
242
272
                case DBUS_MESSAGE_FIELD_INTERFACE:
243
272
                        c_dvar_read(&v, "<s>)", c_dvar_type_s, &metadata->fields.interface);
244
245
272
                        if (!strcmp(metadata->fields.interface, "org.freedesktop.DBus.Local"))
246
1
                                return MESSAGE_E_INVALID_HEADER;
247
248
271
                        if (!dbus_validate_interface(metadata->fields.interface, strlen(metadata->fields.interface)))
249
233
                                return MESSAGE_E_INVALID_HEADER;
250
251
38
                        break;
252
253
183
                case DBUS_MESSAGE_FIELD_MEMBER:
254
183
                        c_dvar_read(&v, "<s>)", c_dvar_type_s, &metadata->fields.member);
255
256
183
                        if (!dbus_validate_member(metadata->fields.member, strlen(metadata->fields.member)))
257
165
                                return MESSAGE_E_INVALID_HEADER;
258
259
18
                        break;
260
261
208
                case DBUS_MESSAGE_FIELD_ERROR_NAME:
262
208
                        c_dvar_read(&v, "<s>)", c_dvar_type_s, &metadata->fields.error_name);
263
264
208
                        if (!dbus_validate_error_name(metadata->fields.error_name, strlen(metadata->fields.error_name)))
265
204
                                return MESSAGE_E_INVALID_HEADER;
266
267
4
                        break;
268
269
69
                case DBUS_MESSAGE_FIELD_REPLY_SERIAL:
270
69
                        c_dvar_read(&v, "<u>)", c_dvar_type_u, &metadata->fields.reply_serial);
271
272
69
                        if (!metadata->fields.reply_serial)
273
16
                                return MESSAGE_E_INVALID_HEADER;
274
275
53
                        break;
276
277
200
                case DBUS_MESSAGE_FIELD_DESTINATION:
278
200
                        c_dvar_read(&v, "<s>)", c_dvar_type_s, &metadata->fields.destination);
279
280
200
                        if (!dbus_validate_name(metadata->fields.destination, strlen(metadata->fields.destination)))
281
193
                                return MESSAGE_E_INVALID_HEADER;
282
283
7
                        break;
284
285
111
                case DBUS_MESSAGE_FIELD_SENDER:
286
111
                        c_dvar_read(&v, "<s>)", c_dvar_type_s, &metadata->fields.sender);
287
288
111
                        if (!dbus_validate_name(metadata->fields.sender, strlen(metadata->fields.sender)))
289
102
                                return MESSAGE_E_INVALID_HEADER;
290
291
                        /* cache sender in case it needs to be stitched out */
292
9
                        message->original_sender = (void *)metadata->fields.sender;
293
9
                        break;
294
295
506
                case DBUS_MESSAGE_FIELD_SIGNATURE:
296
506
                        c_dvar_read(&v, "<g>)", c_dvar_type_g, &metadata->fields.signature);
297
506
                        break;
298
299
43
                case DBUS_MESSAGE_FIELD_UNIX_FDS:
300
43
                        c_dvar_read(&v, "<u>)", c_dvar_type_u, &metadata->fields.unix_fds);
301
302
43
                        if (metadata->fields.unix_fds > fdlist_count(message->fds))
303
31
                                return MESSAGE_E_MISSING_FDS;
304
305
12
                        break;
306
307
12
                default:
308
0
                        return error_origin(-ENOTRECOVERABLE);
309
1.89k
                }
310
1.89k
        }
311
312
        /*
313
         * Check mandatory fields. That is, depending on the message types, all
314
         * mandatory fields must be present.
315
         */
316
317
2.02k
        switch (metadata->header.type) {
318
107
        case DBUS_MESSAGE_TYPE_METHOD_CALL:
319
107
                mask = (1U << DBUS_MESSAGE_FIELD_PATH) |
320
107
                       (1U << DBUS_MESSAGE_FIELD_MEMBER);
321
107
                break;
322
29
        case DBUS_MESSAGE_TYPE_METHOD_RETURN:
323
29
                mask = (1U << DBUS_MESSAGE_FIELD_REPLY_SERIAL);
324
29
                break;
325
20
        case DBUS_MESSAGE_TYPE_ERROR:
326
20
                mask = (1U << DBUS_MESSAGE_FIELD_ERROR_NAME) |
327
20
                       (1U << DBUS_MESSAGE_FIELD_REPLY_SERIAL);
328
20
                break;
329
30
        case DBUS_MESSAGE_TYPE_SIGNAL:
330
30
                mask = (1U << DBUS_MESSAGE_FIELD_PATH) |
331
30
                       (1U << DBUS_MESSAGE_FIELD_INTERFACE) |
332
30
                       (1U << DBUS_MESSAGE_FIELD_MEMBER);
333
30
                break;
334
1.84k
        default:
335
1.84k
                mask = 0;
336
1.84k
                break;
337
2.02k
        }
338
339
2.02k
        if ((metadata->fields.available & mask) != mask)
340
185
                return MESSAGE_E_INVALID_HEADER;
341
342
        /*
343
         * Fix up the signature. The DBus spec states that missing signatures
344
         * should be treated as empty.
345
         */
346
347
1.84k
        metadata->fields.signature = metadata->fields.signature ?: "";
348
349
        /*
350
         * Finish the variant parser. If anything went wobbly in between, we
351
         * will be told here.
352
         */
353
354
1.84k
        c_dvar_read(&v, "])");
355
356
1.84k
        r = c_dvar_end_read(&v);
357
1.84k
        if (r > 0)
358
1.03k
                return MESSAGE_E_INVALID_HEADER;
359
810
        else if (r)
360
0
                return error_fold(r);
361
362
810
        return 0;
363
1.84k
}
364
365
768
static int message_parse_body(Message *message, MessageMetadata *metadata) {
366
768
        _c_cleanup_(c_dvar_deinit) CDVar v = C_DVAR_INIT;
367
768
        const char *signature = metadata->fields.signature;
368
768
        size_t i, n_signature, n_types;
369
768
        CDVarType *t, *types;
370
768
        int r;
371
372
        /*
373
         * Parse body-signature into CDVarType array. We use a single array
374
         * with all the argument-types concatenated.
375
         */
376
377
768
        n_signature = strlen(signature);
378
768
        c_assert(n_signature < 256);
379
768
        types = alloca(n_signature * sizeof(CDVarType));
380
768
        n_types = 0;
381
382
5.91k
        for (i = 0; i < n_signature; i += types[i].length) {
383
5.14k
                t = types + i;
384
5.14k
                r = c_dvar_type_new_from_signature(&t, signature + i, n_signature - i);
385
5.14k
                if (r)
386
0
                        return r < 0 ? error_origin(r) : MESSAGE_E_INVALID_HEADER;
387
388
5.14k
                ++n_types;
389
5.14k
        }
390
391
        /*
392
         * Now that we know the argument types, use c_dvar_skip() to verify
393
         * them. While at it, cache all the string/path arguments, so the match
394
         * rule processing can access them directly.
395
         */
396
397
768
        c_dvar_begin_read(&v, message->big_endian, types, n_types, message->body, message->n_body);
398
399
5.91k
        for (i = 0, t = types; i < n_types; ++i, t += t->length) {
400
5.14k
                switch (t->element) {
401
1.35k
                case 's':
402
1.84k
                case 'o':
403
1.84k
                        if (i < C_ARRAY_SIZE(metadata->args)) {
404
1.50k
                                metadata->args[i].element = t->element;
405
1.50k
                                c_dvar_read(&v, (char[2]){ t->element, 0 }, &metadata->args[i].value);
406
1.50k
                                metadata->n_args = i + 1;
407
1.50k
                                break;
408
1.50k
                        }
409
410
                        /* fallthrough */
411
3.64k
                default:
412
3.64k
                        c_dvar_skip(&v, "*");
413
3.64k
                        break;
414
5.14k
                }
415
5.14k
        }
416
417
768
        r = c_dvar_end_read(&v);
418
768
        if (r)
419
406
                return r < 0 ? error_origin(r) : MESSAGE_E_INVALID_BODY;
420
421
362
        return 0;
422
768
}
423
424
/**
425
 * message_parse_metadata() - parse message metadata
426
 * @message:            message to operate on
427
 *
428
 * This parses the message, verifies its complience to the spec, and caches its metadata. If
429
 * the message contains more FDs than expected, the excess ones are dropped, otherwise the
430
 * message object is not altered.
431
 *
432
 * This method is idempotent.
433
 *
434
 * Return: 0 on success,
435
 *         MESSAGE_E_MISSING_FDS if the message contains fewer FDs than declared in the metadata,
436
 *         MESSAGE_E_INVALID_HEADER if the header violates the spec in other ways,
437
 *         MESSAGE_E_INVALID_BODY if the body could not be parsed.
438
 */
439
3.11k
int message_parse_metadata(Message *message) {
440
3.11k
        void *p;
441
3.11k
        int r;
442
443
3.11k
        if (message->parsed)
444
0
                return 0;
445
446
        /*
447
         * As first step, parse the static header and the dynamic header
448
         * fields. Any error there is fatal.
449
         */
450
3.11k
        r = message_parse_header(message, &message->metadata);
451
3.11k
        if (r)
452
2.30k
                return error_trace(r);
453
454
        /*
455
         * Validate the padding between the header and body. Those must be 0!
456
         * We usually wouldn't care but must be compatible to dbus-daemon(1),
457
         * so lets verify them.
458
         */
459
912
        for (p = (void *)message->header + message->n_header; p < message->body; ++p)
460
144
                if (*(const uint8_t *)p)
461
42
                        return MESSAGE_E_INVALID_HEADER;
462
463
        /*
464
         * Now that the header is validated, we read through the message body.
465
         * Again, this is required for compatibility with dbus-daemon(1), but
466
         * also to fetch the arguments for match-filters used by broadcasts.
467
         */
468
768
        r = message_parse_body(message, &message->metadata);
469
768
        if (r)
470
406
                return error_trace(r);
471
472
        /*
473
         * dbus-daemon(1) only ever fetches the correct number of FDs from its
474
         * stream. This violates the D-Bus specification, which requires FDs to
475
         * be sent together with the message, and in a single hunk. Therefore,
476
         * we try to stick to dbus-daemon(1) behavior as close as possible, by
477
         * rejecting if the requested count exceeds the passed count. However,
478
         * we always discard any remaining FDs silently.
479
         */
480
362
        if (message->fds)
481
0
                fdlist_truncate(message->fds, message->metadata.fields.unix_fds);
482
483
362
        message->parsed = true;
484
362
        return 0;
485
768
}
486
487
/**
488
 * message_stitch_sender() - stitch in new sender field
489
 * @message:                    message to operate on
490
 * @sender_id:                  sender id to stitch in
491
 *
492
 * When the broker forwards messages, it needs to fill in the sender-field
493
 * reliably. Unfortunately, this requires modifying the fields-array of the
494
 * D-Bus header. Since we do not want to re-write the entire array, we allow
495
 * some stitching magic here to happen.
496
 *
497
 * This means, we use some nice properties of tuple-arrays in the D-Bus
498
 * marshalling (namely, they're 8-byte aligned, thus statically discoverable
499
 * when we know the offset), and simply cut out the existing sender field and
500
 * append a new one.
501
 *
502
 * This function must not be called more than once on any message (it will
503
 * throw a fatal error). Furthermore, this will cut the message in parts, such
504
 * that it is no longer readable linearly. However, none of the fields are
505
 * relocated nor overwritten. That is, any cached pointer stays valid, though
506
 * maybe no longer part of the actual message.
507
 */
508
362
void message_stitch_sender(Message *message, uint64_t sender_id) {
509
362
        size_t n, n_stitch, n_field, n_sender;
510
362
        const char *sender;
511
362
        void *end, *field;
512
513
        /*
514
         * Must not be called more than once. We reserve the 2 iovecs between
515
         * the original header and body to stitch the sender field. The caller
516
         * must have parsed the metadata before.
517
         */
518
362
        c_assert(message->parsed);
519
362
        c_assert(!message->vecs[1].iov_base && !message->vecs[1].iov_len);
520
362
        c_assert(!message->vecs[2].iov_base && !message->vecs[2].iov_len);
521
522
        /*
523
         * Convert the sender id to a unique name. This should never fail on
524
         * a valid sender id.
525
         */
526
362
        sender = address_to_string(&(Address)ADDRESS_INIT_ID(sender_id));
527
362
        message->metadata.sender_id = sender_id;
528
529
        /*
530
         * Calculate string, field, and buffer lengths. We need to possibly cut
531
         * out a `(yv)' and insert another one at the end. See the D-Bus
532
         * marshalling for details, but shortly this means:
533
         *
534
         *     - Tuples are always 8-byte aligned. Hence, we can reliably
535
         *       calculate field offsets.
536
         *
537
         *     - A string-field needs `1 + 3 + 4 + n + 1' bytes:
538
         *
539
         *         - length of 'y':                 1
540
         *         - length of 'v':                 3 + 4 + n + 1
541
         *           - type 'g' needs:
542
         *             - size field byte:           1
543
         *             - type string 's':           1
544
         *             - zero termination:          1
545
         *           - sender string needs:
546
         *             - alignment to 4:            0
547
         *             - size field int:            4
548
         *             - sender string:             n
549
         *             - zero termination:          1
550
         */
551
362
        n_sender = strlen(sender);
552
362
        n_field = 1 + 3 + 4 + n_sender + 1;
553
362
        n_stitch = c_align_to(n_field, 8);
554
555
        /*
556
         * The patch buffer is pre-allocated. Verify its size is sufficient to
557
         * hold the stitched sender.
558
         */
559
362
        {
560
362
                static_assert(1 + 3 + 4 + ADDRESS_ID_STRING_MAX + 1 <= sizeof(message->patch),
561
362
                              "Message patch buffer has insufficient size");
562
362
                static_assert(alignof(message->patch) >= 8,
563
362
                              "Message patch buffer has insufficient alignment");
564
362
                c_assert(n_stitch <= sizeof(message->patch));
565
362
                c_assert(n_sender <= ADDRESS_ID_STRING_MAX);
566
362
        }
567
568
362
        if (message->original_sender) {
569
                /*
570
                 * If @message already has a sender field, we need to remove it
571
                 * first, so we can append the correct sender. The message
572
                 * parser cached the start of a possible sender field as
573
                 * @message->original_sender (pointing to the start of the
574
                 * sender string!). Hence, calculate the offset to its
575
                 * surrounding field and cut it out.
576
                 * See above for size-calculations of `(yv)' fields.
577
                 */
578
5
                n = strlen(message->original_sender);
579
5
                end = (void *)message->header + c_align_to(message->n_header, 8);
580
5
                field = message->original_sender - (1 + 3 + 4);
581
582
5
                c_assert(message->original_sender >= (void *)message->header);
583
5
                c_assert(message->original_sender + n + 1 <= end);
584
585
                /* fold remaining fields into following vector */
586
5
                message->vecs[1].iov_base = field + c_align_to(1 + 3 + 4 + n + 1, 8);
587
5
                message->vecs[1].iov_len = message->vecs[0].iov_len;
588
5
                message->vecs[1].iov_len -= message->vecs[1].iov_base - message->vecs[0].iov_base;
589
590
                /* cut field from previous vector */
591
5
                message->vecs[0].iov_len = field - message->vecs[0].iov_base;
592
593
                /*
594
                 * @message->n_header as well as @message->header->n_fields are
595
                 * screwed here, but fixed up below.
596
                 *
597
                 * Note that we cannot fix them here, since we can only
598
                 * calculate them if we actually append data. Otherwise, we
599
                 * cannot know the length of the last field, and as such cannot
600
                 * subtract the trailing padding.
601
                 */
602
5
        }
603
604
        /*
605
         * Now that any possible sender field was cut out, we can append the
606
         * new sender field at the end. The 3rd iovec is reserved for that
607
         * purpose.
608
         */
609
610
362
        message->vecs[2].iov_base = message->patch;
611
362
        message->vecs[2].iov_len = n_stitch;
612
613
        /* fill in `(yv)' with sender and padding */
614
362
        message->patch[0] = DBUS_MESSAGE_FIELD_SENDER;
615
362
        message->patch[1] = 1;
616
362
        message->patch[2] = 's';
617
362
        message->patch[3] = 0;
618
362
        if (message->big_endian)
619
93
                c_memcpy(message->patch + 4, (uint32_t[1]){ htobe32(n_sender) }, sizeof(uint32_t));
620
269
        else
621
269
                c_memcpy(message->patch + 4, (uint32_t[1]){ htole32(n_sender) }, sizeof(uint32_t));
622
362
        c_memcpy(message->patch + 8, sender, n_sender + 1);
623
362
        c_memset(message->patch + 8 + n_sender + 1, 0, n_stitch - n_field);
624
625
        /*
626
         * After we cut the previous sender field and inserted the new, adjust
627
         * all the size-counters in the message again.
628
         */
629
630
362
        message->n_header = message->vecs[0].iov_len +
631
362
                            message->vecs[1].iov_len +
632
362
                            n_field;
633
362
        message->n_data = c_align_to(message->n_header, 8) + message->n_body;
634
635
362
        if (message->big_endian)
636
93
                message->header->n_fields = htobe32(message->n_header - sizeof(*message->header));
637
269
        else
638
269
                message->header->n_fields = htole32(message->n_header - sizeof(*message->header));
639
362
}
640
641
/**
642
 * message_log_append() - append message metadata to the log
643
 * @message:            message to operate on
644
 * @log:                log to append to
645
 *
646
 * This appends the metadata of @message to the next log message written
647
 * to @log.
648
 */
649
0
void message_log_append(Message *message, Log *log) {
650
0
        log_appendf(log,
651
0
                    "DBUS_BROKER_MESSAGE_DESTINATION=%s\n"
652
0
                    "DBUS_BROKER_MESSAGE_SERIAL=%"PRIu32"\n"
653
0
                    "DBUS_BROKER_MESSAGE_SIGNATURE=%s\n"
654
0
                    "DBUS_BROKER_MESSAGE_UNIX_FDS=%"PRIu32"\n",
655
0
                    message->metadata.fields.destination ?: "<broadcast>",
656
0
                    message->metadata.header.serial,
657
0
                    message->metadata.fields.signature ?: "<missing>",
658
0
                    message->metadata.fields.unix_fds);
659
660
0
        switch (message->metadata.header.type) {
661
0
        case DBUS_MESSAGE_TYPE_METHOD_CALL:
662
0
                log_appendf(log,
663
0
                            "DBUS_BROKER_MESSAGE_TYPE=method_call\n"
664
0
                            "DBUS_BROKER_MESSAGE_PATH=%s\n"
665
0
                            "DBUS_BROKER_MESSAGE_INTERFACE=%s\n"
666
0
                            "DBUS_BROKER_MESSAGE_MEMBER=%s\n",
667
0
                            message->metadata.fields.path ?: "<missing>",
668
0
                            message->metadata.fields.interface ?: "<missing>",
669
0
                            message->metadata.fields.member ?: "<missing>");
670
0
                break;
671
0
        case DBUS_MESSAGE_TYPE_SIGNAL:
672
0
                log_appendf(log,
673
0
                            "DBUS_BROKER_MESSAGE_TYPE=signal\n"
674
0
                            "DBUS_BROKER_MESSAGE_PATH=%s\n"
675
0
                            "DBUS_BROKER_MESSAGE_INTERFACE=%s\n"
676
0
                            "DBUS_BROKER_MESSAGE_MEMBER=%s\n",
677
0
                            message->metadata.fields.path ?: "<missing>",
678
0
                            message->metadata.fields.interface ?: "<missing>",
679
0
                            message->metadata.fields.member ?: "<missing>");
680
0
                break;
681
0
        case DBUS_MESSAGE_TYPE_METHOD_RETURN:
682
0
                log_appendf(log,
683
0
                            "DBUS_BROKER_MESSAGE_TYPE=method_return\n"
684
0
                            "MESSAGE_REPLY_SERIAL=%"PRIu32"\n",
685
0
                            message->metadata.fields.reply_serial);
686
0
                break;
687
0
        case DBUS_MESSAGE_TYPE_ERROR:
688
0
                log_appendf(log,
689
0
                            "DBUS_BROKER_MESSAGE_TYPE=method_return\n"
690
0
                            "DBUS_BROKER_MESSAGE_ERROR_NAME=%s\n"
691
0
                            "DBUS_BROKER_MESSAGE_REPLY_SERIAL=%"PRIu32"\n",
692
0
                            message->metadata.fields.error_name,
693
0
                            message->metadata.fields.reply_serial);
694
0
                break;
695
0
        default:
696
0
                log_appendf(log, "DBUS_BROKER_MESSAGE_TYPE=%u\n", message->metadata.header.type);
697
0
        }
698
0
}