Bug 87675 - Stack Overflow in function next_is_type_qual() in cp-demangle.c, as demonstrated by "nm -C"
Summary: Stack Overflow in function next_is_type_qual() in cp-demangle.c, as demonstr...
Status: UNCONFIRMED
Alias: None
Product: gcc
Classification: Unclassified
Component: demangler (show other bugs)
Version: unknown
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2018-10-21 13:00 UTC by N1705695H
Modified: 2018-10-29 14:18 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed:


Attachments
POC (280 bytes, text/plain)
2018-10-21 13:00 UTC, N1705695H
Details

Note You need to log in before you can comment on or make changes to this bug.
Description N1705695H 2018-10-21 13:00:41 UTC
Created attachment 44874 [details]
POC

An issue was discovered in cp-demangle.c in GNU libiberty, as distributed in GNU Binutils 2.31. Stack Exhaustion occurs in the C++ demangling functions provided by libiberty, and there is a stack consumption problem caused by recursive stack frames: next_is_type_qua() and cplus_demangle_type()

Please use the "./nm -C $POC" to reproduce the bug. This result can trigger different Stack Overflow, you can try several times.

To reproduce this bug. You need to build bintuils-2.31 with ASAN. Here is the compile Option. Another approach is to set the break Point and debug it, as the stack overflow didn't crash the program.

> CC=clang LDFLAGS="-ldl" CFLAGS="-DFORTIFY_SOURCE=2 -fstack-protector-all -fsanitize=undefined,address -fno-omit-frame-pointer -g -O0 -Wno-error" ./configure --disable-shared --disable-gdb --disable-libdecnumber --disable-sim

The ASAN dumps the stack trace as follows:

> ASAN:DEADLYSIGNAL
> =================================================================
> ==9864==ERROR: AddressSanitizer: stack-overflow on address 0x7fff9e5c9f58 (pc > 0x0000009684ac bp 0x000000000000 sp 0x7fff9e5c9f58 T0)
>     #0 0x9684ab in next_is_type_qual cp-demangle.c:2290
>     #1 0x9684ab in cplus_demangle_type cp-demangle.c:2387
>     #2 0x9684ab in next_is_type_qual cp-demangle.c:2290
>     #3 0x9684ab in cplus_demangle_type cp-demangle.c:2387
>     #4 0x9684ab in next_is_type_qual cp-demangle.c:2290
>     #5 0x9684ab in cplus_demangle_type cp-demangle.c:2387
>     #6 0x9684ab in next_is_type_qual cp-demangle.c:2290
>     #7 0x9684ab in cplus_demangle_type cp-demangle.c:2387
>     #8 0x9684ab in next_is_type_qual cp-demangle.c:2290
>     #9 0x9684ab in cplus_demangle_type cp-demangle.c:2387
>     #10 0x9684ab in next_is_type_qual cp-demangle.c:2290
>     #11 0x9684ab in cplus_demangle_type cp-demangle.c:2387
>     #12 0x9684ab in next_is_type_qual cp-demangle.c:2290
>     #13 0x9684ab in cplus_demangle_type cp-demangle.c:2387
>     #14 0x9684ab in next_is_type_qual cp-demangle.c:2290
>     #15 0x9684ab in cplus_demangle_type cp-demangle.c:2387
>     #16 0x9684ab in next_is_type_qual cp-demangle.c:2290
>     #17 0x9684ab in cplus_demangle_type cp-demangle.c:2387
>     #18 0x9684ab in next_is_type_qual cp-demangle.c:2290
>     #19 0x9684ab in cplus_demangle_type cp-demangle.c:2387
>     #20 0x9684ab in next_is_type_qual cp-demangle.c:2290
>     #21 0x9684ab in cplus_demangle_type cp-demangle.c:2387
>     ...
>     # 0xc5800000c22  (<unknown module>)

> SUMMARY: AddressSanitizer: stack-overflow cp-demangle.c:2290 in next_is_type_qual
> ==9864==ABORTING
> 00000000 AAborted
Comment 1 Michael Matz 2018-10-29 14:18:16 UTC
One of usual fuzzer fake CVEs.

This is basically a similar "problem" like initially reported in
  https://sourceware.org/bugzilla/show_bug.cgi?id=23008
where I actually analyzed it.  The problem is that C++ mangled names
have a recursive structure.  For demonstration purposes let's assume that the
character 'F' in a mangled name means "here come nested template arguments,
described next", then you need to recurse down to decode those nested args,
and if the next character is 'F' as well, you just recurse down again.  So
a mangled "name" with a million 'F' characters in succession will need
a recursion depth of a million.

So, when you feed the demangler such a name a stack overflow is expected.
Exactly when the overflow occurs depends on how the demangler is compiled,
i.e. how much stack space is needed from one to the next recursion level
(sometimes the recursion is tail recursion, so in some compilation modes
can even be elided and so lead to non-exhaustion).

Many characters of the mangled names have this property, so there are multiple
variants of names that all lead to stack exhaustion, so the fuzzers were able
to create many different testcases:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85122 (aka bugzilla PR23008)
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85452
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87335
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87636
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87675
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87681

Unfortunately they now also started to submit fake CVEs for these, like this
one (CVE-2018-18701) or CVE-2018-18700 (aka bug 87681).

If libiberty ever implements a check for this (which essentially can only be an
arbitrary limit, which is frowned upon, especially as it must be very small, as
people might have their stack limit set very low) fine, if not, also fine.
Until then feeding such names to any demangling tool leads to stack exhaustion
and hence segfault.  Like any other memory exhaustion not a security bug.