• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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