From 7eedcd76f7d5b8c98fa60013e1fe6e960bf19df3 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Fri, 7 Sep 2018 22:28:37 +0100 Subject: [PATCH] gvariant: Check tuple offsets against serialised data length MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As with the previous commit, when getting a child from a serialised tuple, check its offset against the length of the serialised data of the tuple (excluding the length of the offset table). The offset was already checked against the length of the entire serialised tuple (including the offset table) — but a child should not be able to start inside the offset table. A test is included. oss-fuzz#9803 Signed-off-by: Philip Withnall --- glib/gvariant-serialiser.c | 16 ++++++++++++++-- glib/tests/gvariant.c | 26 ++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c index aa71d3c1c..643894919 100644 --- a/glib/gvariant-serialiser.c +++ b/glib/gvariant-serialiser.c @@ -870,7 +870,7 @@ gvs_tuple_get_child (GVariantSerialised value, const GVariantMemberInfo *member_info; GVariantSerialised child = { 0, }; gsize offset_size; - gsize start, end; + gsize start, end, last_end; member_info = g_variant_type_info_member_info (value.type_info, index_); child.type_info = g_variant_type_info_ref (member_info->type_info); @@ -940,7 +940,19 @@ gvs_tuple_get_child (GVariantSerialised value, offset_size * (member_info->i + 2), offset_size); - if (start < end && end <= value.size) + /* The child should not extend into the offset table. */ + if (index_ != g_variant_type_info_n_members (value.type_info) - 1) + { + GVariantSerialised last_child; + last_child = gvs_tuple_get_child (value, + g_variant_type_info_n_members (value.type_info) - 1); + last_end = last_child.data + last_child.size - value.data; + g_variant_type_info_unref (last_child.type_info); + } + else + last_end = end; + + if (start < end && end <= value.size && end <= last_end) { child.data = value.data + start; child.size = end - start; diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c index 1ab535534..be9920c1e 100644 --- a/glib/tests/gvariant.c +++ b/glib/tests/gvariant.c @@ -4841,6 +4841,30 @@ test_normal_checking_array_offsets (void) g_variant_unref (variant); } +/* Test that a tuple with invalidly large values in its offset table is + * normalised successfully without looping infinitely. */ +static void +test_normal_checking_tuple_offsets (void) +{ + const guint8 data[] = { + 0x07, 0xe5, 0x00, 0x07, 0x00, 0x07, + '(', 'a', 's', 'a', 's', 'a', 's', 'a', 's', 'a', 's', 'a', 's', ')', + }; + 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) { @@ -4911,6 +4935,8 @@ main (int argc, char **argv) test_normal_checking_tuples); g_test_add_func ("/gvariant/normal-checking/array-offsets", test_normal_checking_array_offsets); + g_test_add_func ("/gvariant/normal-checking/tuple-offsets", + test_normal_checking_tuple_offsets); g_test_add_func ("/gvariant/recursion-limits/variant-in-variant", test_recursion_limits_variant_in_variant);