summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Withnall <pwithnall@endlessos.org>2022-12-29 18:42:44 +0000
committerPhilip Withnall <pwithnall@endlessos.org>2023-01-18 12:15:47 +0000
commit53702d68c4ee7b939a725ec4a5d707a2bdead1e9 (patch)
tree70eebfcc3193a8097391bdf1aa0770a4ddbdaa72
parentf068347b1419213be20e3647f5d4f1d505bdcba4 (diff)
downloadglib-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.c46
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");