/src/wireshark/epan/dissectors/packet-dbus.c
Line | Count | Source |
1 | | /* packet-dbus.c |
2 | | * Routines for D-Bus dissection |
3 | | * Copyright 2012, Jakub Zawadzki <darkjames-ws@darkjames.pl> |
4 | | * Copyright 2020, Simon Holesch <simon@holesch.de> |
5 | | * |
6 | | * Protocol specification available at http://dbus.freedesktop.org/doc/dbus-specification.html |
7 | | * |
8 | | * Wireshark - Network traffic analyzer |
9 | | * By Gerald Combs <gerald@wireshark.org> |
10 | | * Copyright 1998 Gerald Combs |
11 | | * |
12 | | * SPDX-License-Identifier: GPL-2.0-or-later |
13 | | */ |
14 | | |
15 | | #include "config.h" |
16 | | |
17 | | #include <epan/packet.h> |
18 | | #include <wiretap/wtap.h> |
19 | | #include <epan/expert.h> |
20 | | #include <epan/ptvcursor.h> |
21 | | #include <epan/tfs.h> |
22 | | #include <wsutil/ws_roundup.h> |
23 | | #include <epan/conversation.h> |
24 | | #include "packet-tcp.h" |
25 | | |
26 | 0 | #define DBUS_MAX_ARRAY_LEN (64 * 1024 * 1024) |
27 | 0 | #define DBUS_MAX_NAME_LENGTH 255 |
28 | 0 | #define DBUS_MAX_SIGNATURE_LENGTH 255 |
29 | 0 | #define DBUS_MAX_TYPE_NESTING_LEVEL 32 |
30 | 0 | #define DBUS_MAX_TOTAL_NESTING_LEVEL (2 * DBUS_MAX_TYPE_NESTING_LEVEL) |
31 | | |
32 | 0 | #define SIG_CODE_BYTE ('y') |
33 | 0 | #define SIG_CODE_BOOLEAN ('b') |
34 | 0 | #define SIG_CODE_INT16 ('n') |
35 | 0 | #define SIG_CODE_UINT16 ('q') |
36 | 0 | #define SIG_CODE_INT32 ('i') |
37 | 0 | #define SIG_CODE_UINT32 ('u') |
38 | 0 | #define SIG_CODE_INT64 ('x') |
39 | 0 | #define SIG_CODE_UINT64 ('t') |
40 | 0 | #define SIG_CODE_DOUBLE ('d') |
41 | 0 | #define SIG_CODE_STRING ('s') |
42 | 0 | #define SIG_CODE_OBJECT_PATH ('o') |
43 | 0 | #define SIG_CODE_SIGNATURE ('g') |
44 | 0 | #define SIG_CODE_ARRAY ('a') |
45 | 0 | #define SIG_CODE_STRUCT_OPEN ('(') |
46 | 0 | #define SIG_CODE_STRUCT_CLOSE (')') |
47 | 0 | #define SIG_CODE_VARIANT ('v') |
48 | 0 | #define SIG_CODE_DICT_ENTRY_OPEN ('{') |
49 | 0 | #define SIG_CODE_DICT_ENTRY_CLOSE ('}') |
50 | 0 | #define SIG_CODE_UNIX_FD ('h') |
51 | | |
52 | | void proto_register_dbus(void); |
53 | | void proto_reg_handoff_dbus(void); |
54 | | |
55 | | static int proto_dbus; |
56 | | static bool dbus_desegment = true; |
57 | | static bool dbus_resolve_names = true; |
58 | | |
59 | | static dissector_handle_t dbus_handle; |
60 | | static dissector_handle_t dbus_handle_tcp; |
61 | | |
62 | 0 | #define DBUS_MESSAGE_TYPE_INVALID 0 |
63 | 0 | #define DBUS_MESSAGE_TYPE_METHOD_CALL 1 |
64 | 0 | #define DBUS_MESSAGE_TYPE_METHOD_RETURN 2 |
65 | 0 | #define DBUS_MESSAGE_TYPE_ERROR 3 |
66 | 0 | #define DBUS_MESSAGE_TYPE_SIGNAL 4 |
67 | | |
68 | | static const value_string message_type_vals[] = { |
69 | | { DBUS_MESSAGE_TYPE_INVALID, "Invalid" }, |
70 | | { DBUS_MESSAGE_TYPE_METHOD_CALL, "Method call" }, |
71 | | { DBUS_MESSAGE_TYPE_METHOD_RETURN, "Method reply" }, |
72 | | { DBUS_MESSAGE_TYPE_ERROR, "Error reply" }, |
73 | | { DBUS_MESSAGE_TYPE_SIGNAL, "Signal emission" }, |
74 | | { 0, NULL } |
75 | | }; |
76 | | |
77 | 0 | #define DBUS_HEADER_FIELD_INVALID 0 |
78 | 0 | #define DBUS_HEADER_FIELD_PATH 1 |
79 | 0 | #define DBUS_HEADER_FIELD_INTERFACE 2 |
80 | 0 | #define DBUS_HEADER_FIELD_MEMBER 3 |
81 | 0 | #define DBUS_HEADER_FIELD_ERROR_NAME 4 |
82 | 0 | #define DBUS_HEADER_FIELD_REPLY_SERIAL 5 |
83 | 0 | #define DBUS_HEADER_FIELD_DESTINATION 6 |
84 | 0 | #define DBUS_HEADER_FIELD_SENDER 7 |
85 | 0 | #define DBUS_HEADER_FIELD_SIGNATURE 8 |
86 | 0 | #define DBUS_HEADER_FIELD_UNIX_FDS 9 |
87 | | |
88 | | static const value_string field_code_vals[] = { |
89 | | { DBUS_HEADER_FIELD_INVALID, "Invalid" }, |
90 | | { DBUS_HEADER_FIELD_PATH, "Path" }, |
91 | | { DBUS_HEADER_FIELD_INTERFACE, "Interface" }, |
92 | | { DBUS_HEADER_FIELD_MEMBER, "Member" }, |
93 | | { DBUS_HEADER_FIELD_ERROR_NAME, "Error name" }, |
94 | | { DBUS_HEADER_FIELD_REPLY_SERIAL, "Reply serial" }, |
95 | | { DBUS_HEADER_FIELD_DESTINATION, "Destination" }, |
96 | | { DBUS_HEADER_FIELD_SENDER, "sender" }, |
97 | | { DBUS_HEADER_FIELD_SIGNATURE, "Signature" }, |
98 | | { DBUS_HEADER_FIELD_UNIX_FDS, "Unix FDs" }, |
99 | | { 0, NULL } |
100 | | }; |
101 | | |
102 | | static const value_string endianness_vals[] = { |
103 | | { 'l', "little-endian" }, |
104 | | { 'B', "big-endian" }, |
105 | | { 0, NULL } |
106 | | }; |
107 | | |
108 | 15 | #define DBUS_FLAGS_NO_REPLY_EXPECTED_MASK 0x01 |
109 | 15 | #define DBUS_FLAGS_NO_AUTO_START_MASK 0x02 |
110 | 15 | #define DBUS_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION_MASK 0x04 |
111 | | |
112 | | static const true_false_string allow_vals = { "Allow", "Don't allow" }; |
113 | | static const true_false_string no_start_vals = { "Don't start", "Start" }; |
114 | | static const true_false_string not_expected_vals = { "Not expected", "Expected" }; |
115 | | |
116 | | static int hf_dbus_endianness; |
117 | | static int hf_dbus_message_type; |
118 | | static int hf_dbus_flags; |
119 | | static int hf_dbus_flags_no_reply_expected; |
120 | | static int hf_dbus_flags_no_auto_start; |
121 | | static int hf_dbus_flags_allow_interactive_authorization; |
122 | | static int hf_dbus_version; |
123 | | static int hf_dbus_body_length; |
124 | | static int hf_dbus_serial; |
125 | | static int hf_dbus_field_code; |
126 | | static int hf_dbus_padding; |
127 | | static int hf_dbus_path; |
128 | | static int hf_dbus_interface; |
129 | | static int hf_dbus_member; |
130 | | static int hf_dbus_error_name; |
131 | | static int hf_dbus_reply_serial; |
132 | | static int hf_dbus_destination; |
133 | | static int hf_dbus_sender; |
134 | | static int hf_dbus_signature; |
135 | | static int hf_dbus_unix_fds; |
136 | | static int hf_dbus_body; |
137 | | static int hf_dbus_type_byte; |
138 | | static int hf_dbus_type_boolean; |
139 | | static int hf_dbus_type_int16; |
140 | | static int hf_dbus_type_uint16; |
141 | | static int hf_dbus_type_int32; |
142 | | static int hf_dbus_type_uint32; |
143 | | static int hf_dbus_type_int64; |
144 | | static int hf_dbus_type_uint64; |
145 | | static int hf_dbus_type_double; |
146 | | static int hf_dbus_type_string; |
147 | | static int hf_dbus_type_object_path; |
148 | | static int hf_dbus_type_signature; |
149 | | static int hf_dbus_type_array; |
150 | | static int hf_dbus_type_array_length; |
151 | | static int hf_dbus_type_struct; |
152 | | static int hf_dbus_type_variant; |
153 | | static int hf_dbus_type_variant_signature; |
154 | | static int hf_dbus_type_dict_entry; |
155 | | static int hf_dbus_type_dict_entry_key; |
156 | | static int hf_dbus_type_unix_fd; |
157 | | static int hf_dbus_response_in; |
158 | | static int hf_dbus_response_to; |
159 | | static int hf_dbus_response_time; |
160 | | |
161 | | static int ett_dbus; |
162 | | static int ett_dbus_flags; |
163 | | static int ett_dbus_header_field_array; |
164 | | static int ett_dbus_header_field; |
165 | | static int ett_dbus_body; |
166 | | static int ett_dbus_type_array; |
167 | | static int ett_dbus_type_struct; |
168 | | static int ett_dbus_type_variant; |
169 | | static int ett_dbus_type_dict_entry; |
170 | | |
171 | | static expert_field ei_dbus_endianness_invalid; |
172 | | static expert_field ei_dbus_message_type_invalid; |
173 | | static expert_field ei_dbus_message_type_unknown; |
174 | | static expert_field ei_dbus_version_invalid; |
175 | | static expert_field ei_dbus_serial_invalid; |
176 | | static expert_field ei_dbus_field_code_invalid; |
177 | | static expert_field ei_dbus_required_header_field_missing; |
178 | | static expert_field ei_dbus_padding_invalid; |
179 | | static expert_field ei_dbus_field_signature_wrong; |
180 | | static expert_field ei_dbus_interface_invalid; |
181 | | static expert_field ei_dbus_member_invalid; |
182 | | static expert_field ei_dbus_error_name_invalid; |
183 | | static expert_field ei_dbus_bus_name_invalid; |
184 | | static expert_field ei_dbus_type_boolean_invalid; |
185 | | static expert_field ei_dbus_string_invalid; |
186 | | static expert_field ei_dbus_type_signature_invalid; |
187 | | static expert_field ei_dbus_type_array_too_long; |
188 | | static expert_field ei_dbus_type_array_content_out_of_bounds; |
189 | | static expert_field ei_dbus_type_object_path_invalid; |
190 | | static expert_field ei_dbus_type_variant_signature_invalid; |
191 | | static expert_field ei_dbus_nested_too_deeply; |
192 | | |
193 | | typedef struct { |
194 | | ptvcursor_t *cursor; |
195 | | packet_info *pinfo; |
196 | | unsigned enc; |
197 | | uint32_t message_type; |
198 | | uint8_t flags; |
199 | | uint32_t body_len; |
200 | | uint32_t serial; |
201 | | |
202 | | proto_item *current_pi; |
203 | | const char *path; |
204 | | const char *interface; |
205 | | const char *member; |
206 | | const char *error_name; |
207 | | uint32_t reply_serial; |
208 | | const char *destination; |
209 | | const char *sender; |
210 | | const char *signature; |
211 | | uint32_t unix_fds; |
212 | | } dbus_packet_t; |
213 | | |
214 | | typedef struct _dbus_type_reader_t { |
215 | | dbus_packet_t *packet; |
216 | | const char *signature; |
217 | | uint32_t level; |
218 | | uint32_t array_level; |
219 | | uint32_t struct_level; |
220 | | uint32_t dict_entry_level; |
221 | | const char *array_type_start; |
222 | | int array_end_offset; |
223 | | bool is_in_variant; |
224 | | bool is_basic_variant; |
225 | | bool is_in_dict_entry; |
226 | | bool is_basic_dict_entry; |
227 | | proto_item *container; |
228 | | struct _dbus_type_reader_t *parent; |
229 | | } dbus_type_reader_t; |
230 | | |
231 | | typedef union { |
232 | | bool bool_; |
233 | | uint32_t uint; |
234 | | int32_t int_; |
235 | | uint64_t uint64; |
236 | | int64_t int64; |
237 | | double double_; |
238 | | const char *string; |
239 | | } dbus_val_t; |
240 | | |
241 | | typedef struct { |
242 | | uint32_t req_frame; |
243 | | uint32_t rep_frame; |
244 | | nstime_t req_time; |
245 | | const char *path; |
246 | | const char *interface; |
247 | | const char *member; |
248 | | } dbus_transaction_t; |
249 | | |
250 | | typedef struct { |
251 | | wmem_map_t *packets; |
252 | | } dbus_conv_info_t; |
253 | | |
254 | | static wmem_map_t *request_info_map; |
255 | | static wmem_map_t *unique_name_map; |
256 | | |
257 | | static bool |
258 | 0 | is_ascii_digit(char c) { |
259 | 0 | return (unsigned)c - '0' < 10; |
260 | 0 | } |
261 | | |
262 | | static bool |
263 | 0 | is_ascii_alpha(char c) { |
264 | 0 | return ((unsigned)c | 0x20) - 'a' <= 'z' - 'a'; |
265 | 0 | } |
266 | | |
267 | | static bool |
268 | 0 | is_dbus_object_path_valid(const char *path) { |
269 | | // - The path may be of any length. |
270 | | // - The path must begin with an ASCII '/' (integer 47) character, and must consist of elements separated by |
271 | | // slash characters. |
272 | | // - Each element must only contain the ASCII characters "[A-Z][a-z][0-9]_" |
273 | | // - No element may be the empty string. |
274 | | // - Multiple '/' characters cannot occur in sequence. |
275 | | // - A trailing '/' character is not allowed unless the path is the root path (a single '/' character). |
276 | 0 | if (*path == '/' && *(path + 1) == '\0') { |
277 | 0 | return true; |
278 | 0 | } |
279 | | |
280 | 0 | while (*path == '/') { |
281 | 0 | path++; |
282 | |
|
283 | 0 | if (*path == '/') { |
284 | 0 | return false; |
285 | 0 | } |
286 | | |
287 | 0 | while (is_ascii_alpha(*path) || is_ascii_digit(*path) || *path == '_') { |
288 | 0 | path++; |
289 | 0 | } |
290 | |
|
291 | 0 | if (*path == '\0') { |
292 | 0 | return *(path - 1) != '/'; |
293 | 0 | } |
294 | 0 | } |
295 | | |
296 | 0 | return false; |
297 | 0 | } |
298 | | |
299 | | static bool |
300 | 0 | is_dbus_interface_valid(const char *interface) { |
301 | | // - Interface names are composed of 2 or more elements separated by a period ('.') character. All elements |
302 | | // must contain at least one character. |
303 | | // - Each element must only contain the ASCII characters "[A-Z][a-z][0-9]_" and must not begin with a digit. |
304 | | // - Interface names must not exceed the maximum name length. |
305 | 0 | int elements = 0; |
306 | 0 | const char *p = interface; |
307 | 0 | do { |
308 | 0 | if (!(is_ascii_alpha(*p) || *p == '_')) { |
309 | 0 | return false; |
310 | 0 | } |
311 | 0 | p++; |
312 | 0 | elements++; |
313 | |
|
314 | 0 | while (is_ascii_alpha(*p) || is_ascii_digit(*p) || *p == '_') { |
315 | 0 | p++; |
316 | 0 | } |
317 | |
|
318 | 0 | if (*p == '\0') { |
319 | 0 | size_t length = p - interface; |
320 | 0 | return elements >= 2 && length <= DBUS_MAX_NAME_LENGTH; |
321 | 0 | } |
322 | 0 | } while (*p++ == '.'); |
323 | | |
324 | 0 | return false; |
325 | 0 | } |
326 | | |
327 | | static bool |
328 | 0 | is_dbus_member_name_valid(const char *member_name) { |
329 | | // - Must only contain the ASCII characters "[A-Z][a-z][0-9]_" and may not begin with a digit. |
330 | | // - Must not contain the '.' (period) character. |
331 | | // - Must not exceed the maximum name length. |
332 | | // - Must be at least 1 byte in length. |
333 | 0 | const char *p = member_name; |
334 | |
|
335 | 0 | if (!(is_ascii_alpha(*p) || *p == '_')) { |
336 | 0 | return false; |
337 | 0 | } |
338 | | |
339 | 0 | do { |
340 | 0 | p++; |
341 | 0 | } while (is_ascii_alpha(*p) || is_ascii_digit(*p) || *p == '_'); |
342 | |
|
343 | 0 | if (*p == '\0') { |
344 | 0 | size_t length = p - member_name; |
345 | 0 | return length <= DBUS_MAX_NAME_LENGTH; |
346 | 0 | } |
347 | | |
348 | 0 | return false; |
349 | 0 | } |
350 | | |
351 | | static bool |
352 | 0 | is_dbus_bus_name_valid(const char *bus_name) { |
353 | | // - Bus names that start with a colon (':') character are unique connection names. Other bus names are called |
354 | | // well-known bus names. |
355 | | // - Bus names are composed of 1 or more elements separated by a period ('.') character. All elements must |
356 | | // contain at least one character. |
357 | | // - Each element must only contain the ASCII characters "[A-Z][a-z][0-9]_-", with "-" discouraged in new bus |
358 | | // names. Only elements that are part of a unique connection name may begin with a digit, elements in other |
359 | | // bus names must not begin with a digit. |
360 | | // - Bus names must contain at least one '.' (period) character (and thus at least two elements). |
361 | | // - Bus names must not begin with a '.' (period) character. |
362 | | // - Bus names must not exceed the maximum name length. |
363 | 0 | int elements = 0; |
364 | 0 | const char *p = bus_name; |
365 | 0 | bool is_unique_name = false; |
366 | |
|
367 | 0 | if (*p == ':') { |
368 | 0 | is_unique_name = true; |
369 | 0 | p++; |
370 | 0 | } |
371 | |
|
372 | 0 | do { |
373 | 0 | if (!(is_ascii_alpha(*p) || *p == '_' || *p == '-' || (is_unique_name && is_ascii_digit(*p)))) { |
374 | 0 | return false; |
375 | 0 | } |
376 | 0 | p++; |
377 | 0 | elements++; |
378 | |
|
379 | 0 | while (is_ascii_alpha(*p) || is_ascii_digit(*p) || *p == '_' || *p == '-') { |
380 | 0 | p++; |
381 | 0 | } |
382 | |
|
383 | 0 | if (*p == '\0') { |
384 | 0 | size_t length = p - bus_name; |
385 | 0 | return elements >= 2 && length <= DBUS_MAX_NAME_LENGTH; |
386 | 0 | } |
387 | 0 | } while (*p++ == '.'); |
388 | | |
389 | 0 | return false; |
390 | 0 | } |
391 | | |
392 | | static bool |
393 | 0 | is_basic_type(char sig_code) { |
394 | 0 | switch (sig_code) { |
395 | 0 | case SIG_CODE_BYTE: |
396 | 0 | case SIG_CODE_BOOLEAN: |
397 | 0 | case SIG_CODE_INT16: |
398 | 0 | case SIG_CODE_UINT16: |
399 | 0 | case SIG_CODE_INT32: |
400 | 0 | case SIG_CODE_UINT32: |
401 | 0 | case SIG_CODE_INT64: |
402 | 0 | case SIG_CODE_UINT64: |
403 | 0 | case SIG_CODE_DOUBLE: |
404 | 0 | case SIG_CODE_STRING: |
405 | 0 | case SIG_CODE_OBJECT_PATH: |
406 | 0 | case SIG_CODE_SIGNATURE: |
407 | 0 | case SIG_CODE_UNIX_FD: |
408 | 0 | return true; |
409 | 0 | default: |
410 | 0 | return false; |
411 | 0 | } |
412 | 0 | } |
413 | | |
414 | | static const char * |
415 | 0 | skip_enclosed_container(const char *signature, char open_bracket, char closed_bracket) { |
416 | 0 | int nested = 0; |
417 | 0 | for (char sig_code = *signature++; sig_code != '\0'; sig_code = *signature++) { |
418 | 0 | if (sig_code == closed_bracket) { |
419 | 0 | if (nested == 0) { |
420 | 0 | return signature; |
421 | 0 | } |
422 | 0 | nested--; |
423 | 0 | } else if (sig_code == open_bracket) { |
424 | 0 | nested++; |
425 | 0 | } |
426 | 0 | } |
427 | 0 | return NULL; |
428 | 0 | } |
429 | | |
430 | | static const char * |
431 | 0 | skip_single_complete_type(const char *signature) { |
432 | 0 | char sig_code; |
433 | 0 | while (1) { |
434 | 0 | sig_code = *signature++; |
435 | 0 | switch (sig_code) { |
436 | 0 | case SIG_CODE_BYTE: |
437 | 0 | case SIG_CODE_BOOLEAN: |
438 | 0 | case SIG_CODE_INT16: |
439 | 0 | case SIG_CODE_UINT16: |
440 | 0 | case SIG_CODE_INT32: |
441 | 0 | case SIG_CODE_UINT32: |
442 | 0 | case SIG_CODE_INT64: |
443 | 0 | case SIG_CODE_UINT64: |
444 | 0 | case SIG_CODE_DOUBLE: |
445 | 0 | case SIG_CODE_STRING: |
446 | 0 | case SIG_CODE_OBJECT_PATH: |
447 | 0 | case SIG_CODE_SIGNATURE: |
448 | 0 | case SIG_CODE_VARIANT: |
449 | 0 | case SIG_CODE_UNIX_FD: |
450 | 0 | return signature; |
451 | 0 | case SIG_CODE_ARRAY: |
452 | 0 | continue; |
453 | 0 | case SIG_CODE_STRUCT_OPEN: |
454 | 0 | return skip_enclosed_container(signature, SIG_CODE_STRUCT_OPEN, SIG_CODE_STRUCT_CLOSE); |
455 | 0 | case SIG_CODE_DICT_ENTRY_OPEN: |
456 | 0 | return skip_enclosed_container(signature, SIG_CODE_DICT_ENTRY_OPEN, SIG_CODE_DICT_ENTRY_CLOSE); |
457 | 0 | default: |
458 | 0 | return NULL; |
459 | 0 | } |
460 | 0 | } |
461 | 0 | } |
462 | | |
463 | | static bool |
464 | 0 | is_dbus_signature_valid(const char *signature, dbus_packet_t *packet) { |
465 | 0 | char sig_code; |
466 | 0 | size_t length = 0; |
467 | 0 | char prev_sig_code = '\0'; |
468 | 0 | wmem_stack_t *expected_chars = wmem_stack_new(packet->pinfo->pool); |
469 | |
|
470 | 0 | while ((sig_code = *signature++) != '\0') { |
471 | 0 | if (++length >= DBUS_MAX_SIGNATURE_LENGTH) { |
472 | 0 | return false; |
473 | 0 | } |
474 | | |
475 | 0 | switch (sig_code) { |
476 | 0 | case SIG_CODE_BYTE: |
477 | 0 | case SIG_CODE_SIGNATURE: |
478 | 0 | case SIG_CODE_VARIANT: |
479 | 0 | case SIG_CODE_INT16: |
480 | 0 | case SIG_CODE_UINT16: |
481 | 0 | case SIG_CODE_INT32: |
482 | 0 | case SIG_CODE_UINT32: |
483 | 0 | case SIG_CODE_BOOLEAN: |
484 | 0 | case SIG_CODE_OBJECT_PATH: |
485 | 0 | case SIG_CODE_STRING: |
486 | 0 | case SIG_CODE_UNIX_FD: |
487 | 0 | case SIG_CODE_INT64: |
488 | 0 | case SIG_CODE_UINT64: |
489 | 0 | case SIG_CODE_DOUBLE: |
490 | 0 | break; |
491 | 0 | case SIG_CODE_ARRAY: |
492 | 0 | switch (*signature) { |
493 | 0 | case '\0': |
494 | 0 | case SIG_CODE_STRUCT_CLOSE: |
495 | 0 | case SIG_CODE_DICT_ENTRY_CLOSE: |
496 | | // arrays must be followed by a single complete type |
497 | 0 | return false; |
498 | 0 | } |
499 | | // invalid signature codes are detected in the next iteration |
500 | 0 | break; |
501 | 0 | case SIG_CODE_STRUCT_OPEN: |
502 | 0 | if (*signature == SIG_CODE_STRUCT_CLOSE) { |
503 | | // empty structures are not allowed |
504 | 0 | return false; |
505 | 0 | } |
506 | 0 | wmem_stack_push(expected_chars, (void *)SIG_CODE_STRUCT_CLOSE); |
507 | 0 | break; |
508 | 0 | case SIG_CODE_DICT_ENTRY_OPEN: { |
509 | | // dict entries must be an array element type |
510 | | // the first single complete type (the "key") must be a basic type |
511 | 0 | if (prev_sig_code != SIG_CODE_ARRAY || !is_basic_type(*signature)) { |
512 | 0 | return false; |
513 | 0 | } |
514 | | |
515 | | // dict entries must contain exactly two single complete types |
516 | | // + 1 can be used here, since the key is a basic type |
517 | 0 | const char *sig_code_close = skip_single_complete_type(signature + 1); |
518 | 0 | if (!sig_code_close || *sig_code_close != SIG_CODE_DICT_ENTRY_CLOSE) { |
519 | 0 | return false; |
520 | 0 | } |
521 | 0 | wmem_stack_push(expected_chars, (void *)SIG_CODE_DICT_ENTRY_CLOSE); |
522 | 0 | break; |
523 | 0 | } |
524 | 0 | case SIG_CODE_STRUCT_CLOSE: |
525 | 0 | case SIG_CODE_DICT_ENTRY_CLOSE: |
526 | 0 | if (wmem_stack_count(expected_chars) == 0 || |
527 | 0 | (char)(uintptr_t)wmem_stack_pop(expected_chars) != sig_code) { |
528 | 0 | return false; |
529 | 0 | } |
530 | 0 | break; |
531 | 0 | default: |
532 | 0 | return false; |
533 | 0 | } |
534 | | |
535 | 0 | prev_sig_code = sig_code; |
536 | 0 | } |
537 | 0 | return wmem_stack_count(expected_chars) == 0; |
538 | 0 | } |
539 | | |
540 | | static void |
541 | 0 | add_expert(dbus_packet_t *packet, expert_field *ei) { |
542 | 0 | expert_add_info(packet->pinfo, packet->current_pi, ei); |
543 | 0 | } |
544 | | |
545 | | static uint32_t |
546 | 0 | add_uint(dbus_packet_t *packet, int hf) { |
547 | 0 | header_field_info *info = proto_registrar_get_nth(hf); |
548 | 0 | int length; |
549 | 0 | uint32_t value; |
550 | 0 | switch (info->type) { |
551 | 0 | case FT_UINT8: |
552 | 0 | length = 1; |
553 | 0 | break; |
554 | 0 | case FT_UINT32: |
555 | 0 | length = 4; |
556 | 0 | break; |
557 | 0 | default: |
558 | 0 | DISSECTOR_ASSERT_NOT_REACHED(); |
559 | 0 | } |
560 | 0 | packet->current_pi = ptvcursor_add_ret_uint(packet->cursor, hf, length, packet->enc, &value); |
561 | 0 | return value; |
562 | 0 | } |
563 | | |
564 | | static const char * |
565 | 0 | add_dbus_string(dbus_packet_t *packet, int hf, unsigned uint_length) { |
566 | 0 | const char *string; |
567 | 0 | int start_offset = ptvcursor_current_offset(packet->cursor); |
568 | 0 | proto_item *pi = ptvcursor_add_ret_string(packet->cursor, hf, uint_length, |
569 | 0 | packet->enc | ENC_UTF_8, packet->pinfo->pool, (const uint8_t**)&string); |
570 | 0 | int item_length = ptvcursor_current_offset(packet->cursor) - start_offset; |
571 | 0 | uint8_t term_byte = tvb_get_uint8(ptvcursor_tvbuff(packet->cursor), ptvcursor_current_offset(packet->cursor)); |
572 | 0 | proto_item_set_len(pi, item_length + 1); |
573 | 0 | ptvcursor_advance(packet->cursor, 1); |
574 | 0 | packet->current_pi = pi; |
575 | |
|
576 | 0 | if ((strlen(string) != (size_t)(item_length - uint_length)) || (term_byte != '\0')) { |
577 | 0 | return NULL; |
578 | 0 | } |
579 | 0 | return string; |
580 | 0 | } |
581 | | |
582 | | static int |
583 | 0 | calculate_padding_len(int offset, char sig) { |
584 | 0 | int alignment; |
585 | 0 | switch (sig) { |
586 | 0 | case SIG_CODE_BYTE: |
587 | 0 | case SIG_CODE_SIGNATURE: |
588 | 0 | case SIG_CODE_VARIANT: |
589 | 0 | default: |
590 | 0 | alignment = 1; |
591 | 0 | break; |
592 | 0 | case SIG_CODE_INT16: |
593 | 0 | case SIG_CODE_UINT16: |
594 | 0 | alignment = 2; |
595 | 0 | break; |
596 | 0 | case SIG_CODE_INT32: |
597 | 0 | case SIG_CODE_UINT32: |
598 | 0 | case SIG_CODE_BOOLEAN: |
599 | 0 | case SIG_CODE_OBJECT_PATH: |
600 | 0 | case SIG_CODE_ARRAY: |
601 | 0 | case SIG_CODE_STRING: |
602 | 0 | case SIG_CODE_UNIX_FD: |
603 | 0 | alignment = 4; |
604 | 0 | break; |
605 | 0 | case SIG_CODE_INT64: |
606 | 0 | case SIG_CODE_UINT64: |
607 | 0 | case SIG_CODE_DOUBLE: |
608 | 0 | case SIG_CODE_STRUCT_OPEN: |
609 | 0 | case SIG_CODE_DICT_ENTRY_OPEN: |
610 | 0 | alignment = 8; |
611 | 0 | break; |
612 | 0 | } |
613 | 0 | return (alignment - (offset % alignment)) % alignment; |
614 | 0 | } |
615 | | |
616 | | static int |
617 | 0 | add_padding(dbus_packet_t *packet, char sig) { |
618 | 0 | uint8_t value; |
619 | 0 | tvbuff_t *tvb = ptvcursor_tvbuff(packet->cursor); |
620 | 0 | int offset = ptvcursor_current_offset(packet->cursor); |
621 | 0 | int padding_len = calculate_padding_len(offset, sig); |
622 | |
|
623 | 0 | if (padding_len != 0) { |
624 | 0 | packet->current_pi = ptvcursor_add(packet->cursor, hf_dbus_padding, padding_len, packet->enc); |
625 | 0 | for (int i = offset; i < (offset + padding_len); i++) { |
626 | 0 | value = tvb_get_uint8(tvb, i); |
627 | 0 | if (value != 0) { |
628 | 0 | add_expert(packet, &ei_dbus_padding_invalid); |
629 | 0 | return 1; |
630 | 0 | } |
631 | 0 | } |
632 | 0 | proto_item_set_hidden(packet->current_pi); |
633 | 0 | } |
634 | 0 | return 0; |
635 | 0 | } |
636 | | |
637 | | static void |
638 | 0 | reader_cleanup(dbus_type_reader_t *reader) { |
639 | 0 | for (dbus_type_reader_t *r = reader; r->parent; r = r->parent) { |
640 | 0 | ptvcursor_pop_subtree(r->packet->cursor); |
641 | 0 | } |
642 | 0 | } |
643 | | |
644 | | static dbus_type_reader_t * |
645 | 0 | reader_next(dbus_type_reader_t *reader, int hf, int ett, dbus_val_t *value) { |
646 | 0 | int err = 0; |
647 | 0 | char sig_code = *reader->signature++; |
648 | 0 | dbus_packet_t *packet = reader->packet; |
649 | 0 | bool is_single_complete_type = true; |
650 | 0 | add_padding(packet, sig_code); |
651 | |
|
652 | 0 | switch (sig_code) { |
653 | 0 | case SIG_CODE_BYTE: |
654 | 0 | packet->current_pi = ptvcursor_add_ret_uint(packet->cursor, |
655 | 0 | hf != -1 ? hf : hf_dbus_type_byte, 1, packet->enc, &value->uint); |
656 | 0 | break; |
657 | 0 | case SIG_CODE_BOOLEAN: { |
658 | 0 | int offset = ptvcursor_current_offset(packet->cursor); |
659 | 0 | tvbuff_t *tvb = ptvcursor_tvbuff(packet->cursor); |
660 | 0 | uint8_t val = tvb_get_uint8(tvb, offset); |
661 | 0 | packet->current_pi = ptvcursor_add_ret_boolean(packet->cursor, |
662 | 0 | hf != -1 ? hf : hf_dbus_type_boolean, 4, packet->enc, &value->bool_); |
663 | 0 | if (val >= 2) { |
664 | 0 | add_expert(packet, &ei_dbus_type_boolean_invalid); |
665 | 0 | err = 1; |
666 | 0 | } |
667 | 0 | break; |
668 | 0 | } |
669 | 0 | case SIG_CODE_INT16: |
670 | 0 | packet->current_pi = ptvcursor_add_ret_int(packet->cursor, |
671 | 0 | hf != -1 ? hf : hf_dbus_type_int16, 2, packet->enc, &value->int_); |
672 | 0 | break; |
673 | 0 | case SIG_CODE_UINT16: |
674 | 0 | packet->current_pi = ptvcursor_add_ret_uint(packet->cursor, |
675 | 0 | hf != -1 ? hf : hf_dbus_type_uint16, 2, packet->enc, &value->uint); |
676 | 0 | break; |
677 | 0 | case SIG_CODE_INT32: |
678 | 0 | packet->current_pi = ptvcursor_add_ret_int(packet->cursor, |
679 | 0 | hf != -1 ? hf : hf_dbus_type_int32, 4, packet->enc, &value->int_); |
680 | 0 | break; |
681 | 0 | case SIG_CODE_UINT32: |
682 | 0 | packet->current_pi = ptvcursor_add_ret_uint(packet->cursor, |
683 | 0 | hf != -1 ? hf : hf_dbus_type_uint32, 4, packet->enc, &value->uint); |
684 | 0 | break; |
685 | 0 | case SIG_CODE_INT64: { |
686 | 0 | int offset = ptvcursor_current_offset(packet->cursor); |
687 | 0 | tvbuff_t *tvb = ptvcursor_tvbuff(packet->cursor); |
688 | 0 | value->int64 = tvb_get_int64(tvb, offset, packet->enc); |
689 | 0 | packet->current_pi = ptvcursor_add(packet->cursor, |
690 | 0 | hf != -1 ? hf : hf_dbus_type_int64, 8, packet->enc); |
691 | 0 | break; |
692 | 0 | } |
693 | 0 | case SIG_CODE_UINT64: { |
694 | 0 | int offset = ptvcursor_current_offset(packet->cursor); |
695 | 0 | tvbuff_t *tvb = ptvcursor_tvbuff(packet->cursor); |
696 | 0 | value->uint64 = tvb_get_uint64(tvb, offset, packet->enc); |
697 | 0 | packet->current_pi = ptvcursor_add(packet->cursor, |
698 | 0 | hf != -1 ? hf : hf_dbus_type_uint64, 8, packet->enc); |
699 | 0 | break; |
700 | 0 | } |
701 | 0 | case SIG_CODE_DOUBLE: { |
702 | 0 | int offset = ptvcursor_current_offset(packet->cursor); |
703 | 0 | tvbuff_t *tvb = ptvcursor_tvbuff(packet->cursor); |
704 | 0 | value->double_ = tvb_get_ieee_double(tvb, offset, packet->enc); |
705 | 0 | packet->current_pi = ptvcursor_add(packet->cursor, |
706 | 0 | hf != -1 ? hf : hf_dbus_type_double, 8, packet->enc); |
707 | 0 | break; |
708 | 0 | } |
709 | 0 | case SIG_CODE_STRING: { |
710 | 0 | const char *val = add_dbus_string(packet, |
711 | 0 | hf != -1 ? hf : hf_dbus_type_string, 4); |
712 | 0 | if (!val || !g_utf8_validate(val, -1, NULL)) { |
713 | 0 | add_expert(packet, &ei_dbus_string_invalid); |
714 | 0 | err = 1; |
715 | 0 | } |
716 | 0 | value->string = val; |
717 | 0 | break; |
718 | 0 | } |
719 | 0 | case SIG_CODE_OBJECT_PATH: { |
720 | 0 | const char *val = add_dbus_string(packet, hf != -1 ? hf : hf_dbus_type_object_path, 4); |
721 | 0 | if (!val || !is_dbus_object_path_valid(val)) { |
722 | 0 | add_expert(packet, &ei_dbus_type_object_path_invalid); |
723 | 0 | err = 1; |
724 | 0 | } |
725 | 0 | value->string = val; |
726 | 0 | break; |
727 | 0 | } |
728 | 0 | case SIG_CODE_SIGNATURE: { |
729 | 0 | const char *val = add_dbus_string(packet, hf != -1 ? hf : hf_dbus_type_signature, 1); |
730 | 0 | if (!val || !is_dbus_signature_valid(val, packet)) { |
731 | 0 | add_expert(packet, &ei_dbus_type_signature_invalid); |
732 | 0 | err = 1; |
733 | 0 | } |
734 | 0 | value->string = val; |
735 | 0 | break; |
736 | 0 | } |
737 | 0 | case SIG_CODE_ARRAY: { |
738 | 0 | is_single_complete_type = false; |
739 | 0 | proto_item *array = ptvcursor_add_with_subtree(packet->cursor, hf != -1 ? hf : hf_dbus_type_array, |
740 | 0 | SUBTREE_UNDEFINED_LENGTH, ENC_NA, ett != -1 ? ett : ett_dbus_type_array); |
741 | 0 | if (*reader->signature == SIG_CODE_DICT_ENTRY_OPEN) { |
742 | 0 | proto_item_append_text(array, " (Dict)"); |
743 | 0 | } |
744 | 0 | uint32_t array_len = add_uint(packet, hf_dbus_type_array_length); |
745 | 0 | value->uint = array_len; |
746 | 0 | add_padding(packet, *reader->signature); |
747 | 0 | if (array_len == 0) { |
748 | 0 | reader->signature = skip_single_complete_type(reader->signature); |
749 | | // all signatures are validated |
750 | 0 | DISSECTOR_ASSERT(reader->signature); |
751 | 0 | ptvcursor_pop_subtree(packet->cursor); |
752 | 0 | is_single_complete_type = true; |
753 | 0 | } else if (array_len <= DBUS_MAX_ARRAY_LEN) { |
754 | 0 | int end_offset = ptvcursor_current_offset(packet->cursor) + array_len; |
755 | 0 | dbus_type_reader_t *child = wmem_new(packet->pinfo->pool, dbus_type_reader_t); |
756 | 0 | *child = (dbus_type_reader_t){ |
757 | 0 | .packet = reader->packet, |
758 | 0 | .signature = reader->signature, |
759 | 0 | .level = reader->level + 1, |
760 | 0 | .array_level = reader->array_level + 1, |
761 | 0 | .array_type_start = reader->signature, |
762 | 0 | .array_end_offset = end_offset, |
763 | 0 | .container = array, |
764 | 0 | .parent = reader, |
765 | 0 | }; |
766 | 0 | reader = child; |
767 | 0 | } else { |
768 | 0 | add_expert(packet, &ei_dbus_type_array_too_long); |
769 | 0 | err = 1; |
770 | 0 | ptvcursor_pop_subtree(packet->cursor); |
771 | 0 | } |
772 | 0 | break; |
773 | 0 | } |
774 | 0 | case SIG_CODE_STRUCT_OPEN: { |
775 | 0 | is_single_complete_type = false; |
776 | 0 | ptvcursor_add_with_subtree(packet->cursor, hf != -1 ? hf : hf_dbus_type_struct, |
777 | 0 | SUBTREE_UNDEFINED_LENGTH, ENC_NA, ett != -1 ? ett : ett_dbus_type_struct); |
778 | 0 | dbus_type_reader_t *child = wmem_new(packet->pinfo->pool, dbus_type_reader_t); |
779 | 0 | *child = (dbus_type_reader_t){ |
780 | 0 | .packet = reader->packet, |
781 | 0 | .signature = reader->signature, |
782 | 0 | .level = reader->level + 1, |
783 | 0 | .struct_level = reader->struct_level + 1, |
784 | 0 | .parent = reader, |
785 | 0 | }; |
786 | 0 | reader = child; |
787 | 0 | break; |
788 | 0 | } |
789 | 0 | case SIG_CODE_VARIANT: { |
790 | 0 | is_single_complete_type = false; |
791 | 0 | proto_item *variant = ptvcursor_add_with_subtree(packet->cursor, |
792 | 0 | hf != -1 ? hf : hf_dbus_type_variant, |
793 | 0 | SUBTREE_UNDEFINED_LENGTH, ENC_NA, ett != -1 ? ett : ett_dbus_type_variant); |
794 | 0 | const char *variant_signature = add_dbus_string(packet, hf_dbus_type_variant_signature, 1); |
795 | 0 | value->string = variant_signature; |
796 | 0 | if (variant_signature && is_dbus_signature_valid(variant_signature, packet)) { |
797 | 0 | if (variant_signature[0] != '\0') { |
798 | 0 | dbus_type_reader_t *child = wmem_new(packet->pinfo->pool, dbus_type_reader_t); |
799 | 0 | *child = (dbus_type_reader_t){ |
800 | 0 | .packet = reader->packet, |
801 | 0 | .signature = variant_signature, |
802 | 0 | .level = reader->level + 1, |
803 | 0 | .is_in_variant = true, |
804 | 0 | .is_basic_variant = is_basic_type(*variant_signature) |
805 | 0 | && *(variant_signature + 1) == '\0', |
806 | 0 | .container = variant, |
807 | 0 | .parent = reader, |
808 | 0 | }; |
809 | 0 | if (reader->is_in_dict_entry && child->is_basic_variant) { |
810 | 0 | reader->is_basic_dict_entry = true; |
811 | 0 | } |
812 | 0 | reader = child; |
813 | 0 | } else { |
814 | 0 | ptvcursor_pop_subtree(packet->cursor); |
815 | 0 | } |
816 | 0 | } else { |
817 | 0 | add_expert(packet, &ei_dbus_type_variant_signature_invalid); |
818 | 0 | err = 1; |
819 | 0 | ptvcursor_pop_subtree(packet->cursor); |
820 | 0 | } |
821 | 0 | break; |
822 | 0 | } |
823 | 0 | case SIG_CODE_DICT_ENTRY_OPEN: { |
824 | 0 | is_single_complete_type = false; |
825 | 0 | proto_item *dict_entry = ptvcursor_add_with_subtree(packet->cursor, |
826 | 0 | hf != -1 ? hf : hf_dbus_type_dict_entry, |
827 | 0 | SUBTREE_UNDEFINED_LENGTH, ENC_NA, ett != -1 ? ett : ett_dbus_type_dict_entry); |
828 | 0 | dbus_type_reader_t *child = wmem_new(packet->pinfo->pool, dbus_type_reader_t); |
829 | 0 | *child = (dbus_type_reader_t){ |
830 | 0 | .packet = reader->packet, |
831 | 0 | .signature = reader->signature, |
832 | 0 | .level = reader->level + 1, |
833 | 0 | .dict_entry_level = reader->dict_entry_level + 1, |
834 | 0 | .is_in_dict_entry = true, |
835 | 0 | .is_basic_dict_entry = is_basic_type(*(reader->signature + 1)), |
836 | 0 | .container = dict_entry, |
837 | 0 | .parent = reader, |
838 | 0 | }; |
839 | 0 | reader = child; |
840 | 0 | break; |
841 | 0 | } |
842 | 0 | case SIG_CODE_STRUCT_CLOSE: |
843 | 0 | case SIG_CODE_DICT_ENTRY_CLOSE: |
844 | 0 | ptvcursor_pop_subtree(packet->cursor); |
845 | 0 | reader->parent->signature = reader->signature; |
846 | 0 | reader = reader->parent; |
847 | 0 | break; |
848 | 0 | case SIG_CODE_UNIX_FD: |
849 | 0 | packet->current_pi = ptvcursor_add_ret_uint(packet->cursor, |
850 | 0 | hf != -1 ? hf : hf_dbus_type_unix_fd, 4, packet->enc, &value->uint); |
851 | 0 | break; |
852 | 0 | default: |
853 | | // all signatures are validated |
854 | 0 | DISSECTOR_ASSERT_NOT_REACHED(); |
855 | 0 | } |
856 | | |
857 | 0 | if (reader->level > DBUS_MAX_TOTAL_NESTING_LEVEL || |
858 | 0 | reader->array_level > DBUS_MAX_TYPE_NESTING_LEVEL || |
859 | 0 | reader->struct_level > DBUS_MAX_TYPE_NESTING_LEVEL || |
860 | 0 | reader->dict_entry_level > DBUS_MAX_TYPE_NESTING_LEVEL) { |
861 | 0 | add_expert(packet, &ei_dbus_nested_too_deeply); |
862 | 0 | err= 1; |
863 | 0 | } else if (is_single_complete_type) { |
864 | | // Arrays and variants don't have a closing signature code, but they end after a single complete type. |
865 | | // Close them here recursively, e.g. "aav" |
866 | 0 | while (1) { |
867 | 0 | if (reader->array_type_start) { // inside array |
868 | 0 | int offset = ptvcursor_current_offset(packet->cursor); |
869 | |
|
870 | 0 | if (offset < reader->array_end_offset) { |
871 | | // parse next array element -> reset signature |
872 | 0 | reader->signature = reader->array_type_start; |
873 | 0 | break; |
874 | 0 | } else if (offset == reader->array_end_offset) { |
875 | | // all array elements parsed |
876 | 0 | ptvcursor_pop_subtree(packet->cursor); |
877 | 0 | reader->parent->signature = reader->signature; |
878 | 0 | reader = reader->parent; |
879 | 0 | } else { |
880 | | // array elements don't fit into array |
881 | 0 | expert_add_info(packet->pinfo, reader->container, |
882 | 0 | &ei_dbus_type_array_content_out_of_bounds); |
883 | 0 | err = 1; |
884 | 0 | break; |
885 | 0 | } |
886 | 0 | } else if (reader->is_in_variant) { |
887 | 0 | if (reader->is_basic_variant) { |
888 | 0 | proto_item_append_text(reader->container, ": %s", |
889 | 0 | proto_item_get_display_repr(packet->pinfo->pool, packet->current_pi)); |
890 | 0 | } |
891 | 0 | ptvcursor_pop_subtree(packet->cursor); |
892 | 0 | reader = reader->parent; |
893 | 0 | } else { |
894 | 0 | break; |
895 | 0 | } |
896 | 0 | } |
897 | 0 | if (reader->is_in_dict_entry) { |
898 | | // add "key: value" to dict entry item to make it readable without expanding the tree |
899 | 0 | if (*(reader->signature - 2) == SIG_CODE_DICT_ENTRY_OPEN) { // == key |
900 | | // key is always a basic type |
901 | 0 | proto_item_append_text(reader->container, ", %s", |
902 | 0 | proto_item_get_display_repr(packet->pinfo->pool, packet->current_pi)); |
903 | 0 | } else if (reader->is_basic_dict_entry) { // == value |
904 | 0 | proto_item_append_text(reader->container, ": %s", |
905 | 0 | proto_item_get_display_repr(packet->pinfo->pool, packet->current_pi)); |
906 | 0 | } |
907 | 0 | } |
908 | 0 | } |
909 | |
|
910 | 0 | if (err) { |
911 | 0 | reader_cleanup(reader); |
912 | 0 | return NULL; |
913 | 0 | } |
914 | 0 | return reader; |
915 | 0 | } |
916 | | |
917 | | static bool |
918 | 0 | reader_is_finished(dbus_type_reader_t *reader) { |
919 | 0 | return *reader->signature == '\0' && reader->parent == NULL; |
920 | 0 | } |
921 | | |
922 | | static int |
923 | 0 | dissect_dbus_signature(dbus_packet_t *packet, const char *signature) { |
924 | 0 | dbus_type_reader_t root_reader = { |
925 | 0 | .packet = packet, |
926 | 0 | .signature = signature, |
927 | 0 | }; |
928 | 0 | dbus_type_reader_t *reader = &root_reader; |
929 | 0 | dbus_val_t value; |
930 | 0 | while (!reader_is_finished(reader)) { |
931 | 0 | reader = reader_next(reader, -1, -1, &value); |
932 | 0 | if (!reader) { |
933 | 0 | return 1; |
934 | 0 | } |
935 | 0 | } |
936 | 0 | return 0; |
937 | 0 | } |
938 | | |
939 | | static int |
940 | 0 | dissect_dbus_body(dbus_packet_t *packet) { |
941 | 0 | int err = 0; |
942 | 0 | if (packet->signature[0]) { |
943 | 0 | ptvcursor_add_with_subtree(packet->cursor, hf_dbus_body, |
944 | 0 | SUBTREE_UNDEFINED_LENGTH, ENC_NA, ett_dbus_body); |
945 | 0 | err = dissect_dbus_signature(packet, packet->signature); |
946 | 0 | ptvcursor_pop_subtree(packet->cursor); |
947 | 0 | } |
948 | 0 | return err; |
949 | 0 | } |
950 | | |
951 | | static void |
952 | 0 | update_unique_name_map(const char *name1, const char *name2) { |
953 | 0 | const char *unique_name; |
954 | 0 | const char *well_known_name; |
955 | |
|
956 | 0 | if (!dbus_resolve_names) { |
957 | 0 | return; |
958 | 0 | } |
959 | | |
960 | 0 | if (name1[0] == ':' && name2[0] != ':') { |
961 | 0 | unique_name = name1; |
962 | 0 | well_known_name = name2; |
963 | 0 | } else if (name2[0] == ':' && name1[0] != ':') { |
964 | 0 | unique_name = name2; |
965 | 0 | well_known_name = name1; |
966 | 0 | } else { |
967 | | // both are well-known or both are unique names |
968 | 0 | return; |
969 | 0 | } |
970 | 0 | if (!wmem_map_contains(unique_name_map, unique_name)) { |
971 | 0 | wmem_map_insert(unique_name_map, |
972 | 0 | wmem_strdup(wmem_file_scope(), unique_name), |
973 | 0 | wmem_strdup(wmem_file_scope(), well_known_name)); |
974 | 0 | } |
975 | 0 | } |
976 | | |
977 | | static void |
978 | 0 | add_conversation(dbus_packet_t *packet, proto_tree *header_field_tree) { |
979 | 0 | bool is_request; |
980 | 0 | char *request_dest; |
981 | 0 | char *key; |
982 | |
|
983 | 0 | if (!packet->sender || !packet->destination) { |
984 | | // in a peer-to-peer setup, sender and destination can be unset, in which case conversation tracking |
985 | | // doesn't make sense. |
986 | 0 | return; |
987 | 0 | } |
988 | | |
989 | 0 | switch (packet->message_type) { |
990 | 0 | case DBUS_MESSAGE_TYPE_METHOD_CALL: |
991 | 0 | if (packet->flags & DBUS_FLAGS_NO_REPLY_EXPECTED_MASK) { |
992 | | // there won't be a response, no need to track |
993 | 0 | return; |
994 | 0 | } |
995 | 0 | is_request = true; |
996 | | |
997 | | // There are cases where the destination address of the request doesn't match the sender address of the |
998 | | // response, for example: |
999 | | // - The request is sent to the well-known bus name (e.g. org.freedesktop.PolicyKit1), but the reply is |
1000 | | // sent from the unique connection name (e.g. :1.10). Both names refer to the same connection and for |
1001 | | // every unique connection name, there can be multiple well-known names. |
1002 | | // - The D-Bus daemon (org.freedesktop.DBus) sends the reply, instead of the recipient, e.g. |
1003 | | // org.freedesktop.DBus.Error.AccessDenied |
1004 | | // To find the correct response, match the request sender + serial with the response destination + |
1005 | | // reply serial. |
1006 | 0 | if (!PINFO_FD_VISITED(packet->pinfo)) { |
1007 | 0 | request_dest = wmem_strdup(wmem_file_scope(), packet->destination); |
1008 | 0 | key = wmem_strdup_printf(wmem_file_scope(), "%s %u", packet->sender, packet->serial); |
1009 | 0 | wmem_map_insert(request_info_map, key, request_dest); |
1010 | 0 | } |
1011 | 0 | break; |
1012 | 0 | case DBUS_MESSAGE_TYPE_METHOD_RETURN: |
1013 | 0 | case DBUS_MESSAGE_TYPE_ERROR: |
1014 | 0 | is_request = false; |
1015 | |
|
1016 | 0 | key = wmem_strdup_printf(packet->pinfo->pool, "%s %u", packet->destination, packet->reply_serial); |
1017 | 0 | request_dest = (char *)wmem_map_lookup(request_info_map, key); |
1018 | 0 | if (request_dest && !g_str_equal(request_dest, packet->sender)) { |
1019 | | // Replace the sender address of the response with the destination address of the request, so |
1020 | | // the conversation can be found. |
1021 | 0 | address sender_addr; |
1022 | 0 | set_address(&sender_addr, AT_STRINGZ, (int)strlen(request_dest)+1, request_dest); |
1023 | 0 | conversation_set_conv_addr_port_endpoints(packet->pinfo, &sender_addr, &packet->pinfo->dst, |
1024 | 0 | conversation_pt_to_endpoint_type(packet->pinfo->ptype), |
1025 | 0 | packet->pinfo->srcport, packet->pinfo->destport); |
1026 | |
|
1027 | 0 | if (!PINFO_FD_VISITED(packet->pinfo) && packet->message_type == DBUS_MESSAGE_TYPE_METHOD_RETURN) { |
1028 | 0 | update_unique_name_map(request_dest, packet->sender); |
1029 | 0 | } |
1030 | 0 | } |
1031 | 0 | break; |
1032 | 0 | case DBUS_MESSAGE_TYPE_SIGNAL: |
1033 | 0 | default: |
1034 | | // signals don't have a response, no need to track |
1035 | 0 | return; |
1036 | 0 | } |
1037 | | |
1038 | 0 | conversation_t *conversation = find_or_create_conversation(packet->pinfo); |
1039 | 0 | dbus_conv_info_t *conv_info = (dbus_conv_info_t *)conversation_get_proto_data(conversation, proto_dbus); |
1040 | |
|
1041 | 0 | if (!conv_info) { |
1042 | 0 | conv_info = wmem_new(wmem_file_scope(), dbus_conv_info_t); |
1043 | 0 | conv_info->packets = wmem_map_new(wmem_file_scope(), g_direct_hash, g_direct_equal); |
1044 | 0 | conversation_add_proto_data(conversation, proto_dbus, conv_info); |
1045 | 0 | } |
1046 | |
|
1047 | 0 | dbus_transaction_t *trans; |
1048 | 0 | if (!PINFO_FD_VISITED(packet->pinfo)) { |
1049 | 0 | if (is_request) { |
1050 | 0 | trans = wmem_new(wmem_file_scope(), dbus_transaction_t); |
1051 | 0 | *trans = (dbus_transaction_t){ |
1052 | 0 | .req_frame = packet->pinfo->num, |
1053 | 0 | .req_time = packet->pinfo->fd->abs_ts, |
1054 | 0 | .path = wmem_strdup(wmem_file_scope(), packet->path), |
1055 | 0 | .interface = wmem_strdup(wmem_file_scope(), packet->interface), |
1056 | 0 | .member = wmem_strdup(wmem_file_scope(), packet->member), |
1057 | 0 | }; |
1058 | 0 | wmem_map_insert(conv_info->packets, GUINT_TO_POINTER(packet->serial), (void *)trans); |
1059 | 0 | } else { |
1060 | 0 | trans = (dbus_transaction_t *)wmem_map_lookup(conv_info->packets, GUINT_TO_POINTER(packet->reply_serial)); |
1061 | 0 | if (trans) { |
1062 | 0 | trans->rep_frame = packet->pinfo->num; |
1063 | 0 | } |
1064 | 0 | } |
1065 | 0 | } else { |
1066 | 0 | uint32_t request_serial = is_request ? packet->serial : packet->reply_serial; |
1067 | 0 | trans = (dbus_transaction_t *)wmem_map_lookup(conv_info->packets, GUINT_TO_POINTER(request_serial)); |
1068 | 0 | } |
1069 | |
|
1070 | 0 | if (!trans) { |
1071 | 0 | return; |
1072 | 0 | } |
1073 | | |
1074 | 0 | if (is_request) { |
1075 | 0 | proto_item *it = proto_tree_add_uint(header_field_tree, hf_dbus_response_in, ptvcursor_tvbuff(packet->cursor), 0, 0, trans->rep_frame); |
1076 | 0 | proto_item_set_generated(it); |
1077 | 0 | } else { |
1078 | 0 | nstime_t ns; |
1079 | 0 | proto_item *it; |
1080 | 0 | tvbuff_t *tvb = ptvcursor_tvbuff(packet->cursor); |
1081 | |
|
1082 | 0 | it = proto_tree_add_string(header_field_tree, hf_dbus_path, tvb, 0, 0, trans->path); |
1083 | 0 | proto_item_set_generated(it); |
1084 | 0 | packet->path = trans->path; |
1085 | |
|
1086 | 0 | it = proto_tree_add_string(header_field_tree, hf_dbus_interface, tvb, 0, 0, trans->interface); |
1087 | 0 | proto_item_set_generated(it); |
1088 | 0 | packet->interface = trans->interface; |
1089 | |
|
1090 | 0 | it = proto_tree_add_string(header_field_tree, hf_dbus_member, tvb, 0, 0, trans->member); |
1091 | 0 | proto_item_set_generated(it); |
1092 | 0 | packet->member = trans->member; |
1093 | |
|
1094 | 0 | it = proto_tree_add_uint(header_field_tree, hf_dbus_response_to, tvb, 0, 0, trans->req_frame); |
1095 | 0 | proto_item_set_generated(it); |
1096 | |
|
1097 | 0 | nstime_delta(&ns, &packet->pinfo->fd->abs_ts, &trans->req_time); |
1098 | 0 | it = proto_tree_add_time(header_field_tree, hf_dbus_response_time, tvb, 0, 0, &ns); |
1099 | 0 | proto_item_set_generated(it); |
1100 | 0 | } |
1101 | 0 | } |
1102 | | |
1103 | | static void |
1104 | 0 | resolve_unique_name(dbus_packet_t *packet, proto_tree *header_field_tree) { |
1105 | 0 | proto_item *it; |
1106 | 0 | tvbuff_t *tvb = ptvcursor_tvbuff(packet->cursor); |
1107 | |
|
1108 | 0 | if (packet->sender) { |
1109 | 0 | const char *sender_well_known = (const char *)wmem_map_lookup(unique_name_map, packet->sender); |
1110 | 0 | if (sender_well_known) { |
1111 | 0 | set_address(&packet->pinfo->src, AT_STRINGZ, (int)strlen(sender_well_known)+1, sender_well_known); |
1112 | 0 | it = proto_tree_add_string(header_field_tree, hf_dbus_sender, tvb, 0, 0, sender_well_known); |
1113 | 0 | proto_item_set_generated(it); |
1114 | 0 | } |
1115 | 0 | } |
1116 | |
|
1117 | 0 | if (packet->destination) { |
1118 | 0 | const char *destination_well_known = (const char *)wmem_map_lookup(unique_name_map, packet->destination); |
1119 | 0 | if (destination_well_known) { |
1120 | 0 | set_address(&packet->pinfo->dst, AT_STRINGZ, (int)strlen(destination_well_known)+1, destination_well_known); |
1121 | 0 | it = proto_tree_add_string(header_field_tree, hf_dbus_destination, tvb, 0, 0, destination_well_known); |
1122 | 0 | proto_item_set_generated(it); |
1123 | 0 | } |
1124 | 0 | } |
1125 | 0 | } |
1126 | | |
1127 | | static int |
1128 | 0 | dissect_dbus_header_fields(dbus_packet_t *packet) { |
1129 | 0 | dbus_type_reader_t root_reader = { |
1130 | 0 | .packet = packet, |
1131 | 0 | .signature = "a{yv}", |
1132 | 0 | }; |
1133 | 0 | dbus_type_reader_t *reader = &root_reader; |
1134 | 0 | dbus_val_t value; |
1135 | 0 | #define NEXT_OR_RETURN(hf, ett) if (!(reader = reader_next(reader, hf, ett, &value))) return 1; |
1136 | | |
1137 | | // Header Field Array |
1138 | 0 | NEXT_OR_RETURN(-1, ett_dbus_header_field_array); |
1139 | 0 | proto_item *header_field_array_pi = reader->container; |
1140 | 0 | proto_item_set_text(header_field_array_pi, "Header Field Array"); |
1141 | 0 | while (reader->level > 0) { |
1142 | | // Header Field (Dict) |
1143 | 0 | NEXT_OR_RETURN(-1, ett_dbus_header_field); |
1144 | | // Field Code |
1145 | 0 | NEXT_OR_RETURN(hf_dbus_field_code, -1); |
1146 | 0 | uint32_t field_code = value.uint; |
1147 | 0 | const char *field_code_str = val_to_str_const(field_code, field_code_vals, "Unknown field code"); |
1148 | 0 | proto_item_append_text(reader->container, ", %s", field_code_str); |
1149 | 0 | if (field_code == DBUS_HEADER_FIELD_INVALID) { |
1150 | 0 | add_expert(packet, &ei_dbus_field_code_invalid); |
1151 | 0 | reader_cleanup(reader); |
1152 | 0 | return 1; |
1153 | 0 | } |
1154 | | |
1155 | | // Header Field Value (Variant) |
1156 | 0 | NEXT_OR_RETURN(-1, -1); |
1157 | 0 | const char *header_field_signature = value.string; |
1158 | |
|
1159 | 0 | const char *expected_signature; |
1160 | 0 | switch (field_code) { |
1161 | 0 | case DBUS_HEADER_FIELD_PATH: |
1162 | 0 | expected_signature = "o"; |
1163 | 0 | break; |
1164 | 0 | case DBUS_HEADER_FIELD_INTERFACE: |
1165 | 0 | case DBUS_HEADER_FIELD_MEMBER: |
1166 | 0 | case DBUS_HEADER_FIELD_ERROR_NAME: |
1167 | 0 | case DBUS_HEADER_FIELD_DESTINATION: |
1168 | 0 | case DBUS_HEADER_FIELD_SENDER: |
1169 | 0 | expected_signature = "s"; |
1170 | 0 | break; |
1171 | 0 | case DBUS_HEADER_FIELD_REPLY_SERIAL: |
1172 | 0 | expected_signature = "u"; |
1173 | 0 | break; |
1174 | 0 | case DBUS_HEADER_FIELD_UNIX_FDS: |
1175 | 0 | expected_signature = "u"; |
1176 | 0 | break; |
1177 | 0 | case DBUS_HEADER_FIELD_SIGNATURE: |
1178 | 0 | expected_signature = "g"; |
1179 | 0 | break; |
1180 | 0 | default: |
1181 | 0 | expected_signature = NULL; |
1182 | 0 | } |
1183 | | |
1184 | 0 | if (expected_signature && strcmp(header_field_signature, expected_signature) != 0) { |
1185 | 0 | add_expert(packet, &ei_dbus_field_signature_wrong); |
1186 | 0 | reader_cleanup(reader); |
1187 | 0 | return 1; |
1188 | 0 | } |
1189 | | |
1190 | | // Variant Value |
1191 | 0 | switch (field_code) { |
1192 | 0 | case DBUS_HEADER_FIELD_PATH: |
1193 | 0 | NEXT_OR_RETURN(hf_dbus_path, -1); |
1194 | 0 | packet->path = value.string; |
1195 | 0 | break; |
1196 | 0 | case DBUS_HEADER_FIELD_INTERFACE: |
1197 | 0 | NEXT_OR_RETURN(hf_dbus_interface, -1); |
1198 | 0 | packet->interface = value.string; |
1199 | 0 | if (!is_dbus_interface_valid(packet->interface)) { |
1200 | 0 | add_expert(packet, &ei_dbus_interface_invalid); |
1201 | 0 | reader_cleanup(reader); |
1202 | 0 | return 1; |
1203 | 0 | } |
1204 | 0 | break; |
1205 | 0 | case DBUS_HEADER_FIELD_MEMBER: |
1206 | 0 | NEXT_OR_RETURN(hf_dbus_member, -1); |
1207 | 0 | packet->member = value.string; |
1208 | 0 | if (!is_dbus_member_name_valid(packet->member)) { |
1209 | 0 | add_expert(packet, &ei_dbus_member_invalid); |
1210 | 0 | reader_cleanup(reader); |
1211 | 0 | return 1; |
1212 | 0 | } |
1213 | 0 | break; |
1214 | 0 | case DBUS_HEADER_FIELD_ERROR_NAME: |
1215 | 0 | NEXT_OR_RETURN(hf_dbus_error_name, -1); |
1216 | 0 | packet->error_name = value.string; |
1217 | 0 | if (!is_dbus_interface_valid(packet->error_name)) { |
1218 | 0 | add_expert(packet, &ei_dbus_error_name_invalid); |
1219 | 0 | reader_cleanup(reader); |
1220 | 0 | return 1; |
1221 | 0 | } |
1222 | 0 | break; |
1223 | 0 | case DBUS_HEADER_FIELD_DESTINATION: |
1224 | 0 | NEXT_OR_RETURN(hf_dbus_destination, -1); |
1225 | 0 | packet->destination = value.string; |
1226 | 0 | if (!is_dbus_bus_name_valid(packet->destination)) { |
1227 | 0 | add_expert(packet, &ei_dbus_bus_name_invalid); |
1228 | 0 | reader_cleanup(reader); |
1229 | 0 | return 1; |
1230 | 0 | } |
1231 | 0 | set_address(&packet->pinfo->dst, AT_STRINGZ, (int)strlen(packet->destination)+1, |
1232 | 0 | wmem_strdup(packet->pinfo->pool, packet->destination)); |
1233 | 0 | break; |
1234 | 0 | case DBUS_HEADER_FIELD_SENDER: |
1235 | 0 | NEXT_OR_RETURN(hf_dbus_sender, -1); |
1236 | 0 | packet->sender = value.string; |
1237 | 0 | if (!is_dbus_bus_name_valid(packet->sender)) { |
1238 | 0 | add_expert(packet, &ei_dbus_bus_name_invalid); |
1239 | 0 | reader_cleanup(reader); |
1240 | 0 | return 1; |
1241 | 0 | } |
1242 | 0 | set_address(&packet->pinfo->src, AT_STRINGZ, (int)strlen(packet->sender)+1, |
1243 | 0 | wmem_strdup(packet->pinfo->pool, packet->sender)); |
1244 | 0 | break; |
1245 | 0 | case DBUS_HEADER_FIELD_SIGNATURE: |
1246 | 0 | NEXT_OR_RETURN(hf_dbus_signature, -1); |
1247 | 0 | packet->signature = value.string; |
1248 | 0 | break; |
1249 | 0 | case DBUS_HEADER_FIELD_REPLY_SERIAL: |
1250 | 0 | NEXT_OR_RETURN(hf_dbus_reply_serial, -1); |
1251 | 0 | packet->reply_serial = value.uint; |
1252 | 0 | if (packet->reply_serial == 0) { |
1253 | 0 | add_expert(packet, &ei_dbus_serial_invalid); |
1254 | 0 | reader_cleanup(reader); |
1255 | 0 | return 1; |
1256 | 0 | } |
1257 | 0 | break; |
1258 | 0 | case DBUS_HEADER_FIELD_UNIX_FDS: |
1259 | 0 | NEXT_OR_RETURN(hf_dbus_unix_fds, -1); |
1260 | 0 | packet->unix_fds = value.uint; |
1261 | 0 | break; |
1262 | 0 | default: |
1263 | | // Unknown Field code must be skipped without error |
1264 | 0 | do { |
1265 | 0 | NEXT_OR_RETURN(-1, -1); |
1266 | | // Skip while inside Header Field Array -> Header Field Dict -> Variant |
1267 | 0 | } while (reader->level >= 3); |
1268 | 0 | } |
1269 | | // end of dict |
1270 | 0 | NEXT_OR_RETURN(-1, -1); |
1271 | 0 | } |
1272 | | |
1273 | 0 | bool is_field_missing = false; |
1274 | 0 | switch (packet->message_type) { |
1275 | 0 | case DBUS_MESSAGE_TYPE_METHOD_CALL: |
1276 | 0 | is_field_missing = !packet->path || !packet->member; |
1277 | 0 | break; |
1278 | 0 | case DBUS_MESSAGE_TYPE_METHOD_RETURN: |
1279 | 0 | is_field_missing = !packet->reply_serial; |
1280 | 0 | break; |
1281 | 0 | case DBUS_MESSAGE_TYPE_ERROR: |
1282 | 0 | is_field_missing = !packet->error_name || !packet->reply_serial; |
1283 | 0 | break; |
1284 | 0 | case DBUS_MESSAGE_TYPE_SIGNAL: |
1285 | 0 | is_field_missing = !packet->path || !packet->interface || !packet->member; |
1286 | 0 | break; |
1287 | 0 | default: |
1288 | 0 | DISSECTOR_ASSERT_NOT_REACHED(); |
1289 | 0 | break; |
1290 | 0 | } |
1291 | 0 | if (is_field_missing) { |
1292 | 0 | expert_add_info(packet->pinfo, header_field_array_pi, &ei_dbus_required_header_field_missing); |
1293 | 0 | return 1; |
1294 | 0 | } |
1295 | | |
1296 | 0 | add_conversation(packet, proto_item_get_subtree(header_field_array_pi)); |
1297 | 0 | if (dbus_resolve_names) { |
1298 | 0 | resolve_unique_name(packet, proto_item_get_subtree(header_field_array_pi)); |
1299 | 0 | } |
1300 | |
|
1301 | 0 | switch(packet->message_type) { |
1302 | 0 | case DBUS_MESSAGE_TYPE_METHOD_CALL: |
1303 | 0 | col_add_fstr(packet->pinfo->cinfo, COL_INFO, "%s(%s) @ %s", packet->member, packet->signature, packet->path); |
1304 | 0 | break; |
1305 | 0 | case DBUS_MESSAGE_TYPE_SIGNAL: |
1306 | 0 | col_add_fstr(packet->pinfo->cinfo, COL_INFO, "* %s(%s) @ %s", packet->member, packet->signature, packet->path); |
1307 | 0 | break; |
1308 | 0 | case DBUS_MESSAGE_TYPE_ERROR: |
1309 | 0 | if (packet->member) { |
1310 | 0 | col_add_fstr(packet->pinfo->cinfo, COL_INFO, "! %s: %s", packet->member, packet->error_name); |
1311 | 0 | } else { |
1312 | 0 | col_add_fstr(packet->pinfo->cinfo, COL_INFO, "! %s", packet->error_name); |
1313 | 0 | } |
1314 | 0 | break; |
1315 | 0 | case DBUS_MESSAGE_TYPE_METHOD_RETURN: |
1316 | 0 | if (packet->member) { |
1317 | 0 | if (*packet->signature != '\0') { |
1318 | 0 | col_add_fstr(packet->pinfo->cinfo, COL_INFO, "-> %s: '%s'", packet->member, packet->signature); |
1319 | 0 | } else { |
1320 | 0 | col_add_fstr(packet->pinfo->cinfo, COL_INFO, "-> %s: OK", packet->member); |
1321 | |
|
1322 | 0 | } |
1323 | 0 | } else { |
1324 | 0 | col_add_fstr(packet->pinfo->cinfo, COL_INFO, "-> '%s'", packet->signature); |
1325 | 0 | } |
1326 | 0 | break; |
1327 | 0 | default: |
1328 | 0 | DISSECTOR_ASSERT_NOT_REACHED(); |
1329 | 0 | break; |
1330 | 0 | } |
1331 | | |
1332 | | // Header length must be a multiple of 8 bytes |
1333 | 0 | return add_padding(packet, SIG_CODE_STRUCT_OPEN); |
1334 | 0 | } |
1335 | | |
1336 | | static int |
1337 | 0 | dissect_dbus_header(dbus_packet_t *packet) { |
1338 | 0 | uint32_t val; |
1339 | | |
1340 | | // Endianness |
1341 | 0 | packet->current_pi = ptvcursor_add_ret_uint(packet->cursor, hf_dbus_endianness, 1, ENC_NA, &val); |
1342 | 0 | switch (val) { |
1343 | 0 | case 'l': |
1344 | 0 | packet->enc = ENC_LITTLE_ENDIAN; |
1345 | 0 | break; |
1346 | 0 | case 'B': |
1347 | 0 | packet->enc = ENC_BIG_ENDIAN; |
1348 | 0 | break; |
1349 | 0 | default: |
1350 | 0 | add_expert(packet, &ei_dbus_endianness_invalid); |
1351 | 0 | return 1; |
1352 | 0 | } |
1353 | | |
1354 | | // Message Type |
1355 | 0 | packet->message_type = add_uint(packet, hf_dbus_message_type); |
1356 | 0 | const char *info = try_val_to_str(packet->message_type, message_type_vals); |
1357 | 0 | if (packet->message_type == DBUS_MESSAGE_TYPE_INVALID) { |
1358 | 0 | col_set_str(packet->pinfo->cinfo, COL_INFO, info); |
1359 | 0 | add_expert(packet, &ei_dbus_message_type_invalid); |
1360 | 0 | return 1; |
1361 | 0 | } else if (!info) { |
1362 | 0 | col_set_str(packet->pinfo->cinfo, COL_INFO, "Unknown message type"); |
1363 | 0 | add_expert(packet, &ei_dbus_message_type_unknown); |
1364 | 0 | return 1; |
1365 | 0 | } |
1366 | 0 | col_set_str(packet->pinfo->cinfo, COL_INFO, info); |
1367 | | |
1368 | | // Flags |
1369 | 0 | ptvcursor_add_with_subtree(packet->cursor, hf_dbus_flags, 1, packet->enc, ett_dbus_flags); |
1370 | 0 | ptvcursor_add_no_advance(packet->cursor, hf_dbus_flags_no_reply_expected, 1, packet->enc); |
1371 | 0 | ptvcursor_add_no_advance(packet->cursor, hf_dbus_flags_no_auto_start, 1, packet->enc); |
1372 | 0 | ptvcursor_add_no_advance(packet->cursor, hf_dbus_flags_allow_interactive_authorization, 1, packet->enc); |
1373 | 0 | packet->flags = tvb_get_uint8(ptvcursor_tvbuff(packet->cursor), ptvcursor_current_offset(packet->cursor)); |
1374 | 0 | ptvcursor_advance(packet->cursor, 1); |
1375 | 0 | ptvcursor_pop_subtree(packet->cursor); |
1376 | | |
1377 | | // Version |
1378 | 0 | if (add_uint(packet, hf_dbus_version) != 1) { |
1379 | 0 | add_expert(packet, &ei_dbus_version_invalid); |
1380 | 0 | return 1; |
1381 | 0 | } |
1382 | | |
1383 | | // Body Length |
1384 | 0 | packet->body_len = add_uint(packet, hf_dbus_body_length); |
1385 | | |
1386 | | // Serial |
1387 | 0 | packet->serial = add_uint(packet, hf_dbus_serial); |
1388 | 0 | if (packet->serial == 0) { |
1389 | 0 | add_expert(packet, &ei_dbus_serial_invalid); |
1390 | 0 | return 1; |
1391 | 0 | } |
1392 | | |
1393 | 0 | return 0; |
1394 | 0 | } |
1395 | | |
1396 | | static int |
1397 | 0 | dissect_dbus(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data _U_) { |
1398 | 0 | dbus_packet_t packet = { .pinfo = pinfo, .signature = "" }; |
1399 | |
|
1400 | 0 | col_set_str(pinfo->cinfo, COL_PROTOCOL, "D-Bus"); |
1401 | 0 | col_set_str(pinfo->cinfo, COL_INFO, "D-Bus"); |
1402 | |
|
1403 | 0 | proto_item *pi = proto_tree_add_protocol_format(tree, proto_dbus, tvb, 0, -1, "D-Bus"); |
1404 | 0 | proto_tree *dbus_tree = proto_item_add_subtree(pi, ett_dbus); |
1405 | |
|
1406 | 0 | unsigned offset = 0; |
1407 | 0 | packet.cursor = ptvcursor_new(pinfo->pool, dbus_tree, tvb, offset); |
1408 | |
|
1409 | 0 | (void)(dissect_dbus_header(&packet) || |
1410 | 0 | dissect_dbus_header_fields(&packet) || |
1411 | 0 | dissect_dbus_body(&packet)); |
1412 | |
|
1413 | 0 | offset = ptvcursor_current_offset(packet.cursor); |
1414 | 0 | proto_item_set_end(pi, tvb, offset); |
1415 | 0 | ptvcursor_free(packet.cursor); |
1416 | 0 | return offset; |
1417 | 0 | } |
1418 | | |
1419 | 0 | #define DBUS_HEADER_LEN 16 |
1420 | | |
1421 | | static unsigned |
1422 | | get_dbus_message_len(packet_info *pinfo _U_, tvbuff_t *tvb, |
1423 | 0 | int offset, void *data _U_) { |
1424 | |
|
1425 | 0 | unsigned encoding; |
1426 | 0 | uint32_t len_body, len_hdr; |
1427 | |
|
1428 | 0 | switch (tvb_get_uint8(tvb, offset)) { |
1429 | 0 | case 'l': |
1430 | 0 | encoding = ENC_LITTLE_ENDIAN; |
1431 | 0 | break; |
1432 | 0 | case 'B': |
1433 | 0 | default: |
1434 | 0 | encoding = ENC_BIG_ENDIAN; |
1435 | 0 | break; |
1436 | 0 | } |
1437 | | |
1438 | 0 | len_hdr = DBUS_HEADER_LEN + tvb_get_uint32(tvb, offset + 12, encoding); |
1439 | 0 | len_hdr = WS_ROUNDUP_8(len_hdr); |
1440 | 0 | len_body = tvb_get_uint32(tvb, offset + 4, encoding); |
1441 | |
|
1442 | 0 | return len_hdr + len_body; |
1443 | 0 | } |
1444 | | |
1445 | | static int |
1446 | 0 | dissect_dbus_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { |
1447 | 0 | return dissect_dbus(tvb, pinfo, tree, data); |
1448 | 0 | } |
1449 | | |
1450 | | static int |
1451 | 0 | dissect_dbus_tcp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, void *data) { |
1452 | 0 | tcp_dissect_pdus(tvb, pinfo, tree, dbus_desegment, DBUS_HEADER_LEN, |
1453 | 0 | get_dbus_message_len, dissect_dbus_pdu, data); |
1454 | 0 | return tvb_reported_length(tvb); |
1455 | 0 | } |
1456 | | |
1457 | | void |
1458 | 15 | proto_register_dbus(void) { |
1459 | 15 | static hf_register_info hf[] = { |
1460 | 15 | { &hf_dbus_endianness, { "Endianness", "dbus.endianness", |
1461 | 15 | FT_UINT8, BASE_NONE, VALS(endianness_vals), 0x00, NULL, HFILL }}, |
1462 | 15 | { &hf_dbus_message_type, { "Message Type", "dbus.message_type", |
1463 | 15 | FT_UINT8, BASE_NONE, VALS(message_type_vals), 0x00, NULL, HFILL }}, |
1464 | 15 | { &hf_dbus_flags, { "Message Flags", "dbus.flags", |
1465 | 15 | FT_UINT8, BASE_HEX, NULL, 0x00, NULL, HFILL }}, |
1466 | 15 | { &hf_dbus_flags_no_reply_expected, { "No Reply Expected", "dbus.flags.no_reply_expected", |
1467 | 15 | FT_BOOLEAN, 8, TFS(¬_expected_vals), |
1468 | 15 | DBUS_FLAGS_NO_REPLY_EXPECTED_MASK, NULL, HFILL }}, |
1469 | 15 | { &hf_dbus_flags_no_auto_start, { "No Auto Start", "dbus.flags.no_auto_start", |
1470 | 15 | FT_BOOLEAN, 8, TFS(&no_start_vals), |
1471 | 15 | DBUS_FLAGS_NO_AUTO_START_MASK, NULL, HFILL }}, |
1472 | 15 | { &hf_dbus_flags_allow_interactive_authorization, { "Allow Interactive Authorization", "dbus.flags.allow_interactive_authorization", |
1473 | 15 | FT_BOOLEAN, 8, TFS(&allow_vals), |
1474 | 15 | DBUS_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION_MASK, NULL, HFILL }}, |
1475 | 15 | { &hf_dbus_version, { "Protocol Version", "dbus.version", |
1476 | 15 | FT_UINT8, BASE_DEC, NULL, 0x00, NULL, HFILL }}, |
1477 | 15 | { &hf_dbus_body_length, { "Message Body Length", "dbus.body_length", |
1478 | 15 | FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }}, |
1479 | 15 | { &hf_dbus_serial, { "Message Serial", "dbus.serial", |
1480 | 15 | FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }}, |
1481 | 15 | { &hf_dbus_field_code, { "Field Code", "dbus.field_code", |
1482 | 15 | FT_UINT8, BASE_DEC, VALS(field_code_vals), 0x00, NULL, HFILL }}, |
1483 | 15 | { &hf_dbus_padding, { "Padding", "dbus.padding", |
1484 | 15 | FT_BYTES, BASE_NO_DISPLAY_VALUE, NULL, 0x00, NULL, HFILL }}, |
1485 | 15 | { &hf_dbus_path, { "Path", "dbus.path", |
1486 | 15 | FT_UINT_STRING, BASE_NONE, NULL, 0x00, NULL, HFILL }}, |
1487 | 15 | { &hf_dbus_interface, { "Interface", "dbus.interface", |
1488 | 15 | FT_UINT_STRING, BASE_NONE, NULL, 0x00, NULL, HFILL }}, |
1489 | 15 | { &hf_dbus_member, { "Member", "dbus.member", |
1490 | 15 | FT_UINT_STRING, BASE_NONE, NULL, 0x00, NULL, HFILL }}, |
1491 | 15 | { &hf_dbus_error_name, { "Error name", "dbus.error_name", |
1492 | 15 | FT_UINT_STRING, BASE_NONE, NULL, 0x00, NULL, HFILL }}, |
1493 | 15 | { &hf_dbus_reply_serial, { "Reply serial", "dbus.reply_serial", |
1494 | 15 | FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }}, |
1495 | 15 | { &hf_dbus_destination, { "Destination", "dbus.destination", |
1496 | 15 | FT_UINT_STRING, BASE_NONE, NULL, 0x00, NULL, HFILL }}, |
1497 | 15 | { &hf_dbus_sender, { "Sender", "dbus.sender", |
1498 | 15 | FT_UINT_STRING, BASE_NONE, NULL, 0x00, NULL, HFILL }}, |
1499 | 15 | { &hf_dbus_signature, { "Signature", "dbus.signature", |
1500 | 15 | FT_UINT_STRING, BASE_NONE, NULL, 0x00, NULL, HFILL }}, |
1501 | 15 | { &hf_dbus_unix_fds, { "Unix FDs", "dbus.unix_fds", |
1502 | 15 | FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }}, |
1503 | 15 | { &hf_dbus_body, { "Body", "dbus.body", |
1504 | 15 | FT_BYTES, BASE_NO_DISPLAY_VALUE, NULL, 0x00, NULL, HFILL }}, |
1505 | 15 | { &hf_dbus_type_byte, { "Byte", "dbus.type.byte", |
1506 | 15 | FT_UINT8, BASE_DEC_HEX, NULL, 0x00, NULL, HFILL }}, |
1507 | 15 | { &hf_dbus_type_boolean, { "Boolean", "dbus.type.boolean", |
1508 | 15 | FT_BOOLEAN, BASE_NONE, NULL, 0x00, NULL, HFILL }}, |
1509 | 15 | { &hf_dbus_type_int16, { "Int16", "dbus.type.int16", |
1510 | 15 | FT_INT16, BASE_DEC, NULL, 0x00, NULL, HFILL }}, |
1511 | 15 | { &hf_dbus_type_uint16, { "Uint16", "dbus.type.uint16", |
1512 | 15 | FT_UINT16, BASE_DEC_HEX, NULL, 0x00, NULL, HFILL }}, |
1513 | 15 | { &hf_dbus_type_int32, { "Int32", "dbus.type.int32", |
1514 | 15 | FT_INT32, BASE_DEC, NULL, 0x00, NULL, HFILL }}, |
1515 | 15 | { &hf_dbus_type_uint32, { "Uint32", "dbus.type.uint32", |
1516 | 15 | FT_UINT32, BASE_DEC_HEX, NULL, 0x00, NULL, HFILL }}, |
1517 | 15 | { &hf_dbus_type_int64, { "Int64", "dbus.type.int64", |
1518 | 15 | FT_INT64, BASE_DEC, NULL, 0x00, NULL, HFILL }}, |
1519 | 15 | { &hf_dbus_type_uint64, { "Uint64", "dbus.type.uint64", |
1520 | 15 | FT_UINT64, BASE_DEC_HEX, NULL, 0x00, NULL, HFILL }}, |
1521 | 15 | { &hf_dbus_type_double, { "Double", "dbus.type.double", |
1522 | 15 | FT_DOUBLE, BASE_NONE, NULL, 0x00, NULL, HFILL }}, |
1523 | 15 | { &hf_dbus_type_string, { "String", "dbus.type.string", |
1524 | 15 | FT_UINT_STRING, BASE_NONE, NULL, 0x00, NULL, HFILL }}, |
1525 | 15 | { &hf_dbus_type_object_path, { "Object Path", "dbus.type.object_path", |
1526 | 15 | FT_UINT_STRING, BASE_NONE, NULL, 0x00, NULL, HFILL }}, |
1527 | 15 | { &hf_dbus_type_signature, { "Signature", "dbus.type.signature", |
1528 | 15 | FT_UINT_STRING, BASE_NONE, NULL, 0x00, NULL, HFILL }}, |
1529 | 15 | { &hf_dbus_type_array, { "Array", "dbus.type.array", |
1530 | 15 | FT_BYTES, BASE_NO_DISPLAY_VALUE, NULL, 0x00, NULL, HFILL }}, |
1531 | 15 | { &hf_dbus_type_array_length, { "Array Length", "dbus.type.array.length", |
1532 | 15 | FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }}, |
1533 | 15 | { &hf_dbus_type_struct, { "Struct", "dbus.type.struct", |
1534 | 15 | FT_BYTES, BASE_NO_DISPLAY_VALUE, NULL, 0x00, NULL, HFILL }}, |
1535 | 15 | { &hf_dbus_type_variant, { "Variant", "dbus.type.variant", |
1536 | 15 | FT_BYTES, BASE_NO_DISPLAY_VALUE, NULL, 0x00, NULL, HFILL }}, |
1537 | 15 | { &hf_dbus_type_variant_signature, { "Variant Signature", "dbus.type.variant.signature", |
1538 | 15 | FT_UINT_STRING, BASE_NONE, NULL, 0x00, NULL, HFILL }}, |
1539 | 15 | { &hf_dbus_type_dict_entry, { "Dict Entry", "dbus.type.dict_entry", |
1540 | 15 | FT_BYTES, BASE_NO_DISPLAY_VALUE, NULL, 0x00, NULL, HFILL }}, |
1541 | 15 | { &hf_dbus_type_dict_entry_key, { "Key", "dbus.type.dict_entry.key", |
1542 | 15 | FT_BYTES, BASE_NO_DISPLAY_VALUE, NULL, 0x00, NULL, HFILL }}, |
1543 | 15 | { &hf_dbus_type_unix_fd, { "Unix FD", "dbus.type.unix_fd", |
1544 | 15 | FT_UINT32, BASE_DEC, NULL, 0x00, NULL, HFILL }}, |
1545 | 15 | { &hf_dbus_response_in, { "Response In", "dbus.response_in", |
1546 | 15 | FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_RESPONSE), 0x0, |
1547 | 15 | "The response to this D-Bus call is in this frame", HFILL }}, |
1548 | 15 | { &hf_dbus_response_to, { "Response To", "dbus.response_to", |
1549 | 15 | FT_FRAMENUM, BASE_NONE, FRAMENUM_TYPE(FT_FRAMENUM_REQUEST), 0x0, |
1550 | 15 | "This is a response to the D-Bus call in this frame", HFILL }}, |
1551 | 15 | { &hf_dbus_response_time, { "Response Time", "dbus.response_time", |
1552 | 15 | FT_RELATIVE_TIME, BASE_NONE, NULL, 0x0, |
1553 | 15 | "The time between the Call and the Reply", HFILL }}, |
1554 | 15 | }; |
1555 | | |
1556 | 15 | static int *ett[] = { |
1557 | 15 | &ett_dbus, |
1558 | 15 | &ett_dbus_flags, |
1559 | 15 | &ett_dbus_header_field_array, |
1560 | 15 | &ett_dbus_header_field, |
1561 | 15 | &ett_dbus_body, |
1562 | 15 | &ett_dbus_type_array, |
1563 | 15 | &ett_dbus_type_struct, |
1564 | 15 | &ett_dbus_type_variant, |
1565 | 15 | &ett_dbus_type_dict_entry, |
1566 | 15 | }; |
1567 | | |
1568 | 15 | static ei_register_info ei[] = { |
1569 | 15 | { &ei_dbus_endianness_invalid, { "dbus.endianness.invalid", |
1570 | 15 | PI_PROTOCOL, PI_ERROR, "Invalid endianness flag", EXPFILL }}, |
1571 | 15 | { &ei_dbus_message_type_invalid, { "dbus.message_type.invalid", |
1572 | 15 | PI_PROTOCOL, PI_ERROR, "Invalid message type", EXPFILL }}, |
1573 | 15 | { &ei_dbus_message_type_unknown, { "dbus.message_type.unknown", |
1574 | 15 | PI_PROTOCOL, PI_WARN, "Unknown message type", EXPFILL }}, |
1575 | 15 | { &ei_dbus_version_invalid, { "dbus.version.invalid", |
1576 | 15 | PI_PROTOCOL, PI_ERROR, "Invalid version", EXPFILL }}, |
1577 | 15 | { &ei_dbus_serial_invalid, { "dbus.serial.invalid", |
1578 | 15 | PI_PROTOCOL, PI_ERROR, "Invalid serial", EXPFILL }}, |
1579 | 15 | { &ei_dbus_field_code_invalid, { "dbus.field_code.invalid", |
1580 | 15 | PI_PROTOCOL, PI_ERROR, "Invalid field code", EXPFILL }}, |
1581 | 15 | { &ei_dbus_required_header_field_missing, { "dbus.required_header_field_missing", |
1582 | 15 | PI_PROTOCOL, PI_ERROR, "Required header field is missing", EXPFILL }}, |
1583 | 15 | { &ei_dbus_padding_invalid, { "dbus.padding.invalid", |
1584 | 15 | PI_PROTOCOL, PI_ERROR, "Padding bytes must be zero", EXPFILL }}, |
1585 | 15 | { &ei_dbus_field_signature_wrong, { "dbus.field_signature_wrong", |
1586 | 15 | PI_PROTOCOL, PI_ERROR, "Wrong header field variant signature", EXPFILL }}, |
1587 | 15 | { &ei_dbus_interface_invalid, { "dbus.interface.invalid", |
1588 | 15 | PI_PROTOCOL, PI_ERROR, "Invalid interface name", EXPFILL }}, |
1589 | 15 | { &ei_dbus_member_invalid, { "dbus.member.invalid", |
1590 | 15 | PI_PROTOCOL, PI_ERROR, "Invalid member name", EXPFILL }}, |
1591 | 15 | { &ei_dbus_error_name_invalid, { "dbus.error_name.invalid", |
1592 | 15 | PI_PROTOCOL, PI_ERROR, "Invalid error name", EXPFILL }}, |
1593 | 15 | { &ei_dbus_bus_name_invalid, { "dbus.bus_name.invalid", |
1594 | 15 | PI_PROTOCOL, PI_ERROR, "Invalid bus name", EXPFILL }}, |
1595 | 15 | { &ei_dbus_type_boolean_invalid, { "dbus.type.boolean.invalid", |
1596 | 15 | PI_PROTOCOL, PI_ERROR, "Invalid boolean value", EXPFILL }}, |
1597 | 15 | { &ei_dbus_string_invalid, { "dbus.type.string.invalid", |
1598 | 15 | PI_PROTOCOL, PI_ERROR, "Invalid string value", EXPFILL }}, |
1599 | 15 | { &ei_dbus_type_signature_invalid, { "dbus.type.signature.invalid", |
1600 | 15 | PI_PROTOCOL, PI_ERROR, "Invalid signature", EXPFILL }}, |
1601 | 15 | { &ei_dbus_type_array_too_long, { "dbus.type.array.too_long", |
1602 | 15 | PI_PROTOCOL, PI_ERROR, "Array too long", EXPFILL }}, |
1603 | 15 | { &ei_dbus_type_array_content_out_of_bounds, { "dbus.type.array.content_out_of_bounds", |
1604 | 15 | PI_PROTOCOL, PI_ERROR, "Array content is out of bounds", EXPFILL }}, |
1605 | 15 | { &ei_dbus_type_object_path_invalid, { "dbus.type.object_path.invalid", |
1606 | 15 | PI_PROTOCOL, PI_ERROR, "Invalid object path", EXPFILL }}, |
1607 | 15 | { &ei_dbus_type_variant_signature_invalid, { "dbus.type.variant.signature.invalid", |
1608 | 15 | PI_PROTOCOL, PI_ERROR, "Invalid variant signature", EXPFILL }}, |
1609 | 15 | { &ei_dbus_nested_too_deeply, { "dbus.nested_too_deeply", |
1610 | 15 | PI_PROTOCOL, PI_ERROR, "Containers nested too deeply", EXPFILL }}, |
1611 | 15 | }; |
1612 | | |
1613 | 15 | expert_module_t *expert_dbus; |
1614 | 15 | module_t *dbus_module; |
1615 | | |
1616 | 15 | proto_dbus = proto_register_protocol("D-Bus", "D-Bus", "dbus"); |
1617 | 15 | proto_register_field_array(proto_dbus, hf, array_length(hf)); |
1618 | 15 | proto_register_subtree_array(ett, array_length(ett)); |
1619 | 15 | expert_dbus = expert_register_protocol(proto_dbus); |
1620 | 15 | expert_register_field_array(expert_dbus, ei, array_length(ei)); |
1621 | | |
1622 | 15 | dbus_handle = register_dissector("dbus", dissect_dbus, proto_dbus); |
1623 | 15 | dbus_handle_tcp = register_dissector("dbus.tcp", dissect_dbus_tcp, proto_dbus); |
1624 | | |
1625 | 15 | dbus_module = prefs_register_protocol(proto_dbus, NULL); |
1626 | 15 | prefs_register_bool_preference(dbus_module, "resolve_names", |
1627 | 15 | "Resolve unique names into well-known names", |
1628 | 15 | "Show the first inferred well-known bus name (e.g. \"com.example.MusicPlayer1\") instead of the unique connection name (e.g. \":1.18\"). Might be confusing if a connection owns more than one well-known name.", &dbus_resolve_names); |
1629 | | |
1630 | 15 | request_info_map = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), wmem_str_hash, g_str_equal); |
1631 | 15 | unique_name_map = wmem_map_new_autoreset(wmem_epan_scope(), wmem_file_scope(), wmem_str_hash, g_str_equal); |
1632 | 15 | } |
1633 | | |
1634 | | void |
1635 | 15 | proto_reg_handoff_dbus(void) { |
1636 | 15 | dissector_add_uint("wtap_encap", WTAP_ENCAP_DBUS, dbus_handle); |
1637 | 15 | dissector_add_for_decode_as_with_preference("tcp.port", dbus_handle_tcp); |
1638 | 15 | } |
1639 | | |
1640 | | /* |
1641 | | * Editor modelines - https://www.wireshark.org/tools/modelines.html |
1642 | | * |
1643 | | * Local variables: |
1644 | | * c-basic-offset: 8 |
1645 | | * tab-width: 8 |
1646 | | * indent-tabs-mode: t |
1647 | | * End: |
1648 | | * |
1649 | | * vi: set shiftwidth=8 tabstop=8 noexpandtab: |
1650 | | * :indentSize=8:tabSize=8:noTabs=false: |
1651 | | */ |