From d2224b475d20b544cf782ce046183209d419a012 Mon Sep 17 00:00:00 2001 From: Philip Withnall Date: Tue, 4 Dec 2018 12:55:21 +0000 Subject: [PATCH 325/682] gvariant: Fix error handling for parsing Unicode escapes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When parsing an escaped Unicode character in a text format GVariant string, such as '\U0001F415', the code uses g_ascii_strtoull(). This, unexpectedly, accepts minus signs, which can cause an assertion failure when input like '\u-FF4' is presented for parsing. Validate that there are no leading sign characters when parsing. This shouldn’t be considered a security bug, because the GVariant text format parser should not be used on untrusted input. oss-fuzz#11576 Signed-off-by: Philip Withnall --- glib/gvariant-parser.c | 20 +++++++++++++++++--- glib/tests/gvariant.c | 20 ++++++++++++++++++-- 2 files changed, 35 insertions(+), 5 deletions(-) diff --git a/glib/gvariant-parser.c b/glib/gvariant-parser.c index 44e341965..b860d42f4 100644 --- a/glib/gvariant-parser.c +++ b/glib/gvariant-parser.c @@ -1528,6 +1528,8 @@ string_free (AST *ast) g_slice_free (String, string); } +/* Accepts exactly @length hexadecimal digits. No leading sign or `0x`/`0X` prefix allowed. + * No leading/trailing space allowed. */ static gboolean unicode_unescape (const gchar *src, gint *src_ofs, @@ -1538,8 +1540,9 @@ unicode_unescape (const gchar *src, GError **error) { gchar buffer[9]; - guint64 value; + guint64 value = 0; gchar *end; + gsize n_valid_chars; (*src_ofs)++; @@ -1547,11 +1550,22 @@ unicode_unescape (const gchar *src, strncpy (buffer, src + *src_ofs, length); buffer[length] = '\0'; - value = g_ascii_strtoull (buffer, &end, 0x10); + for (n_valid_chars = 0; n_valid_chars < length; n_valid_chars++) + if (!g_ascii_isxdigit (buffer[n_valid_chars])) + break; + + if (n_valid_chars == length) + value = g_ascii_strtoull (buffer, &end, 0x10); if (value == 0 || end != buffer + length) { - parser_set_error (error, ref, NULL, + SourceRef escape_ref; + + escape_ref = *ref; + escape_ref.start += *src_ofs; + escape_ref.end = escape_ref.start + n_valid_chars; + + parser_set_error (error, &escape_ref, NULL, G_VARIANT_PARSE_ERROR_INVALID_CHARACTER, "invalid %d-character unicode escape", length); return FALSE;