98 lines
3.2 KiB
Diff
98 lines
3.2 KiB
Diff
From eb7c9adc3b2570f6b82110b52a24609d124f38de Mon Sep 17 00:00:00 2001
|
||
From: Philip Withnall <withnall@endlessm.com>
|
||
Date: Thu, 16 Aug 2018 20:12:02 +0100
|
||
Subject: [PATCH 160/682] gvariant: Fix checking arithmetic for tuple element
|
||
ends
|
||
MIME-Version: 1.0
|
||
Content-Type: text/plain; charset=UTF-8
|
||
Content-Transfer-Encoding: 8bit
|
||
|
||
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 ();
|
||
}
|
||
--
|
||
2.19.1
|
||
|