1 /* GLib testing framework examples and tests
2 *
3 * Copyright (C) 2008-2010 Red Hat, Inc.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
17 *
18 * Author: David Zeuthen <davidz@redhat.com>
19 */
20
21 #include <locale.h>
22 #include <gio/gio.h>
23
24 #include <string.h>
25 #ifndef _MSC_VER
26 #include <unistd.h>
27 #endif
28 #include <dbus/dbus.h>
29
30 /* ---------------------------------------------------------------------------------------------------- */
31
32 static void
hexdump(const guchar * str,gsize len)33 hexdump (const guchar *str, gsize len)
34 {
35 const guchar *data = (const guchar *) str;
36 guint n, m;
37
38 for (n = 0; n < len; n += 16)
39 {
40 g_printerr ("%04x: ", n);
41
42 for (m = n; m < n + 16; m++)
43 {
44 if (m > n && (m%4) == 0)
45 g_printerr (" ");
46 if (m < len)
47 g_printerr ("%02x ", data[m]);
48 else
49 g_printerr (" ");
50 }
51
52 g_printerr (" ");
53
54 for (m = n; m < len && m < n + 16; m++)
55 g_printerr ("%c", g_ascii_isprint (data[m]) ? data[m] : '.');
56
57 g_printerr ("\n");
58 }
59 }
60
61 /* ---------------------------------------------------------------------------------------------------- */
62
63 static gboolean
append_gv_to_dbus_iter(DBusMessageIter * iter,GVariant * value,GError ** error)64 append_gv_to_dbus_iter (DBusMessageIter *iter,
65 GVariant *value,
66 GError **error)
67 {
68 const GVariantType *type;
69
70 type = g_variant_get_type (value);
71 if (g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN))
72 {
73 dbus_bool_t v = g_variant_get_boolean (value);
74 dbus_message_iter_append_basic (iter, DBUS_TYPE_BOOLEAN, &v);
75 }
76 else if (g_variant_type_equal (type, G_VARIANT_TYPE_BYTE))
77 {
78 guint8 v = g_variant_get_byte (value);
79 dbus_message_iter_append_basic (iter, DBUS_TYPE_BYTE, &v);
80 }
81 else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT16))
82 {
83 gint16 v = g_variant_get_int16 (value);
84 dbus_message_iter_append_basic (iter, DBUS_TYPE_INT16, &v);
85 }
86 else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT16))
87 {
88 guint16 v = g_variant_get_uint16 (value);
89 dbus_message_iter_append_basic (iter, DBUS_TYPE_UINT16, &v);
90 }
91 else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT32))
92 {
93 gint32 v = g_variant_get_int32 (value);
94 dbus_message_iter_append_basic (iter, DBUS_TYPE_INT32, &v);
95 }
96 else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT32))
97 {
98 guint32 v = g_variant_get_uint32 (value);
99 dbus_message_iter_append_basic (iter, DBUS_TYPE_UINT32, &v);
100 }
101 else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT64))
102 {
103 gint64 v = g_variant_get_int64 (value);
104 dbus_message_iter_append_basic (iter, DBUS_TYPE_INT64, &v);
105 }
106 else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT64))
107 {
108 guint64 v = g_variant_get_uint64 (value);
109 dbus_message_iter_append_basic (iter, DBUS_TYPE_UINT64, &v);
110 }
111 else if (g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE))
112 {
113 gdouble v = g_variant_get_double (value);
114 dbus_message_iter_append_basic (iter, DBUS_TYPE_DOUBLE, &v);
115 }
116 else if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING))
117 {
118 const gchar *v = g_variant_get_string (value, NULL);
119 dbus_message_iter_append_basic (iter, DBUS_TYPE_STRING, &v);
120 }
121 else if (g_variant_type_equal (type, G_VARIANT_TYPE_OBJECT_PATH))
122 {
123 const gchar *v = g_variant_get_string (value, NULL);
124 dbus_message_iter_append_basic (iter, DBUS_TYPE_OBJECT_PATH, &v);
125 }
126 else if (g_variant_type_equal (type, G_VARIANT_TYPE_SIGNATURE))
127 {
128 const gchar *v = g_variant_get_string (value, NULL);
129 dbus_message_iter_append_basic (iter, DBUS_TYPE_SIGNATURE, &v);
130 }
131 else if (g_variant_type_is_variant (type))
132 {
133 DBusMessageIter sub;
134 GVariant *child;
135
136 child = g_variant_get_child_value (value, 0);
137 dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT,
138 g_variant_get_type_string (child),
139 &sub);
140 if (!append_gv_to_dbus_iter (&sub, child, error))
141 {
142 g_variant_unref (child);
143 goto fail;
144 }
145 dbus_message_iter_close_container (iter, &sub);
146 g_variant_unref (child);
147 }
148 else if (g_variant_type_is_array (type))
149 {
150 DBusMessageIter dbus_iter;
151 const gchar *type_string;
152 GVariantIter gv_iter;
153 GVariant *item;
154
155 type_string = g_variant_get_type_string (value);
156 type_string++; /* skip the 'a' */
157
158 dbus_message_iter_open_container (iter, DBUS_TYPE_ARRAY,
159 type_string, &dbus_iter);
160 g_variant_iter_init (&gv_iter, value);
161
162 while ((item = g_variant_iter_next_value (&gv_iter)))
163 {
164 if (!append_gv_to_dbus_iter (&dbus_iter, item, error))
165 {
166 goto fail;
167 }
168 }
169
170 dbus_message_iter_close_container (iter, &dbus_iter);
171 }
172 else if (g_variant_type_is_tuple (type))
173 {
174 DBusMessageIter dbus_iter;
175 GVariantIter gv_iter;
176 GVariant *item;
177
178 dbus_message_iter_open_container (iter, DBUS_TYPE_STRUCT,
179 NULL, &dbus_iter);
180 g_variant_iter_init (&gv_iter, value);
181
182 while ((item = g_variant_iter_next_value (&gv_iter)))
183 {
184 if (!append_gv_to_dbus_iter (&dbus_iter, item, error))
185 goto fail;
186 }
187
188 dbus_message_iter_close_container (iter, &dbus_iter);
189 }
190 else if (g_variant_type_is_dict_entry (type))
191 {
192 DBusMessageIter dbus_iter;
193 GVariant *key, *val;
194
195 dbus_message_iter_open_container (iter, DBUS_TYPE_DICT_ENTRY,
196 NULL, &dbus_iter);
197 key = g_variant_get_child_value (value, 0);
198 if (!append_gv_to_dbus_iter (&dbus_iter, key, error))
199 {
200 g_variant_unref (key);
201 goto fail;
202 }
203 g_variant_unref (key);
204
205 val = g_variant_get_child_value (value, 1);
206 if (!append_gv_to_dbus_iter (&dbus_iter, val, error))
207 {
208 g_variant_unref (val);
209 goto fail;
210 }
211 g_variant_unref (val);
212
213 dbus_message_iter_close_container (iter, &dbus_iter);
214 }
215 else
216 {
217 g_set_error (error,
218 G_IO_ERROR,
219 G_IO_ERROR_INVALID_ARGUMENT,
220 "Error serializing GVariant with type-string '%s' to a D-Bus message",
221 g_variant_get_type_string (value));
222 goto fail;
223 }
224
225 return TRUE;
226
227 fail:
228 return FALSE;
229 }
230
231 static gboolean
append_gv_to_dbus_message(DBusMessage * message,GVariant * value,GError ** error)232 append_gv_to_dbus_message (DBusMessage *message,
233 GVariant *value,
234 GError **error)
235 {
236 gboolean ret;
237 guint n;
238
239 ret = FALSE;
240
241 if (value != NULL)
242 {
243 DBusMessageIter iter;
244 GVariantIter gv_iter;
245 GVariant *item;
246
247 dbus_message_iter_init_append (message, &iter);
248
249 g_variant_iter_init (&gv_iter, value);
250 n = 0;
251 while ((item = g_variant_iter_next_value (&gv_iter)))
252 {
253 if (!append_gv_to_dbus_iter (&iter, item, error))
254 {
255 g_prefix_error (error,
256 "Error encoding in-arg %d: ",
257 n);
258 goto out;
259 }
260 n++;
261 }
262 }
263
264 ret = TRUE;
265
266 out:
267 return ret;
268 }
269
270 static void
print_gv_dbus_message(GVariant * value)271 print_gv_dbus_message (GVariant *value)
272 {
273 DBusMessage *message;
274 char *blob;
275 int blob_len;
276 GError *error;
277
278 message = dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_CALL);
279 dbus_message_set_serial (message, 0x41);
280 dbus_message_set_path (message, "/foo/bar");
281 dbus_message_set_member (message, "Member");
282
283 error = NULL;
284 if (!append_gv_to_dbus_message (message, value, &error))
285 {
286 g_printerr ("Error printing GVariant as DBusMessage: %s", error->message);
287 g_error_free (error);
288 goto out;
289 }
290
291 dbus_message_marshal (message, &blob, &blob_len);
292 g_printerr ("\n");
293 hexdump ((guchar *) blob, blob_len);
294 out:
295 dbus_message_unref (message);
296 }
297
298 /* ---------------------------------------------------------------------------------------------------- */
299
300 static void
dbus_1_message_append(GString * s,guint indent,DBusMessageIter * iter)301 dbus_1_message_append (GString *s,
302 guint indent,
303 DBusMessageIter *iter)
304 {
305 gint arg_type;
306 DBusMessageIter sub;
307
308 g_string_append_printf (s, "%*s", indent, "");
309
310 arg_type = dbus_message_iter_get_arg_type (iter);
311 switch (arg_type)
312 {
313 case DBUS_TYPE_BOOLEAN:
314 {
315 dbus_bool_t value;
316 dbus_message_iter_get_basic (iter, &value);
317 g_string_append_printf (s, "bool: %s\n", value ? "true" : "false");
318 break;
319 }
320
321 case DBUS_TYPE_BYTE:
322 {
323 guchar value;
324 dbus_message_iter_get_basic (iter, &value);
325 g_string_append_printf (s, "byte: 0x%02x\n", (guint) value);
326 break;
327 }
328
329 case DBUS_TYPE_INT16:
330 {
331 gint16 value;
332 dbus_message_iter_get_basic (iter, &value);
333 g_string_append_printf (s, "int16: %" G_GINT16_FORMAT "\n", value);
334 break;
335 }
336
337 case DBUS_TYPE_UINT16:
338 {
339 guint16 value;
340 dbus_message_iter_get_basic (iter, &value);
341 g_string_append_printf (s, "uint16: %" G_GUINT16_FORMAT "\n", value);
342 break;
343 }
344
345 case DBUS_TYPE_INT32:
346 {
347 gint32 value;
348 dbus_message_iter_get_basic (iter, &value);
349 g_string_append_printf (s, "int32: %" G_GINT32_FORMAT "\n", value);
350 break;
351 }
352
353 case DBUS_TYPE_UINT32:
354 {
355 guint32 value;
356 dbus_message_iter_get_basic (iter, &value);
357 g_string_append_printf (s, "uint32: %" G_GUINT32_FORMAT "\n", value);
358 break;
359 }
360
361 case DBUS_TYPE_INT64:
362 {
363 gint64 value;
364 dbus_message_iter_get_basic (iter, &value);
365 g_string_append_printf (s, "int64: %" G_GINT64_FORMAT "\n", value);
366 break;
367 }
368
369 case DBUS_TYPE_UINT64:
370 {
371 guint64 value;
372 dbus_message_iter_get_basic (iter, &value);
373 g_string_append_printf (s, "uint64: %" G_GUINT64_FORMAT "\n", value);
374 break;
375 }
376
377 case DBUS_TYPE_DOUBLE:
378 {
379 gdouble value;
380 dbus_message_iter_get_basic (iter, &value);
381 g_string_append_printf (s, "double: %f\n", value);
382 break;
383 }
384
385 case DBUS_TYPE_STRING:
386 {
387 const gchar *value;
388 dbus_message_iter_get_basic (iter, &value);
389 g_string_append_printf (s, "string: '%s'\n", value);
390 break;
391 }
392
393 case DBUS_TYPE_OBJECT_PATH:
394 {
395 const gchar *value;
396 dbus_message_iter_get_basic (iter, &value);
397 g_string_append_printf (s, "object_path: '%s'\n", value);
398 break;
399 }
400
401 case DBUS_TYPE_SIGNATURE:
402 {
403 const gchar *value;
404 dbus_message_iter_get_basic (iter, &value);
405 g_string_append_printf (s, "signature: '%s'\n", value);
406 break;
407 }
408
409 #ifdef DBUS_TYPE_UNIX_FD
410 case DBUS_TYPE_UNIX_FD:
411 {
412 /* unfortunately there's currently no way to get just the
413 * protocol value, since dbus_message_iter_get_basic() wants
414 * to be 'helpful' and dup the fd for the user...
415 */
416 g_string_append (s, "unix-fd: (not extracted)\n");
417 break;
418 }
419 #endif
420
421 case DBUS_TYPE_VARIANT:
422 g_string_append_printf (s, "variant:\n");
423 dbus_message_iter_recurse (iter, &sub);
424 while (dbus_message_iter_get_arg_type (&sub))
425 {
426 dbus_1_message_append (s, indent + 2, &sub);
427 dbus_message_iter_next (&sub);
428 }
429 break;
430
431 case DBUS_TYPE_ARRAY:
432 g_string_append_printf (s, "array:\n");
433 dbus_message_iter_recurse (iter, &sub);
434 while (dbus_message_iter_get_arg_type (&sub))
435 {
436 dbus_1_message_append (s, indent + 2, &sub);
437 dbus_message_iter_next (&sub);
438 }
439 break;
440
441 case DBUS_TYPE_STRUCT:
442 g_string_append_printf (s, "struct:\n");
443 dbus_message_iter_recurse (iter, &sub);
444 while (dbus_message_iter_get_arg_type (&sub))
445 {
446 dbus_1_message_append (s, indent + 2, &sub);
447 dbus_message_iter_next (&sub);
448 }
449 break;
450
451 case DBUS_TYPE_DICT_ENTRY:
452 g_string_append_printf (s, "dict_entry:\n");
453 dbus_message_iter_recurse (iter, &sub);
454 while (dbus_message_iter_get_arg_type (&sub))
455 {
456 dbus_1_message_append (s, indent + 2, &sub);
457 dbus_message_iter_next (&sub);
458 }
459 break;
460
461 default:
462 g_printerr ("Error serializing D-Bus message to GVariant. Unsupported arg type '%c' (%d)",
463 arg_type,
464 arg_type);
465 g_assert_not_reached ();
466 break;
467 }
468 }
469
470 static gchar *
dbus_1_message_print(DBusMessage * message)471 dbus_1_message_print (DBusMessage *message)
472 {
473 GString *s;
474 guint n;
475 DBusMessageIter iter;
476
477 s = g_string_new (NULL);
478 n = 0;
479 dbus_message_iter_init (message, &iter);
480 while (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_INVALID)
481 {
482 g_string_append_printf (s, "value %d: ", n);
483 dbus_1_message_append (s, 2, &iter);
484 dbus_message_iter_next (&iter);
485 n++;
486 }
487
488 return g_string_free (s, FALSE);
489 }
490
491 /* ---------------------------------------------------------------------------------------------------- */
492
493 static gchar *
get_body_signature(GVariant * value)494 get_body_signature (GVariant *value)
495 {
496 const gchar *s;
497 gsize len;
498 gchar *ret;
499
500 if (value == NULL)
501 {
502 ret = g_strdup ("");
503 goto out;
504 }
505
506 s = g_variant_get_type_string (value);
507 len = strlen (s);
508 g_assert (len >= 2);
509
510 ret = g_strndup (s + 1, len - 2);
511
512 out:
513 return ret;
514 }
515
516 /* If @value is floating, this assumes ownership. */
517 static gchar *
get_and_check_serialization(GVariant * value)518 get_and_check_serialization (GVariant *value)
519 {
520 guchar *blob;
521 gsize blob_size;
522 DBusMessage *dbus_1_message;
523 GDBusMessage *message;
524 GDBusMessage *recovered_message;
525 GError *error;
526 DBusError dbus_error;
527 gchar *s = NULL;
528 guint n;
529
530 message = g_dbus_message_new ();
531 g_dbus_message_set_body (message, value);
532 g_dbus_message_set_message_type (message, G_DBUS_MESSAGE_TYPE_METHOD_CALL);
533 g_dbus_message_set_serial (message, 0x41);
534 s = get_body_signature (value);
535 g_dbus_message_set_header (message, G_DBUS_MESSAGE_HEADER_FIELD_PATH, g_variant_new_object_path ("/foo/bar"));
536 g_dbus_message_set_header (message, G_DBUS_MESSAGE_HEADER_FIELD_MEMBER, g_variant_new_string ("Member"));
537 g_dbus_message_set_header (message, G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE, g_variant_new_signature (s));
538 g_free (s);
539
540 /* First check that the serialization to the D-Bus wire format is correct - do this for both byte orders */
541 for (n = 0; n < 2; n++)
542 {
543 GDBusMessageByteOrder byte_order;
544 switch (n)
545 {
546 case 0:
547 byte_order = G_DBUS_MESSAGE_BYTE_ORDER_BIG_ENDIAN;
548 break;
549 case 1:
550 byte_order = G_DBUS_MESSAGE_BYTE_ORDER_LITTLE_ENDIAN;
551 break;
552 case 2:
553 g_assert_not_reached ();
554 break;
555 }
556 g_dbus_message_set_byte_order (message, byte_order);
557
558 error = NULL;
559 blob = g_dbus_message_to_blob (message,
560 &blob_size,
561 G_DBUS_CAPABILITY_FLAGS_NONE,
562 &error);
563 g_assert_no_error (error);
564 g_assert (blob != NULL);
565
566 switch (byte_order)
567 {
568 case G_DBUS_MESSAGE_BYTE_ORDER_BIG_ENDIAN:
569 g_assert_cmpint (blob[0], ==, 'B');
570 break;
571 case G_DBUS_MESSAGE_BYTE_ORDER_LITTLE_ENDIAN:
572 g_assert_cmpint (blob[0], ==, 'l');
573 break;
574 }
575
576 dbus_error_init (&dbus_error);
577 dbus_1_message = dbus_message_demarshal ((char *) blob, blob_size, &dbus_error);
578 if (dbus_error_is_set (&dbus_error))
579 {
580 g_printerr ("Error calling dbus_message_demarshal() on this blob: %s: %s\n",
581 dbus_error.name,
582 dbus_error.message);
583 hexdump (blob, blob_size);
584 dbus_error_free (&dbus_error);
585
586 s = g_variant_print (value, TRUE);
587 g_printerr ("\nThe blob was generated from the following GVariant value:\n%s\n\n", s);
588 g_free (s);
589
590 g_printerr ("If the blob was encoded using DBusMessageIter, the payload would have been:\n");
591 print_gv_dbus_message (value);
592
593 g_assert_not_reached ();
594 }
595
596 s = dbus_1_message_print (dbus_1_message);
597 dbus_message_unref (dbus_1_message);
598
599 /* Then serialize back and check that the body is identical */
600
601 error = NULL;
602 recovered_message = g_dbus_message_new_from_blob (blob,
603 blob_size,
604 G_DBUS_CAPABILITY_FLAGS_NONE,
605 &error);
606 g_assert_no_error (error);
607 g_assert (recovered_message != NULL);
608
609 if (value == NULL)
610 {
611 g_assert (g_dbus_message_get_body (recovered_message) == NULL);
612 }
613 else
614 {
615 g_assert (g_dbus_message_get_body (recovered_message) != NULL);
616 g_assert_cmpvariant (g_dbus_message_get_body (recovered_message), value);
617 }
618 g_object_unref (recovered_message);
619 g_free (blob);
620 }
621
622 g_object_unref (message);
623
624 return g_steal_pointer (&s);
625 }
626
627 /* If @value is floating, this assumes ownership. */
628 static void
check_serialization(GVariant * value,const gchar * expected_dbus_1_output)629 check_serialization (GVariant *value,
630 const gchar *expected_dbus_1_output)
631 {
632 gchar *s = get_and_check_serialization (value);
633 g_assert_cmpstr (s, ==, expected_dbus_1_output);
634 g_free (s);
635 }
636
637 static void
test_message_serialize_basic(void)638 test_message_serialize_basic (void)
639 {
640 check_serialization (NULL, "");
641
642 check_serialization (g_variant_new ("(sogybnqiuxtd)",
643 "this is a string",
644 "/this/is/a/path",
645 "sad",
646 42,
647 TRUE,
648 -42,
649 60000,
650 -44,
651 100000,
652 -(G_GUINT64_CONSTANT(2)<<34),
653 G_GUINT64_CONSTANT(0xffffffffffffffff),
654 42.5),
655 "value 0: string: 'this is a string'\n"
656 "value 1: object_path: '/this/is/a/path'\n"
657 "value 2: signature: 'sad'\n"
658 "value 3: byte: 0x2a\n"
659 "value 4: bool: true\n"
660 "value 5: int16: -42\n"
661 "value 6: uint16: 60000\n"
662 "value 7: int32: -44\n"
663 "value 8: uint32: 100000\n"
664 "value 9: int64: -34359738368\n"
665 "value 10: uint64: 18446744073709551615\n"
666 "value 11: double: 42.500000\n");
667 }
668
669 /* ---------------------------------------------------------------------------------------------------- */
670
671 static void
test_message_serialize_complex(void)672 test_message_serialize_complex (void)
673 {
674 GError *error;
675 GVariant *value;
676 guint i;
677 gchar *serialization = NULL;
678
679 error = NULL;
680
681 value = g_variant_parse (G_VARIANT_TYPE ("(aia{ss})"),
682 "([1, 2, 3], {'one': 'white', 'two': 'black'})",
683 NULL, NULL, &error);
684 g_assert_no_error (error);
685 g_assert (value != NULL);
686 check_serialization (value,
687 "value 0: array:\n"
688 " int32: 1\n"
689 " int32: 2\n"
690 " int32: 3\n"
691 "value 1: array:\n"
692 " dict_entry:\n"
693 " string: 'one'\n"
694 " string: 'white'\n"
695 " dict_entry:\n"
696 " string: 'two'\n"
697 " string: 'black'\n");
698 g_variant_unref (value);
699
700 value = g_variant_parse (G_VARIANT_TYPE ("(sa{sv}as)"),
701 "('01234567890123456', {}, ['Something'])",
702 NULL, NULL, &error);
703 g_assert_no_error (error);
704 g_assert (value != NULL);
705 check_serialization (value,
706 "value 0: string: '01234567890123456'\n"
707 "value 1: array:\n"
708 "value 2: array:\n"
709 " string: 'Something'\n");
710 g_variant_unref (value);
711
712 /* https://bugzilla.gnome.org/show_bug.cgi?id=621838 */
713 check_serialization (g_variant_new_parsed ("(@aay [], {'cwd': <'/home/davidz/Hacking/glib/gio/tests'>})"),
714 "value 0: array:\n"
715 "value 1: array:\n"
716 " dict_entry:\n"
717 " string: 'cwd'\n"
718 " variant:\n"
719 " string: '/home/davidz/Hacking/glib/gio/tests'\n");
720
721 #ifdef DBUS_TYPE_UNIX_FD
722 value = g_variant_parse (G_VARIANT_TYPE ("(hah)"),
723 "(42, [43, 44])",
724 NULL, NULL, &error);
725 g_assert_no_error (error);
726 g_assert (value != NULL);
727 /* about (not extracted), see comment in DBUS_TYPE_UNIX_FD case in
728 * dbus_1_message_append() above.
729 */
730 check_serialization (value,
731 "value 0: unix-fd: (not extracted)\n"
732 "value 1: array:\n"
733 " unix-fd: (not extracted)\n"
734 " unix-fd: (not extracted)\n");
735 g_variant_unref (value);
736 #endif
737
738 /* Deep nesting of variants (just below the recursion limit). */
739 value = g_variant_new_string ("buried");
740 for (i = 0; i < 64; i++)
741 value = g_variant_new_variant (value);
742 value = g_variant_new_tuple (&value, 1);
743
744 serialization = get_and_check_serialization (value);
745 g_assert_nonnull (serialization);
746 g_assert_true (g_str_has_prefix (serialization,
747 "value 0: variant:\n"
748 " variant:\n"
749 " variant:\n"));
750 g_free (serialization);
751
752 /* Deep nesting of arrays and structs (just below the recursion limit).
753 * See https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-marshaling-signature */
754 value = g_variant_new_string ("hello");
755 for (i = 0; i < 32; i++)
756 value = g_variant_new_tuple (&value, 1);
757 for (i = 0; i < 32; i++)
758 value = g_variant_new_array (NULL, &value, 1);
759 value = g_variant_new_tuple (&value, 1);
760
761 serialization = get_and_check_serialization (value);
762 g_assert_nonnull (serialization);
763 g_assert_true (g_str_has_prefix (serialization,
764 "value 0: array:\n"
765 " array:\n"
766 " array:\n"));
767 g_free (serialization);
768 }
769
770
771 /* ---------------------------------------------------------------------------------------------------- */
772
773 static void
replace(char * blob,gsize len,const char * before,const char * after)774 replace (char *blob,
775 gsize len,
776 const char *before,
777 const char *after)
778 {
779 gsize i;
780 gsize slen = strlen (before) + 1;
781
782 g_assert_cmpuint (strlen (before), ==, strlen (after));
783 g_assert_cmpuint (len, >=, slen);
784
785 for (i = 0; i < (len - slen + 1); i++)
786 {
787 if (memcmp (blob + i, before, slen) == 0)
788 memcpy (blob + i, after, slen);
789 }
790 }
791
792 static void
test_message_serialize_invalid(void)793 test_message_serialize_invalid (void)
794 {
795 guint n;
796
797 /* Other things we could check (note that GDBus _does_ check for all
798 * these things - we just don't have test-suit coverage for it)
799 *
800 * - array exceeding 64 MiB (2^26 bytes) - unfortunately libdbus-1 checks
801 * this, e.g.
802 *
803 * process 19620: arguments to dbus_message_iter_append_fixed_array() were incorrect,
804 * assertion "n_elements <= DBUS_MAXIMUM_ARRAY_LENGTH / _dbus_type_get_alignment (element_type)"
805 * failed in file dbus-message.c line 2344.
806 * This is normally a bug in some application using the D-Bus library.
807 * D-Bus not built with -rdynamic so unable to print a backtrace
808 * Aborted (core dumped)
809 *
810 * - message exceeding 128 MiB (2^27 bytes)
811 *
812 * - endianness, message type, flags, protocol version
813 */
814
815 for (n = 0; n < 3; n++)
816 {
817 GDBusMessage *message;
818 GError *error;
819 DBusMessage *dbus_message;
820 char *blob;
821 int blob_len;
822 /* these are in pairs with matching length */
823 const gchar *valid_utf8_str = "this is valid...";
824 const gchar *invalid_utf8_str = "this is invalid\xff";
825 const gchar *valid_signature = "a{sv}a{sv}a{sv}aiai";
826 const gchar *invalid_signature = "not valid signature";
827 const gchar *valid_object_path = "/this/is/a/valid/dbus/object/path";
828 const gchar *invalid_object_path = "/this/is/not a valid object path!";
829
830 dbus_message = dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_CALL);
831 dbus_message_set_serial (dbus_message, 0x41);
832 dbus_message_set_path (dbus_message, "/foo/bar");
833 dbus_message_set_member (dbus_message, "Member");
834 switch (n)
835 {
836 case 0:
837 /* invalid UTF-8 */
838 dbus_message_append_args (dbus_message,
839 DBUS_TYPE_STRING, &valid_utf8_str,
840 DBUS_TYPE_INVALID);
841 break;
842
843 case 1:
844 /* invalid object path */
845 dbus_message_append_args (dbus_message,
846 DBUS_TYPE_OBJECT_PATH, &valid_object_path,
847 DBUS_TYPE_INVALID);
848 break;
849
850 case 2:
851 /* invalid signature */
852 dbus_message_append_args (dbus_message,
853 DBUS_TYPE_SIGNATURE, &valid_signature,
854 DBUS_TYPE_INVALID);
855 break;
856
857 default:
858 g_assert_not_reached ();
859 break;
860 }
861 dbus_message_marshal (dbus_message, &blob, &blob_len);
862 /* hack up the message to be invalid by replacing each valid string
863 * with its invalid counterpart */
864 replace (blob, blob_len, valid_utf8_str, invalid_utf8_str);
865 replace (blob, blob_len, valid_object_path, invalid_object_path);
866 replace (blob, blob_len, valid_signature, invalid_signature);
867
868 error = NULL;
869 message = g_dbus_message_new_from_blob ((guchar *) blob,
870 blob_len,
871 G_DBUS_CAPABILITY_FLAGS_NONE,
872 &error);
873 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
874 g_error_free (error);
875 g_assert (message == NULL);
876
877 dbus_free (blob);
878 dbus_message_unref (dbus_message);
879 }
880
881 }
882
883 /* ---------------------------------------------------------------------------------------------------- */
884
885 static void
test_message_serialize_header_checks(void)886 test_message_serialize_header_checks (void)
887 {
888 GDBusMessage *message;
889 GDBusMessage *reply;
890 GError *error = NULL;
891 guchar *blob;
892 gsize blob_size;
893
894 /*
895 * check we can't serialize messages with INVALID type
896 */
897 message = g_dbus_message_new ();
898 blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
899 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
900 g_assert_cmpstr (error->message, ==, "Cannot serialize message: type is INVALID");
901 g_clear_error (&error);
902 g_assert_null (blob);
903 g_object_unref (message);
904
905 /*
906 * check that we can't serialize messages with SIGNATURE set to a non-signature-typed value
907 */
908 message = g_dbus_message_new_signal ("/the/path", "The.Interface", "TheMember");
909 g_dbus_message_set_header (message, G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE, g_variant_new_boolean (FALSE));
910 blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
911
912 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
913 g_assert_cmpstr (error->message, ==, "Signature header found but is not of type signature");
914 g_assert_null (blob);
915
916 g_clear_error (&error);
917 g_clear_object (&message);
918
919 /*
920 * check we can't serialize signal messages with INTERFACE, PATH or MEMBER unset / set to reserved value
921 */
922 message = g_dbus_message_new_signal ("/the/path", "The.Interface", "TheMember");
923 /* ----- */
924 /* interface NULL => error */
925 g_dbus_message_set_interface (message, NULL);
926 blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
927 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
928 g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: PATH, INTERFACE or MEMBER header field is missing");
929 g_clear_error (&error);
930 g_assert_null (blob);
931 /* interface reserved value => error */
932 g_dbus_message_set_interface (message, "org.freedesktop.DBus.Local");
933 blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
934 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
935 g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: The INTERFACE header field is using the reserved value org.freedesktop.DBus.Local");
936 g_clear_error (&error);
937 g_assert_null (blob);
938 /* reset interface */
939 g_dbus_message_set_interface (message, "The.Interface");
940 /* ----- */
941 /* path NULL => error */
942 g_dbus_message_set_path (message, NULL);
943 blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
944 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
945 g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: PATH, INTERFACE or MEMBER header field is missing");
946 g_clear_error (&error);
947 g_assert_null (blob);
948 /* path reserved value => error */
949 g_dbus_message_set_path (message, "/org/freedesktop/DBus/Local");
950 blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
951 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
952 g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: The PATH header field is using the reserved value /org/freedesktop/DBus/Local");
953 g_clear_error (&error);
954 g_assert_null (blob);
955 /* reset path */
956 g_dbus_message_set_path (message, "/the/path");
957 /* ----- */
958 /* member NULL => error */
959 g_dbus_message_set_member (message, NULL);
960 blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
961 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
962 g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: PATH, INTERFACE or MEMBER header field is missing");
963 g_clear_error (&error);
964 g_assert_null (blob);
965 /* reset member */
966 g_dbus_message_set_member (message, "TheMember");
967 /* ----- */
968 /* done */
969 g_object_unref (message);
970
971 /*
972 * check that we can't serialize method call messages with PATH or MEMBER unset
973 */
974 message = g_dbus_message_new_method_call (NULL, "/the/path", NULL, "TheMember");
975 /* ----- */
976 /* path NULL => error */
977 g_dbus_message_set_path (message, NULL);
978 blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
979 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
980 g_assert_cmpstr (error->message, ==, "Cannot serialize message: METHOD_CALL message: PATH or MEMBER header field is missing");
981 g_clear_error (&error);
982 g_assert_null (blob);
983 /* reset path */
984 g_dbus_message_set_path (message, "/the/path");
985 /* ----- */
986 /* member NULL => error */
987 g_dbus_message_set_member (message, NULL);
988 blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
989 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
990 g_assert_cmpstr (error->message, ==, "Cannot serialize message: METHOD_CALL message: PATH or MEMBER header field is missing");
991 g_clear_error (&error);
992 g_assert_null (blob);
993 /* reset member */
994 g_dbus_message_set_member (message, "TheMember");
995 /* ----- */
996 /* done */
997 g_object_unref (message);
998
999 /*
1000 * check that we can't serialize method reply messages with REPLY_SERIAL unset
1001 */
1002 message = g_dbus_message_new_method_call (NULL, "/the/path", NULL, "TheMember");
1003 g_dbus_message_set_serial (message, 42);
1004 /* method reply */
1005 reply = g_dbus_message_new_method_reply (message);
1006 g_assert_cmpint (g_dbus_message_get_reply_serial (reply), ==, 42);
1007 g_dbus_message_set_header (reply, G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL, NULL);
1008 blob = g_dbus_message_to_blob (reply, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
1009 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1010 g_assert_cmpstr (error->message, ==, "Cannot serialize message: METHOD_RETURN message: REPLY_SERIAL header field is missing");
1011 g_clear_error (&error);
1012 g_assert_null (blob);
1013 g_object_unref (reply);
1014 /* method error - first nuke ERROR_NAME, then REPLY_SERIAL */
1015 reply = g_dbus_message_new_method_error (message, "Some.Error.Name", "the message");
1016 g_assert_cmpint (g_dbus_message_get_reply_serial (reply), ==, 42);
1017 /* nuke ERROR_NAME */
1018 g_dbus_message_set_error_name (reply, NULL);
1019 blob = g_dbus_message_to_blob (reply, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
1020 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1021 g_assert_cmpstr (error->message, ==, "Cannot serialize message: ERROR message: REPLY_SERIAL or ERROR_NAME header field is missing");
1022 g_clear_error (&error);
1023 g_assert_null (blob);
1024 /* reset ERROR_NAME */
1025 g_dbus_message_set_error_name (reply, "Some.Error.Name");
1026 /* nuke REPLY_SERIAL */
1027 g_dbus_message_set_header (reply, G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL, NULL);
1028 blob = g_dbus_message_to_blob (reply, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
1029 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1030 g_assert_cmpstr (error->message, ==, "Cannot serialize message: ERROR message: REPLY_SERIAL or ERROR_NAME header field is missing");
1031 g_clear_error (&error);
1032 g_assert_null (blob);
1033 g_object_unref (reply);
1034 g_object_unref (message);
1035 }
1036
1037 /* ---------------------------------------------------------------------------------------------------- */
1038
1039 static void
test_message_parse_empty_arrays_of_arrays(void)1040 test_message_parse_empty_arrays_of_arrays (void)
1041 {
1042 GVariant *body;
1043 GError *error = NULL;
1044
1045 g_test_bug ("673612");
1046 /* These three-element array of empty arrays were previously read back as a
1047 * two-element array of empty arrays, due to sometimes erroneously skipping
1048 * four bytes to align for the eight-byte-aligned grandchild types (x and
1049 * dict_entry).
1050 */
1051 body = g_variant_parse (G_VARIANT_TYPE ("(aaax)"),
1052 "([@aax [], [], []],)", NULL, NULL, &error);
1053 g_assert_no_error (error);
1054 check_serialization (body,
1055 "value 0: array:\n"
1056 " array:\n"
1057 " array:\n"
1058 " array:\n");
1059 g_variant_unref (body);
1060
1061 body = g_variant_parse (G_VARIANT_TYPE ("(aaa{uu})"),
1062 "([@aa{uu} [], [], []],)", NULL, NULL, &error);
1063 g_assert_no_error (error);
1064 check_serialization (body,
1065 "value 0: array:\n"
1066 " array:\n"
1067 " array:\n"
1068 " array:\n");
1069 g_variant_unref (body);
1070
1071 /* Due to the same bug, g_dbus_message_new_from_blob() would fail for this
1072 * message because it would try to read past the end of the string. Hence,
1073 * sending this to an application would make it fall off the bus. */
1074 body = g_variant_parse (G_VARIANT_TYPE ("(a(aa{sv}as))"),
1075 "([ ([], []),"
1076 " ([], []),"
1077 " ([], [])],)", NULL, NULL, &error);
1078 g_assert_no_error (error);
1079 check_serialization (body,
1080 "value 0: array:\n"
1081 " struct:\n"
1082 " array:\n"
1083 " array:\n"
1084 " struct:\n"
1085 " array:\n"
1086 " array:\n"
1087 " struct:\n"
1088 " array:\n"
1089 " array:\n");
1090 g_variant_unref (body);
1091 }
1092
1093 /* ---------------------------------------------------------------------------------------------------- */
1094
1095 static void
test_message_serialize_double_array(void)1096 test_message_serialize_double_array (void)
1097 {
1098 GVariantBuilder builder;
1099 GVariant *body;
1100
1101 g_test_bug ("732754");
1102
1103 g_variant_builder_init (&builder, G_VARIANT_TYPE ("ad"));
1104 g_variant_builder_add (&builder, "d", (gdouble)0.0);
1105 g_variant_builder_add (&builder, "d", (gdouble)8.0);
1106 g_variant_builder_add (&builder, "d", (gdouble)22.0);
1107 g_variant_builder_add (&builder, "d", (gdouble)0.0);
1108 body = g_variant_new ("(@ad)", g_variant_builder_end (&builder));
1109 check_serialization (body,
1110 "value 0: array:\n"
1111 " double: 0.000000\n"
1112 " double: 8.000000\n"
1113 " double: 22.000000\n"
1114 " double: 0.000000\n");
1115 }
1116
1117 /* ---------------------------------------------------------------------------------------------------- */
1118
1119 /* Test that an invalid header in a D-Bus message (specifically, with a type
1120 * which doesn’t match what’s expected for the given header) is gracefully
1121 * handled with an error rather than a crash.
1122 * The set of bytes here come directly from fuzzer output. */
1123 static void
test_message_parse_non_signature_header(void)1124 test_message_parse_non_signature_header (void)
1125 {
1126 const guint8 data[] = {
1127 'l', /* little-endian byte order */
1128 0x04, /* message type */
1129 0x0f, /* message flags */
1130 0x01, /* major protocol version */
1131 0x00, 0x00, 0x00, 0x00, /* body length */
1132 0x00, 0x00, 0x00, 0xbc, /* message serial */
1133 /* a{yv} of header fields:
1134 * (things start to be invalid below here) */
1135 0x02, 0x00, 0x00, 0x00, /* array length (in bytes) */
1136 G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE, /* array key */
1137 /* Variant array value: */
1138 0x04, /* signature length */
1139 'd', 0x00, 0x00, 'F', /* signature (invalid) */
1140 0x00, /* nul terminator */
1141 /* (Variant array value payload missing) */
1142 /* (message body length missing) */
1143 };
1144 gsize size = sizeof (data);
1145 GDBusMessage *message = NULL;
1146 GError *local_error = NULL;
1147
1148 message = g_dbus_message_new_from_blob ((guchar *) data, size,
1149 G_DBUS_CAPABILITY_FLAGS_NONE,
1150 &local_error);
1151 g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1152 g_assert_null (message);
1153
1154 g_clear_error (&local_error);
1155 }
1156
1157 /* ---------------------------------------------------------------------------------------------------- */
1158
1159 /* Test that an invalid header in a D-Bus message (specifically, containing a
1160 * variant with an empty type signature) is gracefully handled with an error
1161 * rather than a crash. The set of bytes here come directly from fuzzer
1162 * output. */
1163 static void
test_message_parse_empty_signature_header(void)1164 test_message_parse_empty_signature_header (void)
1165 {
1166 const guint8 data[] = {
1167 'l', /* little-endian byte order */
1168 0x20, /* message type */
1169 0x20, /* message flags */
1170 0x01, /* major protocol version */
1171 0x20, 0x20, 0x20, 0x00, /* body length (invalid) */
1172 0x20, 0x20, 0x20, 0x20, /* message serial */
1173 /* a{yv} of header fields:
1174 * (things start to be even more invalid below here) */
1175 0x20, 0x20, 0x20, 0x00, /* array length (in bytes) */
1176 0x20, /* array key */
1177 /* Variant array value: */
1178 0x00, /* signature length */
1179 0x00, /* nul terminator */
1180 /* (Variant array value payload missing) */
1181 /* (message body length missing) */
1182 };
1183 gsize size = sizeof (data);
1184 GDBusMessage *message = NULL;
1185 GError *local_error = NULL;
1186
1187 message = g_dbus_message_new_from_blob ((guchar *) data, size,
1188 G_DBUS_CAPABILITY_FLAGS_NONE,
1189 &local_error);
1190 g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1191 g_assert_null (message);
1192
1193 g_clear_error (&local_error);
1194 }
1195
1196 /* ---------------------------------------------------------------------------------------------------- */
1197
1198 /* Test that an invalid header in a D-Bus message (specifically, containing a
1199 * variant with a type signature containing multiple complete types) is
1200 * gracefully handled with an error rather than a crash. The set of bytes here
1201 * come directly from fuzzer output. */
1202 static void
test_message_parse_multiple_signature_header(void)1203 test_message_parse_multiple_signature_header (void)
1204 {
1205 const guint8 data[] = {
1206 'l', /* little-endian byte order */
1207 0x20, /* message type */
1208 0x20, /* message flags */
1209 0x01, /* major protocol version */
1210 0x20, 0x20, 0x20, 0x00, /* body length (invalid) */
1211 0x20, 0x20, 0x20, 0x20, /* message serial */
1212 /* a{yv} of header fields:
1213 * (things start to be even more invalid below here) */
1214 0x20, 0x20, 0x20, 0x00, /* array length (in bytes) */
1215 0x20, /* array key */
1216 /* Variant array value: */
1217 0x02, /* signature length */
1218 'b', 'b', /* two complete types */
1219 0x00, /* nul terminator */
1220 /* (Variant array value payload missing) */
1221 /* (message body length missing) */
1222 };
1223 gsize size = sizeof (data);
1224 GDBusMessage *message = NULL;
1225 GError *local_error = NULL;
1226
1227 message = g_dbus_message_new_from_blob ((guchar *) data, size,
1228 G_DBUS_CAPABILITY_FLAGS_NONE,
1229 &local_error);
1230 g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1231 g_assert_null (message);
1232
1233 g_clear_error (&local_error);
1234 }
1235
1236 /* ---------------------------------------------------------------------------------------------------- */
1237
1238 /* Test that an invalid header in a D-Bus message (specifically, containing a
1239 * variant with a valid type signature that is too long to be a valid
1240 * #GVariantType due to exceeding the array nesting limits) is gracefully
1241 * handled with an error rather than a crash. The set of bytes here come
1242 * directly from fuzzer output. */
1243 static void
test_message_parse_over_long_signature_header(void)1244 test_message_parse_over_long_signature_header (void)
1245 {
1246 const guint8 data[] = {
1247 'l', /* little-endian byte order */
1248 0x20, /* message type */
1249 0x20, /* message flags */
1250 0x01, /* major protocol version */
1251 0x20, 0x20, 0x20, 0x01, /* body length (invalid) */
1252 0x20, 0x20, 0x20, 0x20, /* message serial */
1253 /* a{yv} of header fields:
1254 * (things start to be even more invalid below here) */
1255 0x20, 0x00, 0x00, 0x00, /* array length (in bytes) */
1256 0x08, /* array key */
1257 /* Variant array value: */
1258 0x04, /* signature length */
1259 'g', 0x00, 0x20, 0x20, /* one complete type plus some rubbish */
1260 0x00, /* nul terminator */
1261 /* (Variant array value payload) */
1262 /* Critically, this contains 128 nested ‘a’s, which exceeds
1263 * %G_VARIANT_MAX_RECURSION_DEPTH. */
1264 0xec,
1265 'a', 'b', 'g', 'd', 'u', 'd', 'd', 'd', 'd', 'd', 'd', 'd',
1266 'd', 'd', 'd',
1267 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
1268 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
1269 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
1270 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
1271 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
1272 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
1273 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
1274 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
1275 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
1276 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
1277 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
1278 'v'
1279 /* (message body length missing) */
1280 };
1281 gsize size = sizeof (data);
1282 GDBusMessage *message = NULL;
1283 GError *local_error = NULL;
1284
1285 message = g_dbus_message_new_from_blob ((guchar *) data, size,
1286 G_DBUS_CAPABILITY_FLAGS_NONE,
1287 &local_error);
1288 g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1289 g_assert_null (message);
1290
1291 g_clear_error (&local_error);
1292 }
1293
1294 /* ---------------------------------------------------------------------------------------------------- */
1295
1296 /* Test that an invalid header in a D-Bus message (specifically, containing too
1297 * many levels of nested variant) is gracefully handled with an error rather
1298 * than a crash. The set of bytes here come almost directly from fuzzer output. */
1299 static void
test_message_parse_deep_header_nesting(void)1300 test_message_parse_deep_header_nesting (void)
1301 {
1302 const guint8 data[] = {
1303 'l', /* little-endian byte order */
1304 0x20, /* message type */
1305 0x20, /* message flags */
1306 0x01, /* major protocol version */
1307 0x20, 0x20, 0x20, 0x00, /* body length (invalid) */
1308 0x20, 0x20, 0x20, 0x20, /* message serial */
1309 /* a{yv} of header fields:
1310 * (things start to be even more invalid below here) */
1311 0x20, 0x20, 0x20, 0x00, /* array length (in bytes) */
1312 0x20, /* array key (this is not currently a valid header field) */
1313 /* Variant array value: */
1314 0x01, /* signature length */
1315 'v', /* one complete type */
1316 0x00, /* nul terminator */
1317 /* (Variant array value payload) */
1318 /* Critically, this contains 64 nested variants (minus two for the
1319 * ‘arbitrary valid content’ below, but ignoring two for the `a{yv}`
1320 * above), which in total exceeds %G_DBUS_MAX_TYPE_DEPTH. */
1321 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1322 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1323 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1324 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1325 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1326 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1327 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1328 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1329 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1330 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1331 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1332 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1333 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1334 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1335 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1336 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1337 /* Some arbitrary valid content inside the innermost variant: */
1338 0x01, 'y', 0x00, 0xcc,
1339 /* (message body length missing) */
1340 };
1341 gsize size = sizeof (data);
1342 GDBusMessage *message = NULL;
1343 GError *local_error = NULL;
1344
1345 message = g_dbus_message_new_from_blob ((guchar *) data, size,
1346 G_DBUS_CAPABILITY_FLAGS_NONE,
1347 &local_error);
1348 g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1349 g_assert_null (message);
1350
1351 g_clear_error (&local_error);
1352 }
1353
1354 /* ---------------------------------------------------------------------------------------------------- */
1355
1356 /* Test that an invalid body in a D-Bus message (specifically, containing too
1357 * many levels of nested variant) is gracefully handled with an error rather
1358 * than a crash. The set of bytes here are a modified version of the bytes from
1359 * test_message_parse_deep_header_nesting(). */
1360 static void
test_message_parse_deep_body_nesting(void)1361 test_message_parse_deep_body_nesting (void)
1362 {
1363 const guint8 data[] = {
1364 'l', /* little-endian byte order */
1365 0x20, /* message type */
1366 0x20, /* message flags */
1367 0x01, /* major protocol version */
1368 0x20, 0x20, 0x20, 0x00, /* body length (invalid) */
1369 0x20, 0x20, 0x20, 0x20, /* message serial */
1370 /* a{yv} of header fields: */
1371 0x07, 0x00, 0x00, 0x00, /* array length (in bytes) */
1372 0x08, /* array key (signature field) */
1373 /* Variant array value: */
1374 0x01, /* signature length */
1375 'g', /* one complete type */
1376 0x00, /* nul terminator */
1377 /* (Variant array value payload) */
1378 0x01, 'v', 0x00,
1379 /* End-of-header padding to reach an 8-byte boundary: */
1380 0x00,
1381 /* Message body: over 64 levels of nested variant, which is not valid: */
1382 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1383 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1384 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1385 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1386 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1387 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1388 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1389 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1390 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1391 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1392 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1393 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1394 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1395 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1396 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1397 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1398 /* Some arbitrary valid content inside the innermost variant: */
1399 0x01, 'y', 0x00, 0xcc,
1400 };
1401 gsize size = sizeof (data);
1402 GDBusMessage *message = NULL;
1403 GError *local_error = NULL;
1404
1405 message = g_dbus_message_new_from_blob ((guchar *) data, size,
1406 G_DBUS_CAPABILITY_FLAGS_NONE,
1407 &local_error);
1408 g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1409 g_assert_null (message);
1410
1411 g_clear_error (&local_error);
1412 }
1413
1414 /* ---------------------------------------------------------------------------------------------------- */
1415
1416 int
main(int argc,char * argv[])1417 main (int argc,
1418 char *argv[])
1419 {
1420 g_setenv ("LC_ALL", "C", TRUE);
1421 setlocale (LC_ALL, "C");
1422
1423 g_test_init (&argc, &argv, NULL);
1424 g_test_bug_base ("https://bugzilla.gnome.org/show_bug.cgi?id=");
1425
1426 g_test_add_func ("/gdbus/message-serialize/basic",
1427 test_message_serialize_basic);
1428 g_test_add_func ("/gdbus/message-serialize/complex",
1429 test_message_serialize_complex);
1430 g_test_add_func ("/gdbus/message-serialize/invalid",
1431 test_message_serialize_invalid);
1432 g_test_add_func ("/gdbus/message-serialize/header-checks",
1433 test_message_serialize_header_checks);
1434 g_test_add_func ("/gdbus/message-serialize/double-array",
1435 test_message_serialize_double_array);
1436
1437 g_test_add_func ("/gdbus/message-parse/empty-arrays-of-arrays",
1438 test_message_parse_empty_arrays_of_arrays);
1439 g_test_add_func ("/gdbus/message-parse/non-signature-header",
1440 test_message_parse_non_signature_header);
1441 g_test_add_func ("/gdbus/message-parse/empty-signature-header",
1442 test_message_parse_empty_signature_header);
1443 g_test_add_func ("/gdbus/message-parse/multiple-signature-header",
1444 test_message_parse_multiple_signature_header);
1445 g_test_add_func ("/gdbus/message-parse/over-long-signature-header",
1446 test_message_parse_over_long_signature_header);
1447 g_test_add_func ("/gdbus/message-parse/deep-header-nesting",
1448 test_message_parse_deep_header_nesting);
1449 g_test_add_func ("/gdbus/message-parse/deep-body-nesting",
1450 test_message_parse_deep_body_nesting);
1451
1452 return g_test_run();
1453 }
1454
1455