diff options
author | Philip Withnall <pwithnall@endlessos.org> | 2022-12-29 18:42:44 +0000 |
---|---|---|
committer | Philip Withnall <pwithnall@endlessos.org> | 2023-01-18 12:15:47 +0000 |
commit | 53702d68c4ee7b939a725ec4a5d707a2bdead1e9 (patch) | |
tree | 70eebfcc3193a8097391bdf1aa0770a4ddbdaa72 | |
parent | f068347b1419213be20e3647f5d4f1d505bdcba4 (diff) | |
download | glib-53702d68c4ee7b939a725ec4a5d707a2bdead1e9.tar.gz |
gvariant: Optimise g_variant_print() for nested maybes
As with commit 9ae59bd647882bcb33103331255a5149d2fb90d2, deeply nested
maybes in an array can be exploited by a malicious caller to cause a
geometric increase in processing time and number of `GVariant` instances
handled by the `g_variant_print()` code.
Optimise this by skipping recursing through most of the chain of maybes,
thus avoiding all the setup checks in each recursive call.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
oss-fuzz#54577
-rw-r--r-- | glib/gvariant.c | 46 |
1 files changed, 32 insertions, 14 deletions
diff --git a/glib/gvariant.c b/glib/gvariant.c index 8f0c237db..cef0216c5 100644 --- a/glib/gvariant.c +++ b/glib/gvariant.c @@ -2226,8 +2226,9 @@ g_variant_print_string (GVariant *value, if (g_variant_n_children (value)) { - gchar *printed_child; - GVariant *element; + const GVariantType *base_type; + guint i, depth; + GVariant *element = NULL; /* Nested maybes: * @@ -2241,19 +2242,36 @@ g_variant_print_string (GVariant *value, * "just" is actually exactly the case where we have a nested * Nothing. * - * Instead of searching for that nested Nothing, we just print - * the contained value into a separate string and see if we - * end up with "nothing" at the end of it. If so, we need to - * add "just" at our level. + * Search for the nested Nothing, to save a lot of recursion if there + * are multiple levels of maybes. */ - element = g_variant_get_child_value (value, 0); - printed_child = g_variant_print (element, FALSE); - g_variant_unref (element); - - if (g_str_has_suffix (printed_child, "nothing")) - g_string_append (string, "just "); - g_string_append (string, printed_child); - g_free (printed_child); + for (depth = 0, base_type = g_variant_get_type (value); + g_variant_type_is_maybe (base_type); + depth++, base_type = g_variant_type_element (base_type)); + + element = g_variant_ref (value); + for (i = 0; i < depth && element != NULL; i++) + { + GVariant *new_element = g_variant_n_children (element) ? g_variant_get_child_value (element, 0) : NULL; + g_variant_unref (element); + element = g_steal_pointer (&new_element); + } + + if (element == NULL) + { + /* One of the maybes was Nothing, so print out the right number of + * justs. */ + for (; i > 1; i--) + g_string_append (string, "just "); + g_string_append (string, "nothing"); + } + else + { + /* There are no Nothings, so print out the child with no prefixes. */ + g_variant_print_string (element, string, FALSE); + } + + g_clear_pointer (&element, g_variant_unref); } else g_string_append (string, "nothing"); |