[glib: 4/5] gvariant: Fix error handling for parsing Unicode escapes



commit d2224b475d20b544cf782ce046183209d419a012
Author: Philip Withnall <withnall endlessm com>
Date:   Tue Dec 4 12:55:21 2018 +0000

    gvariant: Fix error handling for parsing Unicode escapes
    
    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 <withnall endlessm com>

 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 %" G_GSIZE_FORMAT "-character unicode escape", length);
       return FALSE;
diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c
index 827e47532..bf86b3c88 100644
--- a/glib/tests/gvariant.c
+++ b/glib/tests/gvariant.c
@@ -4039,6 +4039,22 @@ test_parse_failures (void)
     "b\"\\\"",                  "0-4:",            "unterminated string constant",
     "b'\\'a",                   "0-5:",            "unterminated string constant",
     "b\"\\\"a",                 "0-5:",            "unterminated string constant",
+    "'\\u-ff4'",                "3:",              "invalid 4-character unicode escape",
+    "'\\u+ff4'",                "3:",              "invalid 4-character unicode escape",
+    "'\\u'",                    "3:",              "invalid 4-character unicode escape",
+    "'\\u0'",                   "3-4:",            "invalid 4-character unicode escape",
+    "'\\uHELLO'",               "3:",              "invalid 4-character unicode escape",
+    "'\\u ff4'",                "3:",              "invalid 4-character unicode escape",
+    "'\\u012'",                 "3-6:",            "invalid 4-character unicode escape",
+    "'\\u0xff4'",               "3-4:",            "invalid 4-character unicode escape",
+    "'\\U-ff4'",                "3:",              "invalid 8-character unicode escape",
+    "'\\U+ff4'",                "3:",              "invalid 8-character unicode escape",
+    "'\\U'",                    "3:",              "invalid 8-character unicode escape",
+    "'\\U0'",                   "3-4:",            "invalid 8-character unicode escape",
+    "'\\UHELLO'",               "3:",              "invalid 8-character unicode escape",
+    "'\\U ff4'",                "3:",              "invalid 8-character unicode escape",
+    "'\\U0123456'",             "3-10:",           "invalid 8-character unicode escape",
+    "'\\U0xff4'",               "3-4:",            "invalid 8-character unicode escape",
   };
   guint i;
 
@@ -4674,8 +4690,8 @@ test_print_context (void)
     { NULL, "[1, 2, 3, 'str']", " ^        ^^^^^" },
     { G_VARIANT_TYPE_UINT16, "{ 'abc':'def' }", "  ^^^^^^^^^^^^^^^" },
     { NULL, "<5", "    ^" },
-    { NULL, "'ab\\ux'", "  ^^^^^^^" },
-    { NULL, "'ab\\U00efx'", "  ^^^^^^^^^^^" }
+    { NULL, "'ab\\ux'", "       ^ " },
+    { NULL, "'ab\\U00efx'", "       ^^^^  " }
   };
   GVariant *v;
   gchar *s;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]