Coverage Report

Created: 2024-09-08 06:36

/src/dbus-broker/src/dbus/message.c
Line
Count
Source (jump to first uncovered line)
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
2.98k
static int message_new(Message **messagep, bool big_endian, size_t n_extra) {
22
2.98k
        _c_cleanup_(message_unrefp) Message *message = NULL;
23
24
2.98k
        static_assert(alignof(message->extra) >= 8,
25
2.98k
                      "Message payload has insufficient alignment");
26
27
2.98k
        message = malloc(sizeof(*message) + c_align_to(n_extra, 8));
28
2.98k
        if (!message)
29
0
                return error_origin(-ENOMEM);
30
31
2.98k
        *message = (Message)MESSAGE_INIT(big_endian);
32
33
2.98k
        *messagep = message;
34
2.98k
        message = NULL;
35
2.98k
        return 0;
36
2.98k
}
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.01k
int message_new_incoming(Message **messagep, MessageHeader header) {
52
3.01k
        _c_cleanup_(message_unrefp) Message *message = NULL;
53
3.01k
        uint64_t n_header, n_body, n_data;
54
3.01k
        int r;
55
56
3.01k
        if (_c_likely_(header.endian == 'l')) {
57
2.05k
                n_header = sizeof(header) + (uint64_t)le32toh(header.n_fields);
58
2.05k
                n_body = (uint64_t)le32toh(header.n_body);
59
2.05k
        } else if (header.endian == 'B') {
60
937
                n_header = sizeof(header) + (uint64_t)be32toh(header.n_fields);
61
937
                n_body = (uint64_t)be32toh(header.n_body);
62
937
        } else {
63
21
                return MESSAGE_E_CORRUPT_HEADER;
64
21
        }
65
66
2.99k
        n_data = c_align_to(n_header, 8) + n_body;
67
2.99k
        if (n_data > MESSAGE_SIZE_MAX)
68
14
                return MESSAGE_E_TOO_LARGE;
69
70
2.98k
        r = message_new(&message, (header.endian == 'B'), n_data);
71
2.98k
        if (r)
72
0
                return error_trace(r);
73
74
2.98k
        message->n_data = n_data;
75
2.98k
        message->n_header = n_header;
76
2.98k
        message->n_body = n_body;
77
2.98k
        message->data = message->extra;
78
2.98k
        message->header = (void *)message->data;
79
2.98k
        message->body = message->data + c_align_to(n_header, 8);
80
2.98k
        message->vecs[0] = (struct iovec){ message->header, c_align_to(n_header, 8) };
81
2.98k
        message->vecs[1] = (struct iovec){ NULL, 0 };
82
2.98k
        message->vecs[2] = (struct iovec){ NULL, 0 };
83
2.98k
        message->vecs[3] = (struct iovec){ message->body, n_body };
84
85
2.98k
        message->n_copied += sizeof(header);
86
2.98k
        c_memcpy(message->data, &header, sizeof(header));
87
88
2.98k
        *messagep = message;
89
2.98k
        message = NULL;
90
2.98k
        return 0;
91
2.98k
}
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
2.98k
void message_free(_Atomic unsigned long *n_refs, void *userdata) {
144
2.98k
        Message *message = c_container_of(n_refs, Message, n_refs);
145
146
2.98k
        if (message->allocated_data)
147
0
                free(message->data);
148
2.98k
        fdlist_free(message->fds);
149
2.98k
        free(message);
150
2.98k
}
151
152
2.91k
static int message_parse_header(Message *message, MessageMetadata *metadata) {
153
2.91k
        static const CDVarType type[] = {
154
2.91k
                C_DVAR_T_INIT(
155
2.91k
                        C_DVAR_T_TUPLE7(
156
2.91k
                                C_DVAR_T_y,
157
2.91k
                                C_DVAR_T_y,
158
2.91k
                                C_DVAR_T_y,
159
2.91k
                                C_DVAR_T_y,
160
2.91k
                                C_DVAR_T_u,
161
2.91k
                                C_DVAR_T_u,
162
2.91k
                                C_DVAR_T_ARRAY(
163
2.91k
                                        C_DVAR_T_TUPLE2(
164
2.91k
                                                C_DVAR_T_y,
165
2.91k
                                                C_DVAR_T_v
166
2.91k
                                        )
167
2.91k
                                )
168
2.91k
                        )
169
2.91k
                ), /* (yyyyuua(yv)) */
170
2.91k
        };
171
2.91k
        _c_cleanup_(c_dvar_deinit) CDVar v = C_DVAR_INIT;
172
2.91k
        unsigned int mask;
173
2.91k
        uint8_t field;
174
2.91k
        int r;
175
176
2.91k
        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
2.91k
        c_dvar_read(&v, "(yyyyuu[",
192
2.91k
                    NULL,
193
2.91k
                    &metadata->header.type,
194
2.91k
                    &metadata->header.flags,
195
2.91k
                    &metadata->header.version,
196
2.91k
                    NULL,
197
2.91k
                    &metadata->header.serial);
198
199
2.91k
        if (metadata->header.type == DBUS_MESSAGE_TYPE_INVALID)
200
1
                return MESSAGE_E_INVALID_HEADER;
201
2.91k
        if (metadata->header.version != 1)
202
9
                return MESSAGE_E_INVALID_HEADER;
203
2.90k
        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
8.75k
        while (c_dvar_more(&v)) {
218
6.80k
                c_dvar_read(&v, "(y", &field);
219
220
6.80k
                if (field >= _DBUS_MESSAGE_FIELD_N) {
221
5.01k
                        c_dvar_skip(&v, "*)");
222
5.01k
                        continue;
223
5.01k
                }
224
225
1.79k
                if (metadata->fields.available & (1U << field))
226
2
                        return MESSAGE_E_INVALID_HEADER;
227
228
1.79k
                metadata->fields.available |= 1U << field;
229
230
1.79k
                switch (field) {
231
111
                case DBUS_MESSAGE_FIELD_INVALID:
232
111
                        return MESSAGE_E_INVALID_HEADER;
233
234
142
                case DBUS_MESSAGE_FIELD_PATH:
235
142
                        c_dvar_read(&v, "<o>)", c_dvar_type_o, &metadata->fields.path);
236
237
142
                        if (!strcmp(metadata->fields.path, "/org/freedesktop/DBus/Local"))
238
1
                                return MESSAGE_E_INVALID_HEADER;
239
240
141
                        break;
241
242
319
                case DBUS_MESSAGE_FIELD_INTERFACE:
243
319
                        c_dvar_read(&v, "<s>)", c_dvar_type_s, &metadata->fields.interface);
244
245
319
                        if (!strcmp(metadata->fields.interface, "org.freedesktop.DBus.Local"))
246
1
                                return MESSAGE_E_INVALID_HEADER;
247
248
318
                        if (!dbus_validate_interface(metadata->fields.interface, strlen(metadata->fields.interface)))
249
278
                                return MESSAGE_E_INVALID_HEADER;
250
251
40
                        break;
252
253
156
                case DBUS_MESSAGE_FIELD_MEMBER:
254
156
                        c_dvar_read(&v, "<s>)", c_dvar_type_s, &metadata->fields.member);
255
256
156
                        if (!dbus_validate_member(metadata->fields.member, strlen(metadata->fields.member)))
257
143
                                return MESSAGE_E_INVALID_HEADER;
258
259
13
                        break;
260
261
150
                case DBUS_MESSAGE_FIELD_ERROR_NAME:
262
150
                        c_dvar_read(&v, "<s>)", c_dvar_type_s, &metadata->fields.error_name);
263
264
150
                        if (!dbus_validate_error_name(metadata->fields.error_name, strlen(metadata->fields.error_name)))
265
146
                                return MESSAGE_E_INVALID_HEADER;
266
267
4
                        break;
268
269
53
                case DBUS_MESSAGE_FIELD_REPLY_SERIAL:
270
53
                        c_dvar_read(&v, "<u>)", c_dvar_type_u, &metadata->fields.reply_serial);
271
272
53
                        if (!metadata->fields.reply_serial)
273
8
                                return MESSAGE_E_INVALID_HEADER;
274
275
45
                        break;
276
277
152
                case DBUS_MESSAGE_FIELD_DESTINATION:
278
152
                        c_dvar_read(&v, "<s>)", c_dvar_type_s, &metadata->fields.destination);
279
280
152
                        if (!dbus_validate_name(metadata->fields.destination, strlen(metadata->fields.destination)))
281
143
                                return MESSAGE_E_INVALID_HEADER;
282
283
9
                        break;
284
285
95
                case DBUS_MESSAGE_FIELD_SENDER:
286
95
                        c_dvar_read(&v, "<s>)", c_dvar_type_s, &metadata->fields.sender);
287
288
95
                        if (!dbus_validate_name(metadata->fields.sender, strlen(metadata->fields.sender)))
289
85
                                return MESSAGE_E_INVALID_HEADER;
290
291
                        /* cache sender in case it needs to be stitched out */
292
10
                        message->original_sender = (void *)metadata->fields.sender;
293
10
                        break;
294
295
574
                case DBUS_MESSAGE_FIELD_SIGNATURE:
296
574
                        c_dvar_read(&v, "<g>)", c_dvar_type_g, &metadata->fields.signature);
297
574
                        break;
298
299
38
                case DBUS_MESSAGE_FIELD_UNIX_FDS:
300
38
                        c_dvar_read(&v, "<u>)", c_dvar_type_u, &metadata->fields.unix_fds);
301
302
38
                        if (metadata->fields.unix_fds > fdlist_count(message->fds))
303
32
                                return MESSAGE_E_MISSING_FDS;
304
305
6
                        break;
306
307
6
                default:
308
0
                        return error_origin(-ENOTRECOVERABLE);
309
1.79k
                }
310
1.79k
        }
311
312
        /*
313
         * Check mandatory fields. That is, depending on the message types, all
314
         * mandatory fields must be present.
315
         */
316
317
1.95k
        switch (metadata->header.type) {
318
61
        case DBUS_MESSAGE_TYPE_METHOD_CALL:
319
61
                mask = (1U << DBUS_MESSAGE_FIELD_PATH) |
320
61
                       (1U << DBUS_MESSAGE_FIELD_MEMBER);
321
61
                break;
322
34
        case DBUS_MESSAGE_TYPE_METHOD_RETURN:
323
34
                mask = (1U << DBUS_MESSAGE_FIELD_REPLY_SERIAL);
324
34
                break;
325
17
        case DBUS_MESSAGE_TYPE_ERROR:
326
17
                mask = (1U << DBUS_MESSAGE_FIELD_ERROR_NAME) |
327
17
                       (1U << DBUS_MESSAGE_FIELD_REPLY_SERIAL);
328
17
                break;
329
14
        case DBUS_MESSAGE_TYPE_SIGNAL:
330
14
                mask = (1U << DBUS_MESSAGE_FIELD_PATH) |
331
14
                       (1U << DBUS_MESSAGE_FIELD_INTERFACE) |
332
14
                       (1U << DBUS_MESSAGE_FIELD_MEMBER);
333
14
                break;
334
1.82k
        default:
335
1.82k
                mask = 0;
336
1.82k
                break;
337
1.95k
        }
338
339
1.95k
        if ((metadata->fields.available & mask) != mask)
340
126
                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.82k
        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.82k
        c_dvar_read(&v, "])");
355
356
1.26k
        r = c_dvar_end_read(&v);
357
1.26k
        if (r > 0)
358
923
                return MESSAGE_E_INVALID_HEADER;
359
339
        else if (r)
360
0
                return error_fold(r);
361
362
339
        return 0;
363
1.26k
}
364
365
865
static int message_parse_body(Message *message, MessageMetadata *metadata) {
366
865
        _c_cleanup_(c_dvar_deinit) CDVar v = C_DVAR_INIT;
367
865
        const char *signature = metadata->fields.signature;
368
865
        size_t i, n_signature, n_types;
369
865
        CDVarType *t, *types;
370
865
        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
865
        n_signature = strlen(signature);
378
865
        c_assert(n_signature < 256);
379
865
        types = alloca(n_signature * sizeof(CDVarType));
380
865
        n_types = 0;
381
382
5.81k
        for (i = 0; i < n_signature; i += types[i].length) {
383
4.94k
                t = types + i;
384
4.94k
                r = c_dvar_type_new_from_signature(&t, signature + i, n_signature - i);
385
4.94k
                if (r)
386
0
                        return r < 0 ? error_origin(r) : MESSAGE_E_INVALID_HEADER;
387
388
4.94k
                ++n_types;
389
4.94k
        }
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
865
        c_dvar_begin_read(&v, message->big_endian, types, n_types, message->body, message->n_body);
398
399
5.81k
        for (i = 0, t = types; i < n_types; ++i, t += t->length) {
400
4.94k
                switch (t->element) {
401
1.11k
                case 's':
402
1.78k
                case 'o':
403
1.78k
                        if (i < C_ARRAY_SIZE(metadata->args)) {
404
1.30k
                                metadata->args[i].element = t->element;
405
1.30k
                                c_dvar_read(&v, (char[2]){ t->element, 0 }, &metadata->args[i].value);
406
1.30k
                                metadata->n_args = i + 1;
407
1.30k
                                break;
408
1.30k
                        }
409
410
                        /* fallthrough */
411
3.64k
                default:
412
3.64k
                        c_dvar_skip(&v, "*");
413
3.64k
                        break;
414
4.94k
                }
415
4.94k
        }
416
417
865
        r = c_dvar_end_read(&v);
418
865
        if (r)
419
497
                return r < 0 ? error_origin(r) : MESSAGE_E_INVALID_BODY;
420
421
368
        return 0;
422
865
}
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
2.91k
int message_parse_metadata(Message *message) {
440
2.91k
        void *p;
441
2.91k
        int r;
442
443
2.91k
        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
2.91k
        r = message_parse_header(message, &message->metadata);
451
2.91k
        if (r)
452
2.01k
                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
999
        for (p = (void *)message->header + message->n_header; p < message->body; ++p)
460
134
                if (*(const uint8_t *)p)
461
39
                        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
865
        r = message_parse_body(message, &message->metadata);
469
865
        if (r)
470
497
                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
368
        if (message->fds)
481
0
                fdlist_truncate(message->fds, message->metadata.fields.unix_fds);
482
483
368
        message->parsed = true;
484
368
        return 0;
485
865
}
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
368
void message_stitch_sender(Message *message, uint64_t sender_id) {
509
368
        size_t n, n_stitch, n_field, n_sender;
510
368
        const char *sender;
511
368
        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
368
        c_assert(message->parsed);
519
368
        c_assert(!message->vecs[1].iov_base && !message->vecs[1].iov_len);
520
368
        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
368
        sender = address_to_string(&(Address)ADDRESS_INIT_ID(sender_id));
527
368
        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
368
        n_sender = strlen(sender);
552
368
        n_field = 1 + 3 + 4 + n_sender + 1;
553
368
        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
368
        {
560
368
                static_assert(1 + 3 + 4 + ADDRESS_ID_STRING_MAX + 1 <= sizeof(message->patch),
561
368
                              "Message patch buffer has insufficient size");
562
368
                static_assert(alignof(message->patch) >= 8,
563
368
                              "Message patch buffer has insufficient alignment");
564
368
                c_assert(n_stitch <= sizeof(message->patch));
565
368
                c_assert(n_sender <= ADDRESS_ID_STRING_MAX);
566
368
        }
567
568
368
        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
6
                n = strlen(message->original_sender);
579
6
                end = (void *)message->header + c_align_to(message->n_header, 8);
580
6
                field = message->original_sender - (1 + 3 + 4);
581
582
6
                c_assert(message->original_sender >= (void *)message->header);
583
6
                c_assert(message->original_sender + n + 1 <= end);
584
585
                /* fold remaining fields into following vector */
586
6
                message->vecs[1].iov_base = field + c_align_to(1 + 3 + 4 + n + 1, 8);
587
6
                message->vecs[1].iov_len = message->vecs[0].iov_len;
588
6
                message->vecs[1].iov_len -= message->vecs[1].iov_base - message->vecs[0].iov_base;
589
590
                /* cut field from previous vector */
591
6
                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
6
        }
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
368
        message->vecs[2].iov_base = message->patch;
611
368
        message->vecs[2].iov_len = n_stitch;
612
613
        /* fill in `(yv)' with sender and padding */
614
368
        message->patch[0] = DBUS_MESSAGE_FIELD_SENDER;
615
368
        message->patch[1] = 1;
616
368
        message->patch[2] = 's';
617
368
        message->patch[3] = 0;
618
368
        if (message->big_endian)
619
97
                c_memcpy(message->patch + 4, (uint32_t[1]){ htobe32(n_sender) }, sizeof(uint32_t));
620
271
        else
621
271
                c_memcpy(message->patch + 4, (uint32_t[1]){ htole32(n_sender) }, sizeof(uint32_t));
622
368
        c_memcpy(message->patch + 8, sender, n_sender + 1);
623
368
        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
368
        message->n_header = message->vecs[0].iov_len +
631
368
                            message->vecs[1].iov_len +
632
368
                            n_field;
633
368
        message->n_data = c_align_to(message->n_header, 8) + message->n_body;
634
635
368
        if (message->big_endian)
636
97
                message->header->n_fields = htobe32(message->n_header - sizeof(*message->header));
637
271
        else
638
271
                message->header->n_fields = htole32(message->n_header - sizeof(*message->header));
639
368
}
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
}