libiberty: Fix some demangler crashes caused by reading past end of input.
authorMark Wielaard <mark@klomp.org>
Tue, 15 Nov 2016 19:31:50 +0000 (19:31 +0000)
committerMark Wielaard <mark@klomp.org>
Fri, 18 Nov 2016 10:06:18 +0000 (11:06 +0100)
In various situations the cplus_demangle () function could read past the
end of input causing crashes. Add checks in various places to not advance
the demangle string location and fail early when end of string is reached.
Add various examples of input strings to the testsuite that would crash
test-demangle before the fixes.

Found by using the American Fuzzy Lop (afl) fuzzer.

libiberty/ChangeLog:

       * cplus-dem.c (demangle_signature): After 'H', template function,
       no success and don't advance position if end of string reached.
       (demangle_template): After 'z', template name, return zero on
       premature end of string.
       (gnu_special): Guard strchr against searching for zero characters.
       (do_type): If member, only advance mangled string when 'F' found.
       * testsuite/demangle-expected: Add examples of strings that could
       crash the demangler by reading past end of input.

libiberty/ChangeLog
libiberty/cplus-dem.c
libiberty/testsuite/demangle-expected

index d0c5595fce606e1cdd58e0e6bd9c213af04162c5..ea12ba277a028d7bd125d1234ae29965c347f53a 100644 (file)
@@ -1,3 +1,14 @@
+2016-11-14  Mark Wielaard  <mark@klomp.org>
+
+       * cplus-dem.c (demangle_signature): After 'H', template function,
+       no success and don't advance position if end of string reached.
+       (demangle_template): After 'z', template name, return zero on
+       premature end of string.
+       (gnu_special): Guard strchr against searching for zero characters.
+       (do_type): If member, only advance mangled string when 'F' found.
+       * testsuite/demangle-expected: Add examples of strings that could
+       crash the demangler by reading past end of input.
+
 2016-11-06  Mark Wielaard  <mark@klomp.org>
 
        * configure.ac (ac_libiberty_warn_cflags): Add -Wshadow=local.
index c955bfbe1e7d768b452a5ee24141c4581b3b7849..3125a457b9d9800095ea863cacb0d0ba013c5f30 100644 (file)
@@ -1654,7 +1654,10 @@ demangle_signature (struct work_stuff *work,
                                           0);
              if (!(work->constructor & 1))
                expect_return_type = 1;
-             (*mangled)++;
+             if (!**mangled)
+               success = 0;
+             else
+               (*mangled)++;
              break;
            }
          /* fall through */
@@ -2133,6 +2136,8 @@ demangle_template (struct work_stuff *work, const char **mangled,
        {
          int idx;
          (*mangled)++;
+         if (**mangled == '\0')
+           return (0);
          (*mangled)++;
 
          idx = consume_count_with_underscores (mangled);
@@ -2977,7 +2982,7 @@ gnu_special (struct work_stuff *work, const char **mangled, string *declp)
   int success = 1;
   const char *p;
 
-  if ((*mangled)[0] == '_'
+  if ((*mangled)[0] == '_' && (*mangled)[1] != '\0'
       && strchr (cplus_markers, (*mangled)[1]) != NULL
       && (*mangled)[2] == '_')
     {
@@ -2991,7 +2996,7 @@ gnu_special (struct work_stuff *work, const char **mangled, string *declp)
                && (*mangled)[3] == 't'
                && (*mangled)[4] == '_')
               || ((*mangled)[1] == 'v'
-                  && (*mangled)[2] == 't'
+                  && (*mangled)[2] == 't' && (*mangled)[3] != '\0'
                   && strchr (cplus_markers, (*mangled)[3]) != NULL)))
     {
       /* Found a GNU style virtual table, get past "_vt<CPLUS_MARKER>"
@@ -3761,11 +3766,12 @@ do_type (struct work_stuff *work, const char **mangled, string *result)
                    break;
                  }
 
-               if (*(*mangled)++ != 'F')
+               if (*(*mangled) != 'F')
                  {
                    success = 0;
                    break;
                  }
+               (*mangled)++;
              }
            if ((member && !demangle_nested_args (work, mangled, &decl))
                || **mangled != '_')
index 5badc3e58493bfd894b0250c84f8c4bc35dbabfd..236161c2fe378fc29b766627fae110d9d37ee67b 100644 (file)
@@ -4606,3 +4606,23 @@ void f<void, int, false>(void (*)(int) noexcept)
 
 _Z1fIvJiELb0EEvPDwiEFT_DpT0_E
 void f<void, int, false>(void (*)(int) throw(int))
+
+# Could crash
+_
+_
+
+# Could crash
+_vt
+_vt
+
+# Could crash
+_$_1Acitz
+_$_1Acitz
+
+# Could crash
+_$_H1R
+_$_H1R
+
+# Could crash
+_Q8ccQ4M2e.
+_Q8ccQ4M2e.