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 *last_serialization = NULL;
528 gchar *s = NULL;
529 guint n;
530
531 message = g_dbus_message_new ();
532 g_dbus_message_set_body (message, value);
533 g_dbus_message_set_message_type (message, G_DBUS_MESSAGE_TYPE_METHOD_CALL);
534 g_dbus_message_set_serial (message, 0x41);
535 s = get_body_signature (value);
536 g_dbus_message_set_header (message, G_DBUS_MESSAGE_HEADER_FIELD_PATH, g_variant_new_object_path ("/foo/bar"));
537 g_dbus_message_set_header (message, G_DBUS_MESSAGE_HEADER_FIELD_MEMBER, g_variant_new_string ("Member"));
538 g_dbus_message_set_header (message, G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE, g_variant_new_signature (s));
539 g_free (s);
540
541 /* First check that the serialization to the D-Bus wire format is correct - do this for both byte orders */
542 for (n = 0; n < 2; n++)
543 {
544 GDBusMessageByteOrder byte_order;
545 switch (n)
546 {
547 case 0:
548 byte_order = G_DBUS_MESSAGE_BYTE_ORDER_BIG_ENDIAN;
549 break;
550 case 1:
551 byte_order = G_DBUS_MESSAGE_BYTE_ORDER_LITTLE_ENDIAN;
552 break;
553 case 2:
554 g_assert_not_reached ();
555 break;
556 }
557 g_dbus_message_set_byte_order (message, byte_order);
558
559 error = NULL;
560 blob = g_dbus_message_to_blob (message,
561 &blob_size,
562 G_DBUS_CAPABILITY_FLAGS_NONE,
563 &error);
564 g_assert_no_error (error);
565 g_assert (blob != NULL);
566
567 switch (byte_order)
568 {
569 case G_DBUS_MESSAGE_BYTE_ORDER_BIG_ENDIAN:
570 g_assert_cmpint (blob[0], ==, 'B');
571 break;
572 case G_DBUS_MESSAGE_BYTE_ORDER_LITTLE_ENDIAN:
573 g_assert_cmpint (blob[0], ==, 'l');
574 break;
575 }
576
577 dbus_error_init (&dbus_error);
578 dbus_1_message = dbus_message_demarshal ((char *) blob, blob_size, &dbus_error);
579 if (dbus_error_is_set (&dbus_error))
580 {
581 g_printerr ("Error calling dbus_message_demarshal() on this blob: %s: %s\n",
582 dbus_error.name,
583 dbus_error.message);
584 hexdump (blob, blob_size);
585 dbus_error_free (&dbus_error);
586
587 s = g_variant_print (value, TRUE);
588 g_printerr ("\nThe blob was generated from the following GVariant value:\n%s\n\n", s);
589 g_free (s);
590
591 g_printerr ("If the blob was encoded using DBusMessageIter, the payload would have been:\n");
592 print_gv_dbus_message (value);
593
594 g_assert_not_reached ();
595 }
596
597 s = dbus_1_message_print (dbus_1_message);
598 dbus_message_unref (dbus_1_message);
599
600 /* Then serialize back and check that the body is identical */
601
602 error = NULL;
603 recovered_message = g_dbus_message_new_from_blob (blob,
604 blob_size,
605 G_DBUS_CAPABILITY_FLAGS_NONE,
606 &error);
607 g_assert_no_error (error);
608 g_assert (recovered_message != NULL);
609
610 if (value == NULL)
611 {
612 g_assert (g_dbus_message_get_body (recovered_message) == NULL);
613 }
614 else
615 {
616 g_assert (g_dbus_message_get_body (recovered_message) != NULL);
617 g_assert_cmpvariant (g_dbus_message_get_body (recovered_message), value);
618 }
619 g_object_unref (recovered_message);
620 g_free (blob);
621
622 if (last_serialization != NULL)
623 {
624 g_assert_cmpstr (last_serialization, ==, s);
625 g_free (last_serialization);
626 }
627
628 last_serialization = g_steal_pointer (&s);
629 }
630
631 g_object_unref (message);
632
633 return g_steal_pointer (&last_serialization);
634 }
635
636 /* If @value is floating, this assumes ownership. */
637 static void
check_serialization(GVariant * value,const gchar * expected_dbus_1_output)638 check_serialization (GVariant *value,
639 const gchar *expected_dbus_1_output)
640 {
641 gchar *s = get_and_check_serialization (value);
642 g_assert_cmpstr (s, ==, expected_dbus_1_output);
643 g_free (s);
644 }
645
646 static void
test_message_serialize_basic(void)647 test_message_serialize_basic (void)
648 {
649 check_serialization (NULL, "");
650
651 check_serialization (g_variant_new ("(sogybnqiuxtd)",
652 "this is a string",
653 "/this/is/a/path",
654 "sad",
655 42,
656 TRUE,
657 -42,
658 60000,
659 -44,
660 100000,
661 -(G_GUINT64_CONSTANT(2)<<34),
662 G_GUINT64_CONSTANT(0xffffffffffffffff),
663 42.5),
664 "value 0: string: 'this is a string'\n"
665 "value 1: object_path: '/this/is/a/path'\n"
666 "value 2: signature: 'sad'\n"
667 "value 3: byte: 0x2a\n"
668 "value 4: bool: true\n"
669 "value 5: int16: -42\n"
670 "value 6: uint16: 60000\n"
671 "value 7: int32: -44\n"
672 "value 8: uint32: 100000\n"
673 "value 9: int64: -34359738368\n"
674 "value 10: uint64: 18446744073709551615\n"
675 "value 11: double: 42.500000\n");
676 }
677
678 /* ---------------------------------------------------------------------------------------------------- */
679
680 static void
test_message_serialize_complex(void)681 test_message_serialize_complex (void)
682 {
683 GError *error;
684 GVariant *value;
685 guint i;
686 gchar *serialization = NULL;
687
688 error = NULL;
689
690 value = g_variant_parse (G_VARIANT_TYPE ("(aia{ss})"),
691 "([1, 2, 3], {'one': 'white', 'two': 'black'})",
692 NULL, NULL, &error);
693 g_assert_no_error (error);
694 g_assert (value != NULL);
695 check_serialization (value,
696 "value 0: array:\n"
697 " int32: 1\n"
698 " int32: 2\n"
699 " int32: 3\n"
700 "value 1: array:\n"
701 " dict_entry:\n"
702 " string: 'one'\n"
703 " string: 'white'\n"
704 " dict_entry:\n"
705 " string: 'two'\n"
706 " string: 'black'\n");
707 g_variant_unref (value);
708
709 value = g_variant_parse (G_VARIANT_TYPE ("(sa{sv}as)"),
710 "('01234567890123456', {}, ['Something'])",
711 NULL, NULL, &error);
712 g_assert_no_error (error);
713 g_assert (value != NULL);
714 check_serialization (value,
715 "value 0: string: '01234567890123456'\n"
716 "value 1: array:\n"
717 "value 2: array:\n"
718 " string: 'Something'\n");
719 g_variant_unref (value);
720
721 /* https://bugzilla.gnome.org/show_bug.cgi?id=621838 */
722 check_serialization (g_variant_new_parsed ("(@aay [], {'cwd': <'/home/davidz/Hacking/glib/gio/tests'>})"),
723 "value 0: array:\n"
724 "value 1: array:\n"
725 " dict_entry:\n"
726 " string: 'cwd'\n"
727 " variant:\n"
728 " string: '/home/davidz/Hacking/glib/gio/tests'\n");
729
730 #ifdef DBUS_TYPE_UNIX_FD
731 value = g_variant_parse (G_VARIANT_TYPE ("(hah)"),
732 "(42, [43, 44])",
733 NULL, NULL, &error);
734 g_assert_no_error (error);
735 g_assert (value != NULL);
736 /* about (not extracted), see comment in DBUS_TYPE_UNIX_FD case in
737 * dbus_1_message_append() above.
738 */
739 check_serialization (value,
740 "value 0: unix-fd: (not extracted)\n"
741 "value 1: array:\n"
742 " unix-fd: (not extracted)\n"
743 " unix-fd: (not extracted)\n");
744 g_variant_unref (value);
745 #endif
746
747 /* Deep nesting of variants (just below the recursion limit). */
748 value = g_variant_new_string ("buried");
749 for (i = 0; i < 64; i++)
750 value = g_variant_new_variant (value);
751 value = g_variant_new_tuple (&value, 1);
752
753 serialization = get_and_check_serialization (value);
754 g_assert_nonnull (serialization);
755 g_assert_true (g_str_has_prefix (serialization,
756 "value 0: variant:\n"
757 " variant:\n"
758 " variant:\n"));
759 g_free (serialization);
760
761 /* Deep nesting of arrays and structs (just below the recursion limit).
762 * See https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-marshaling-signature */
763 value = g_variant_new_string ("hello");
764 for (i = 0; i < 32; i++)
765 value = g_variant_new_tuple (&value, 1);
766 for (i = 0; i < 32; i++)
767 value = g_variant_new_array (NULL, &value, 1);
768 value = g_variant_new_tuple (&value, 1);
769
770 serialization = get_and_check_serialization (value);
771 g_assert_nonnull (serialization);
772 g_assert_true (g_str_has_prefix (serialization,
773 "value 0: array:\n"
774 " array:\n"
775 " array:\n"));
776 g_free (serialization);
777 }
778
779
780 /* ---------------------------------------------------------------------------------------------------- */
781
782 static void
replace(char * blob,gsize len,const char * before,const char * after)783 replace (char *blob,
784 gsize len,
785 const char *before,
786 const char *after)
787 {
788 gsize i;
789 gsize slen = strlen (before) + 1;
790
791 g_assert_cmpuint (strlen (before), ==, strlen (after));
792 g_assert_cmpuint (len, >=, slen);
793
794 for (i = 0; i < (len - slen + 1); i++)
795 {
796 if (memcmp (blob + i, before, slen) == 0)
797 memcpy (blob + i, after, slen);
798 }
799 }
800
801 static void
test_message_serialize_invalid(void)802 test_message_serialize_invalid (void)
803 {
804 guint n;
805
806 /* Other things we could check (note that GDBus _does_ check for all
807 * these things - we just don't have test-suit coverage for it)
808 *
809 * - array exceeding 64 MiB (2^26 bytes) - unfortunately libdbus-1 checks
810 * this, e.g.
811 *
812 * process 19620: arguments to dbus_message_iter_append_fixed_array() were incorrect,
813 * assertion "n_elements <= DBUS_MAXIMUM_ARRAY_LENGTH / _dbus_type_get_alignment (element_type)"
814 * failed in file dbus-message.c line 2344.
815 * This is normally a bug in some application using the D-Bus library.
816 * D-Bus not built with -rdynamic so unable to print a backtrace
817 * Aborted (core dumped)
818 *
819 * - message exceeding 128 MiB (2^27 bytes)
820 *
821 * - endianness, message type, flags, protocol version
822 */
823
824 for (n = 0; n < 3; n++)
825 {
826 GDBusMessage *message;
827 GError *error;
828 DBusMessage *dbus_message;
829 char *blob;
830 int blob_len;
831 /* these are in pairs with matching length */
832 const gchar *valid_utf8_str = "this is valid...";
833 const gchar *invalid_utf8_str = "this is invalid\xff";
834 const gchar *valid_signature = "a{sv}a{sv}a{sv}aiai";
835 const gchar *invalid_signature = "not valid signature";
836 const gchar *valid_object_path = "/this/is/a/valid/dbus/object/path";
837 const gchar *invalid_object_path = "/this/is/not a valid object path!";
838
839 dbus_message = dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_CALL);
840 dbus_message_set_serial (dbus_message, 0x41);
841 dbus_message_set_path (dbus_message, "/foo/bar");
842 dbus_message_set_member (dbus_message, "Member");
843 switch (n)
844 {
845 case 0:
846 /* invalid UTF-8 */
847 dbus_message_append_args (dbus_message,
848 DBUS_TYPE_STRING, &valid_utf8_str,
849 DBUS_TYPE_INVALID);
850 break;
851
852 case 1:
853 /* invalid object path */
854 dbus_message_append_args (dbus_message,
855 DBUS_TYPE_OBJECT_PATH, &valid_object_path,
856 DBUS_TYPE_INVALID);
857 break;
858
859 case 2:
860 /* invalid signature */
861 dbus_message_append_args (dbus_message,
862 DBUS_TYPE_SIGNATURE, &valid_signature,
863 DBUS_TYPE_INVALID);
864 break;
865
866 default:
867 g_assert_not_reached ();
868 break;
869 }
870 dbus_message_marshal (dbus_message, &blob, &blob_len);
871 /* hack up the message to be invalid by replacing each valid string
872 * with its invalid counterpart */
873 replace (blob, blob_len, valid_utf8_str, invalid_utf8_str);
874 replace (blob, blob_len, valid_object_path, invalid_object_path);
875 replace (blob, blob_len, valid_signature, invalid_signature);
876
877 error = NULL;
878 message = g_dbus_message_new_from_blob ((guchar *) blob,
879 blob_len,
880 G_DBUS_CAPABILITY_FLAGS_NONE,
881 &error);
882 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
883 g_error_free (error);
884 g_assert (message == NULL);
885
886 dbus_free (blob);
887 dbus_message_unref (dbus_message);
888 }
889
890 }
891
892 /* ---------------------------------------------------------------------------------------------------- */
893
894 static void
test_message_serialize_header_checks(void)895 test_message_serialize_header_checks (void)
896 {
897 GDBusMessage *message;
898 GDBusMessage *reply;
899 GError *error = NULL;
900 guchar *blob;
901 gsize blob_size;
902
903 /*
904 * check we can't serialize messages with INVALID type
905 */
906 message = g_dbus_message_new ();
907 blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
908 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
909 g_assert_cmpstr (error->message, ==, "Cannot serialize message: type is INVALID");
910 g_clear_error (&error);
911 g_assert_null (blob);
912 g_object_unref (message);
913
914 /*
915 * check that we can't serialize messages with SIGNATURE set to a non-signature-typed value
916 */
917 message = g_dbus_message_new_signal ("/the/path", "The.Interface", "TheMember");
918 g_dbus_message_set_header (message, G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE, g_variant_new_boolean (FALSE));
919 blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
920
921 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
922 g_assert_cmpstr (error->message, ==, "Signature header found but is not of type signature");
923 g_assert_null (blob);
924
925 g_clear_error (&error);
926 g_clear_object (&message);
927
928 /*
929 * check we can't serialize signal messages with INTERFACE, PATH or MEMBER unset / set to reserved value
930 */
931 message = g_dbus_message_new_signal ("/the/path", "The.Interface", "TheMember");
932 /* ----- */
933 /* interface NULL => error */
934 g_dbus_message_set_interface (message, NULL);
935 blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
936 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
937 g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: PATH, INTERFACE or MEMBER header field is missing");
938 g_clear_error (&error);
939 g_assert_null (blob);
940 /* interface reserved value => error */
941 g_dbus_message_set_interface (message, "org.freedesktop.DBus.Local");
942 blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
943 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
944 g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: The INTERFACE header field is using the reserved value org.freedesktop.DBus.Local");
945 g_clear_error (&error);
946 g_assert_null (blob);
947 /* reset interface */
948 g_dbus_message_set_interface (message, "The.Interface");
949 /* ----- */
950 /* path NULL => error */
951 g_dbus_message_set_path (message, NULL);
952 blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
953 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
954 g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: PATH, INTERFACE or MEMBER header field is missing");
955 g_clear_error (&error);
956 g_assert_null (blob);
957 /* path reserved value => error */
958 g_dbus_message_set_path (message, "/org/freedesktop/DBus/Local");
959 blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
960 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
961 g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: The PATH header field is using the reserved value /org/freedesktop/DBus/Local");
962 g_clear_error (&error);
963 g_assert_null (blob);
964 /* reset path */
965 g_dbus_message_set_path (message, "/the/path");
966 /* ----- */
967 /* member NULL => error */
968 g_dbus_message_set_member (message, NULL);
969 blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
970 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
971 g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: PATH, INTERFACE or MEMBER header field is missing");
972 g_clear_error (&error);
973 g_assert_null (blob);
974 /* reset member */
975 g_dbus_message_set_member (message, "TheMember");
976 /* ----- */
977 /* done */
978 g_object_unref (message);
979
980 /*
981 * check that we can't serialize method call messages with PATH or MEMBER unset
982 */
983 message = g_dbus_message_new_method_call (NULL, "/the/path", NULL, "TheMember");
984 /* ----- */
985 /* path NULL => error */
986 g_dbus_message_set_path (message, NULL);
987 blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
988 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
989 g_assert_cmpstr (error->message, ==, "Cannot serialize message: METHOD_CALL message: PATH or MEMBER header field is missing");
990 g_clear_error (&error);
991 g_assert_null (blob);
992 /* reset path */
993 g_dbus_message_set_path (message, "/the/path");
994 /* ----- */
995 /* member NULL => error */
996 g_dbus_message_set_member (message, NULL);
997 blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
998 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
999 g_assert_cmpstr (error->message, ==, "Cannot serialize message: METHOD_CALL message: PATH or MEMBER header field is missing");
1000 g_clear_error (&error);
1001 g_assert_null (blob);
1002 /* reset member */
1003 g_dbus_message_set_member (message, "TheMember");
1004 /* ----- */
1005 /* done */
1006 g_object_unref (message);
1007
1008 /*
1009 * check that we can't serialize method reply messages with REPLY_SERIAL unset
1010 */
1011 message = g_dbus_message_new_method_call (NULL, "/the/path", NULL, "TheMember");
1012 g_dbus_message_set_serial (message, 42);
1013 /* method reply */
1014 reply = g_dbus_message_new_method_reply (message);
1015 g_assert_cmpint (g_dbus_message_get_reply_serial (reply), ==, 42);
1016 g_dbus_message_set_header (reply, G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL, NULL);
1017 blob = g_dbus_message_to_blob (reply, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
1018 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1019 g_assert_cmpstr (error->message, ==, "Cannot serialize message: METHOD_RETURN message: REPLY_SERIAL header field is missing");
1020 g_clear_error (&error);
1021 g_assert_null (blob);
1022 g_object_unref (reply);
1023 /* method error - first nuke ERROR_NAME, then REPLY_SERIAL */
1024 reply = g_dbus_message_new_method_error (message, "Some.Error.Name", "the message");
1025 g_assert_cmpint (g_dbus_message_get_reply_serial (reply), ==, 42);
1026 /* nuke ERROR_NAME */
1027 g_dbus_message_set_error_name (reply, 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 /* reset ERROR_NAME */
1034 g_dbus_message_set_error_name (reply, "Some.Error.Name");
1035 /* nuke REPLY_SERIAL */
1036 g_dbus_message_set_header (reply, G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL, NULL);
1037 blob = g_dbus_message_to_blob (reply, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error);
1038 g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1039 g_assert_cmpstr (error->message, ==, "Cannot serialize message: ERROR message: REPLY_SERIAL or ERROR_NAME header field is missing");
1040 g_clear_error (&error);
1041 g_assert_null (blob);
1042 g_object_unref (reply);
1043 g_object_unref (message);
1044 }
1045
1046 /* ---------------------------------------------------------------------------------------------------- */
1047
1048 static void
test_message_parse_empty_arrays_of_arrays(void)1049 test_message_parse_empty_arrays_of_arrays (void)
1050 {
1051 GVariant *body;
1052 GError *error = NULL;
1053
1054 g_test_bug ("673612");
1055 /* These three-element array of empty arrays were previously read back as a
1056 * two-element array of empty arrays, due to sometimes erroneously skipping
1057 * four bytes to align for the eight-byte-aligned grandchild types (x and
1058 * dict_entry).
1059 */
1060 body = g_variant_parse (G_VARIANT_TYPE ("(aaax)"),
1061 "([@aax [], [], []],)", NULL, NULL, &error);
1062 g_assert_no_error (error);
1063 check_serialization (body,
1064 "value 0: array:\n"
1065 " array:\n"
1066 " array:\n"
1067 " array:\n");
1068 g_variant_unref (body);
1069
1070 body = g_variant_parse (G_VARIANT_TYPE ("(aaa{uu})"),
1071 "([@aa{uu} [], [], []],)", NULL, NULL, &error);
1072 g_assert_no_error (error);
1073 check_serialization (body,
1074 "value 0: array:\n"
1075 " array:\n"
1076 " array:\n"
1077 " array:\n");
1078 g_variant_unref (body);
1079
1080 /* Due to the same bug, g_dbus_message_new_from_blob() would fail for this
1081 * message because it would try to read past the end of the string. Hence,
1082 * sending this to an application would make it fall off the bus. */
1083 body = g_variant_parse (G_VARIANT_TYPE ("(a(aa{sv}as))"),
1084 "([ ([], []),"
1085 " ([], []),"
1086 " ([], [])],)", NULL, NULL, &error);
1087 g_assert_no_error (error);
1088 check_serialization (body,
1089 "value 0: array:\n"
1090 " struct:\n"
1091 " array:\n"
1092 " array:\n"
1093 " struct:\n"
1094 " array:\n"
1095 " array:\n"
1096 " struct:\n"
1097 " array:\n"
1098 " array:\n");
1099 g_variant_unref (body);
1100 }
1101
1102 /* ---------------------------------------------------------------------------------------------------- */
1103
1104 static void
test_message_serialize_double_array(void)1105 test_message_serialize_double_array (void)
1106 {
1107 GVariantBuilder builder;
1108 GVariant *body;
1109
1110 g_test_bug ("732754");
1111
1112 g_variant_builder_init (&builder, G_VARIANT_TYPE ("ad"));
1113 g_variant_builder_add (&builder, "d", (gdouble)0.0);
1114 g_variant_builder_add (&builder, "d", (gdouble)8.0);
1115 g_variant_builder_add (&builder, "d", (gdouble)22.0);
1116 g_variant_builder_add (&builder, "d", (gdouble)0.0);
1117 body = g_variant_new ("(@ad)", g_variant_builder_end (&builder));
1118 check_serialization (body,
1119 "value 0: array:\n"
1120 " double: 0.000000\n"
1121 " double: 8.000000\n"
1122 " double: 22.000000\n"
1123 " double: 0.000000\n");
1124 }
1125
1126 /* ---------------------------------------------------------------------------------------------------- */
1127
1128 /* Test that an invalid header in a D-Bus message (specifically, with a type
1129 * which doesn’t match what’s expected for the given header) is gracefully
1130 * handled with an error rather than a crash. */
1131 static void
test_message_parse_non_signature_header(void)1132 test_message_parse_non_signature_header (void)
1133 {
1134 const guint8 data[] = {
1135 'l', /* little-endian byte order */
1136 0x02, /* message type (method return) */
1137 0x00, /* message flags (none) */
1138 0x01, /* major protocol version */
1139 0x00, 0x00, 0x00, 0x00, /* body length (in bytes) */
1140 0x00, 0x00, 0x00, 0xbc, /* message serial */
1141 /* a{yv} of header fields:
1142 * (things start to be invalid below here) */
1143 0x10, 0x00, 0x00, 0x00, /* array length (in bytes), must be a multiple of 8 */
1144 0x08, /* array key (SIGNATURE) */
1145 /* Variant array value: */
1146 0x04, /* signature length */
1147 'd', 0x00, 0x00, 'F', /* signature (invalid) */
1148 0x00, /* nul terminator */
1149 /* (Variant array value payload missing) */
1150 /* alignment padding before the next header array element, as structs must
1151 * be 8-aligned: */
1152 0x00,
1153 0x05, /* array key (REPLY_SERIAL, required for method return messages) */
1154 /* Variant array value: */
1155 0x01, /* signature length */
1156 'u', /* one complete type */
1157 0x00, /* nul terminator */
1158 /* (Variant array value payload) */
1159 0x00, 0x01, 0x02, 0x03,
1160 /* (message body is zero-length) */
1161 };
1162 gsize size = sizeof (data);
1163 GDBusMessage *message = NULL;
1164 GError *local_error = NULL;
1165
1166 message = g_dbus_message_new_from_blob ((guchar *) data, size,
1167 G_DBUS_CAPABILITY_FLAGS_NONE,
1168 &local_error);
1169 g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1170 g_assert_null (message);
1171
1172 g_clear_error (&local_error);
1173 }
1174
1175 /* ---------------------------------------------------------------------------------------------------- */
1176
1177 /* Test that an invalid header in a D-Bus message (specifically, containing a
1178 * variant with an empty type signature) is gracefully handled with an error
1179 * rather than a crash. */
1180 static void
test_message_parse_empty_signature_header(void)1181 test_message_parse_empty_signature_header (void)
1182 {
1183 const guint8 data[] = {
1184 'l', /* little-endian byte order */
1185 0x02, /* message type (method return) */
1186 0x00, /* message flags (none) */
1187 0x01, /* major protocol version */
1188 0x00, 0x00, 0x00, 0x00, /* body length (in bytes) */
1189 0x20, 0x20, 0x20, 0x20, /* message serial */
1190 /* a{yv} of header fields:
1191 * (things start to be invalid below here) */
1192 0x10, 0x00, 0x00, 0x00, /* array length (in bytes), must be a multiple of 8 */
1193 0x20, /* array key (this is not currently a valid header field) */
1194 /* Variant array value: */
1195 0x00, /* signature length */
1196 0x00, /* nul terminator */
1197 /* (Variant array value payload missing) */
1198 /* alignment padding before the next header array element, as structs must
1199 * be 8-aligned: */
1200 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1201 0x05, /* array key (REPLY_SERIAL, required for method return messages) */
1202 /* Variant array value: */
1203 0x01, /* signature length */
1204 'u', /* one complete type */
1205 0x00, /* nul terminator */
1206 /* (Variant array value payload) */
1207 0x00, 0x01, 0x02, 0x03,
1208 /* (message body is zero-length) */
1209 };
1210 gsize size = sizeof (data);
1211 GDBusMessage *message = NULL;
1212 GError *local_error = NULL;
1213
1214 message = g_dbus_message_new_from_blob ((guchar *) data, size,
1215 G_DBUS_CAPABILITY_FLAGS_NONE,
1216 &local_error);
1217 g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1218 g_assert_null (message);
1219
1220 g_clear_error (&local_error);
1221 }
1222
1223 /* ---------------------------------------------------------------------------------------------------- */
1224
1225 /* Test that an invalid header in a D-Bus message (specifically, containing a
1226 * variant with a type signature containing multiple complete types) is
1227 * gracefully handled with an error rather than a crash. */
1228 static void
test_message_parse_multiple_signature_header(void)1229 test_message_parse_multiple_signature_header (void)
1230 {
1231 const guint8 data[] = {
1232 'l', /* little-endian byte order */
1233 0x02, /* message type (method return) */
1234 0x00, /* message flags (none) */
1235 0x01, /* major protocol version */
1236 0x00, 0x00, 0x00, 0x00, /* body length (in bytes) */
1237 0x20, 0x20, 0x20, 0x20, /* message serial */
1238 /* a{yv} of header fields:
1239 * (things start to be invalid below here) */
1240 0x10, 0x00, 0x00, 0x00, /* array length (in bytes), must be a multiple of 8 */
1241 0x20, /* array key (this is not currently a valid header field) */
1242 /* Variant array value: */
1243 0x02, /* signature length */
1244 'b', 'b', /* two complete types */
1245 0x00, /* nul terminator */
1246 /* (Variant array value payload missing) */
1247 /* alignment padding before the next header array element, as structs must
1248 * be 8-aligned: */
1249 0x00, 0x00, 0x00,
1250 0x05, /* array key (REPLY_SERIAL, required for method return messages) */
1251 /* Variant array value: */
1252 0x01, /* signature length */
1253 'u', /* one complete type */
1254 0x00, /* nul terminator */
1255 /* (Variant array value payload) */
1256 0x00, 0x01, 0x02, 0x03,
1257 /* (message body is zero-length) */
1258 };
1259 gsize size = sizeof (data);
1260 GDBusMessage *message = NULL;
1261 GError *local_error = NULL;
1262
1263 message = g_dbus_message_new_from_blob ((guchar *) data, size,
1264 G_DBUS_CAPABILITY_FLAGS_NONE,
1265 &local_error);
1266 g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1267 g_assert_null (message);
1268
1269 g_clear_error (&local_error);
1270 }
1271
1272 /* ---------------------------------------------------------------------------------------------------- */
1273
1274 /* Test that an invalid header in a D-Bus message (specifically, containing a
1275 * variant with a valid type signature that is too long to be a valid
1276 * #GVariantType due to exceeding the array nesting limits) is gracefully
1277 * handled with an error rather than a crash. */
1278 static void
test_message_parse_over_long_signature_header(void)1279 test_message_parse_over_long_signature_header (void)
1280 {
1281 const guint8 data[] = {
1282 'l', /* little-endian byte order */
1283 0x02, /* message type (method return) */
1284 0x00, /* message flags (none) */
1285 0x01, /* major protocol version */
1286 0x00, 0x00, 0x00, 0x00, /* body length (in bytes) */
1287 0x20, 0x20, 0x20, 0x20, /* message serial */
1288 /* a{yv} of header fields:
1289 * (things start to be invalid below here) */
1290 0xa0, 0x00, 0x00, 0x00, /* array length (in bytes), must be a multiple of 8 */
1291 0x08, /* array key (SIGNATURE) */
1292 /* Variant array value: */
1293 0x04, /* signature length */
1294 'g', 0x00, 0x20, 0x20, /* one complete type plus some rubbish */
1295 0x00, /* nul terminator */
1296 /* (Variant array value payload) */
1297 /* Critically, this contains 128 nested ‘a’s, which exceeds
1298 * %G_VARIANT_MAX_RECURSION_DEPTH. */
1299 0xec,
1300 'a', 'b', 'g', 'd', 'u', 'd', 'd', 'd', 'd', 'd', 'd', 'd',
1301 'd', 'd', 'd',
1302 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
1303 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
1304 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
1305 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
1306 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
1307 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
1308 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
1309 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
1310 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
1311 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
1312 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a',
1313 'v',
1314 /* first header length is a multiple of 8 so no padding is needed */
1315 0x05, /* array key (REPLY_SERIAL, required for method return messages) */
1316 /* Variant array value: */
1317 0x01, /* signature length */
1318 'u', /* one complete type */
1319 0x00, /* nul terminator */
1320 /* (Variant array value payload) */
1321 0x00, 0x01, 0x02, 0x03,
1322 /* (message body is zero-length) */
1323 };
1324 gsize size = sizeof (data);
1325 GDBusMessage *message = NULL;
1326 GError *local_error = NULL;
1327
1328 message = g_dbus_message_new_from_blob ((guchar *) data, size,
1329 G_DBUS_CAPABILITY_FLAGS_NONE,
1330 &local_error);
1331 g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1332 g_assert_null (message);
1333
1334 g_clear_error (&local_error);
1335 }
1336
1337 /* ---------------------------------------------------------------------------------------------------- */
1338
1339 /* Test that an invalid header in a D-Bus message (specifically, containing too
1340 * many levels of nested variant) is gracefully handled with an error rather
1341 * than a crash. */
1342 static void
test_message_parse_deep_header_nesting(void)1343 test_message_parse_deep_header_nesting (void)
1344 {
1345 const guint8 data[] = {
1346 'l', /* little-endian byte order */
1347 0x02, /* message type (method return) */
1348 0x00, /* message flags (none) */
1349 0x01, /* major protocol version */
1350 0x00, 0x00, 0x00, 0x00, /* body length (in bytes) */
1351 0x20, 0x20, 0x20, 0x20, /* message serial */
1352 /* a{yv} of header fields:
1353 * (things start to be invalid below here) */
1354 0xd0, 0x00, 0x00, 0x00, /* array length (in bytes), must be a multiple of 8 */
1355 0x20, /* array key (this is not currently a valid header field) */
1356 /* Variant array value: */
1357 0x01, /* signature length */
1358 'v', /* one complete type */
1359 0x00, /* nul terminator */
1360 /* (Variant array value payload) */
1361 /* Critically, this contains 64 nested variants (minus two for the
1362 * ‘arbitrary valid content’ below, but ignoring two for the `a{yv}`
1363 * above), which in total exceeds %G_DBUS_MAX_TYPE_DEPTH. */
1364 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1365 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1366 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1367 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1368 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1369 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1370 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1371 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1372 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1373 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1374 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1375 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1376 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1377 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1378 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1379 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1380 /* Some arbitrary valid content inside the innermost variant: */
1381 0x01, 'y', 0x00, 0xcc,
1382 /* no padding needed as this header element length is a multiple of 8 */
1383 0x05, /* array key (REPLY_SERIAL, required for method return messages) */
1384 /* Variant array value: */
1385 0x01, /* signature length */
1386 'u', /* one complete type */
1387 0x00, /* nul terminator */
1388 /* (Variant array value payload) */
1389 0x00, 0x01, 0x02, 0x03,
1390 /* (message body is zero-length) */
1391 };
1392 gsize size = sizeof (data);
1393 GDBusMessage *message = NULL;
1394 GError *local_error = NULL;
1395
1396 message = g_dbus_message_new_from_blob ((guchar *) data, size,
1397 G_DBUS_CAPABILITY_FLAGS_NONE,
1398 &local_error);
1399 g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1400 g_assert_null (message);
1401
1402 g_clear_error (&local_error);
1403 }
1404
1405 /* ---------------------------------------------------------------------------------------------------- */
1406
1407 /* Test that an invalid body in a D-Bus message (specifically, containing too
1408 * many levels of nested variant) is gracefully handled with an error rather
1409 * than a crash. The set of bytes here are a modified version of the bytes from
1410 * test_message_parse_deep_header_nesting(). */
1411 static void
test_message_parse_deep_body_nesting(void)1412 test_message_parse_deep_body_nesting (void)
1413 {
1414 const guint8 data[] = {
1415 'l', /* little-endian byte order */
1416 0x02, /* message type (method return) */
1417 0x00, /* message flags (none) */
1418 0x01, /* major protocol version */
1419 0xc4, 0x00, 0x00, 0x00, /* body length (in bytes) */
1420 0x20, 0x20, 0x20, 0x20, /* message serial */
1421 /* a{yv} of header fields: */
1422 0x10, 0x00, 0x00, 0x00, /* array length (in bytes), must be a multiple of 8 */
1423 0x08, /* array key (SIGNATURE) */
1424 /* Variant array value: */
1425 0x01, /* signature length */
1426 'g', /* one complete type */
1427 0x00, /* nul terminator */
1428 /* (Variant array value payload) */
1429 0x01, 'v', 0x00,
1430 /* alignment padding before the next header array element, as structs must
1431 * be 8-aligned: */
1432 0x00,
1433 0x05, /* array key (REPLY_SERIAL, required for method return messages) */
1434 /* Variant array value: */
1435 0x01, /* signature length */
1436 'u', /* one complete type */
1437 0x00, /* nul terminator */
1438 /* (Variant array value payload) */
1439 0x00, 0x01, 0x02, 0x03,
1440 /* Message body: over 64 levels of nested variant, which is not valid: */
1441 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1442 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1443 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1444 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1445 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1446 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1447 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1448 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1449 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1450 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1451 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1452 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1453 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1454 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1455 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1456 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00, 0x01, 'v', 0x00,
1457 /* Some arbitrary valid content inside the innermost variant: */
1458 0x01, 'y', 0x00, 0xcc,
1459 };
1460 gsize size = sizeof (data);
1461 GDBusMessage *message = NULL;
1462 GError *local_error = NULL;
1463
1464 message = g_dbus_message_new_from_blob ((guchar *) data, size,
1465 G_DBUS_CAPABILITY_FLAGS_NONE,
1466 &local_error);
1467 g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT);
1468 g_assert_null (message);
1469
1470 g_clear_error (&local_error);
1471 }
1472
1473 /* ---------------------------------------------------------------------------------------------------- */
1474
1475 int
main(int argc,char * argv[])1476 main (int argc,
1477 char *argv[])
1478 {
1479 g_setenv ("LC_ALL", "C", TRUE);
1480 setlocale (LC_ALL, "C");
1481
1482 g_test_init (&argc, &argv, NULL);
1483 g_test_bug_base ("https://bugzilla.gnome.org/show_bug.cgi?id=");
1484
1485 g_test_add_func ("/gdbus/message-serialize/basic",
1486 test_message_serialize_basic);
1487 g_test_add_func ("/gdbus/message-serialize/complex",
1488 test_message_serialize_complex);
1489 g_test_add_func ("/gdbus/message-serialize/invalid",
1490 test_message_serialize_invalid);
1491 g_test_add_func ("/gdbus/message-serialize/header-checks",
1492 test_message_serialize_header_checks);
1493 g_test_add_func ("/gdbus/message-serialize/double-array",
1494 test_message_serialize_double_array);
1495
1496 g_test_add_func ("/gdbus/message-parse/empty-arrays-of-arrays",
1497 test_message_parse_empty_arrays_of_arrays);
1498 g_test_add_func ("/gdbus/message-parse/non-signature-header",
1499 test_message_parse_non_signature_header);
1500 g_test_add_func ("/gdbus/message-parse/empty-signature-header",
1501 test_message_parse_empty_signature_header);
1502 g_test_add_func ("/gdbus/message-parse/multiple-signature-header",
1503 test_message_parse_multiple_signature_header);
1504 g_test_add_func ("/gdbus/message-parse/over-long-signature-header",
1505 test_message_parse_over_long_signature_header);
1506 g_test_add_func ("/gdbus/message-parse/deep-header-nesting",
1507 test_message_parse_deep_header_nesting);
1508 g_test_add_func ("/gdbus/message-parse/deep-body-nesting",
1509 test_message_parse_deep_body_nesting);
1510
1511 return g_test_run();
1512 }
1513