[glib/glib-2-58: 1/21] gvariant: Fix checking arithmetic for tuple element ends



commit bfc0e49f20a474c9bc7124a8da13f77204310b12
Author: Philip Withnall <withnall endlessm com>
Date:   Thu Aug 16 20:12:02 2018 +0100

    gvariant: Fix checking arithmetic for tuple element ends
    
    When checking whether a serialised GVariant tuple is in normal form,
    it’s possible for `offset_ptr -= offset_size` to underflow and wrap
    around, resulting in gvs_read_unaligned_le() reading memory outside the
    serialised GVariant bounds.
    
    See §(Tuples) in gvariant-serialiser.c for the documentation on how
    tuples are serialised. Briefly, all variable-length elements in the
    tuple have an offset to their end stored in an array of offsets at the
    end of the tuple. The width of each offset is in offset_size. offset_ptr
    is added to the start of the serialised tuple to get the offset which is
    currently being examined. The offset array is in reverse order compared
    to the tuple elements, hence the subtraction.
    
    The bug can be triggered if a tuple contains a load of variable-length
    elements, each of whose length is actually zero (i.e. empty arrays).
    
    Includes a unit test.
    
    oss-fuzz#9801
    
    Signed-off-by: Philip Withnall <withnall endlessm com>

 glib/gvariant-serialiser.c |  3 +++
 glib/tests/gvariant.c      | 28 ++++++++++++++++++++++++++++
 2 files changed, 31 insertions(+)
---
diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c
index 69f183121..96df54e23 100644
--- a/glib/gvariant-serialiser.c
+++ b/glib/gvariant-serialiser.c
@@ -1065,6 +1065,9 @@ gvs_tuple_is_normal (GVariantSerialised value)
           break;
 
         case G_VARIANT_MEMBER_ENDING_OFFSET:
+          if (offset_ptr < offset_size)
+            return FALSE;
+
           offset_ptr -= offset_size;
 
           if (offset_ptr < offset)
diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c
index de8e42d0b..a5095a380 100644
--- a/glib/tests/gvariant.c
+++ b/glib/tests/gvariant.c
@@ -4631,6 +4631,30 @@ test_stack_dict_init (void)
   g_variant_unref (variant);
 }
 
+/* Test checking arbitrary binary data for normal form. This time, it’s a tuple
+ * with invalid element ends. */
+static void
+test_normal_checking_tuples (void)
+{
+  const guint8 data[] = {
+    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
+    'a', '(', 'a', 'o', 'a', 'o', 'a', 'a', 'o', 'a', 'a', 'o', ')'
+  };
+  gsize size = sizeof (data);
+  GVariant *variant = NULL;
+  GVariant *normal_variant = NULL;
+
+  variant = g_variant_new_from_data (G_VARIANT_TYPE_VARIANT, data, size,
+                                     FALSE, NULL, NULL);
+  g_assert_nonnull (variant);
+
+  normal_variant = g_variant_get_normal_form (variant);
+  g_assert_nonnull (normal_variant);
+
+  g_variant_unref (normal_variant);
+  g_variant_unref (variant);
+}
+
 int
 main (int argc, char **argv)
 {
@@ -4692,5 +4716,9 @@ main (int argc, char **argv)
 
   g_test_add_func ("/gvariant/stack-builder-init", test_stack_builder_init);
   g_test_add_func ("/gvariant/stack-dict-init", test_stack_dict_init);
+
+  g_test_add_func ("/gvariant/normal-checking/tuples",
+                   test_normal_checking_tuples);
+
   return g_test_run ();
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]