[Bug c++/87335] New: The stack overflow in function cplus_demangle_type in cp-demangle.c:2565 (c++filt -t)

classic Classic list List threaded Threaded
14 messages Options
Reply | Threaded
Open this post in threaded view
|

[Bug c++/87335] New: The stack overflow in function cplus_demangle_type in cp-demangle.c:2565 (c++filt -t)

kargl at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87335

            Bug ID: 87335
           Summary: The stack overflow in function cplus_demangle_type in
                    cp-demangle.c:2565 (c++filt -t)
           Product: gcc
           Version: unknown
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: wcventure at 126 dot com
  Target Milestone: ---

Created attachment 44706
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=44706&action=edit
Stack_overflow_in_c++filt-t

Hi,

We have found a stack overflow in function cplus_demangle_type in
cp-demangle.c:2565 in c++filt of the latest binutils code base.

Here is the POC file. Please use the “c++filt -t < $POC ” to reproduce the bug.
Thank you very much.


Command:“c++filt -t < $POC ” (Please remember to use the option -t)

AddressSanitizer:DEADLYSIGNAL
=================================================================
==21814==ERROR: AddressSanitizer: stack-overflow on address 0x7ffcafaefbc0 (pc
0x0000008d3eb1 bp 0x7ffcafaf02d0 sp 0x7ffcafaefbc0 T0)
    #0 0x8d3eb0 in cplus_demangle_type
/binutils-2.31/libiberty/./cp-demangle.c:2367
    #1 0x8d523c in cplus_demangle_type
/binutils-2.31/libiberty/./cp-demangle.c:2565:5
    #2 0x8d523c in cplus_demangle_type
/binutils-2.31/libiberty/./cp-demangle.c:2565:5
    #3 0x8d523c in cplus_demangle_type
/binutils-2.31/libiberty/./cp-demangle.c:2565:5
    #4 0x8d523c in cplus_demangle_type
/binutils-2.31/libiberty/./cp-demangle.c:2565:5
    #5 0x8d523c in cplus_demangle_type
/binutils-2.31/libiberty/./cp-demangle.c:2565:5
    #6 0x8d523c in cplus_demangle_type
/binutils-2.31/libiberty/./cp-demangle.c:2565:5
    #7 0x8d523c in cplus_demangle_type
/binutils-2.31/libiberty/./cp-demangle.c:2565:5
    #8 0x8d523c in cplus_demangle_type
/binutils-2.31/libiberty/./cp-demangle.c:2565:5
    #9 0x8d523c in cplus_demangle_type
/binutils-2.31/libiberty/./cp-demangle.c:2565:5
    ...
    ...
    ...
    #246 0x8d523c in cplus_demangle_type
/binutils-2.31/libiberty/./cp-demangle.c:2565:5
    #247 0x8d523c in cplus_demangle_type
/binutils-2.31/libiberty/./cp-demangle.c:2565:5
    #248 0x8d523c in cplus_demangle_type
/binutils-2.31/libiberty/./cp-demangle.c:2565:5
    #249 0x8d523c in cplus_demangle_type
/binutils-2.31/libiberty/./cp-demangle.c:2565:5

SUMMARY: AddressSanitizer: stack-overflow
/binutils-2.31/libiberty/./cp-demangle.c:2367 in cplus_demangle_type
==21814==ABORTING
Aborted
Reply | Threaded
Open this post in threaded view
|

[Bug c++/87335] The stack overflow in function cplus_demangle_type in cp-demangle.c:2565 (c++filt -t)

kargl at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87335

Martin Liška <marxin at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |marxin at gcc dot gnu.org

--- Comment #1 from Martin Liška <marxin at gcc dot gnu.org> ---
Is the input a valid C++ mangled name of not?
Reply | Threaded
Open this post in threaded view
|

[Bug c++/87335] The stack overflow in function cplus_demangle_type in cp-demangle.c:2565 (c++filt -t)

kargl at gcc dot gnu.org
In reply to this post by kargl at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87335

--- Comment #2 from Cheng Wen <wcventure at 126 dot com> ---
(In reply to Martin Liška from comment #1)
> Is the input a valid C++ mangled name of not?

Hi,
This input is obtained through fuzzing technology. Our fuzzer get some test
cases by mutating a valid input. This can not guarantee that this is a valid
C++ mangled name.

The program c++filt accepts the test case I uploaded. And this test case can
prove that c++filt have problems. When program c++filt executing this input, a
stack-overflow problem occurs. Please check this input and try to fix this bug
if necessary.

Thank you very much.
Reply | Threaded
Open this post in threaded view
|

[Bug c++/87335] The stack overflow in function cplus_demangle_type in cp-demangle.c:2565 (c++filt -t)

kargl at gcc dot gnu.org
In reply to this post by kargl at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87335

--- Comment #3 from Jonathan Wakely <redi at gcc dot gnu.org> ---
No, it's not a valid name. I can't reproduce a crash using the latest code from
GCC though.
Reply | Threaded
Open this post in threaded view
|

[Bug c++/87335] The stack overflow in function cplus_demangle_type in cp-demangle.c:2565 (c++filt -t)

kargl at gcc dot gnu.org
In reply to this post by kargl at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87335

Jonathan Wakely <redi at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|UNCONFIRMED                 |WAITING
   Last reconfirmed|                            |2018-09-18
     Ever confirmed|0                           |1

--- Comment #4 from Jonathan Wakely <redi at gcc dot gnu.org> ---
Are you sure you attached the right file? When I try to demangle the attachment
it doesn't crash, the __cxa_demangle file returns -2, meaning the name is not
valid. That seems like the right result.
Reply | Threaded
Open this post in threaded view
|

[Bug c++/87335] The stack overflow in function cplus_demangle_type in cp-demangle.c:2565 (c++filt -t)

kargl at gcc dot gnu.org
In reply to this post by kargl at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87335

--- Comment #5 from Cheng Wen <wcventure at 126 dot com> ---
(In reply to Jonathan Wakely from comment #4)
> Are you sure you attached the right file? When I try to demangle the
> attachment it doesn't crash, the __cxa_demangle file returns -2, meaning the
> name is not valid. That seems like the right result.

I have tried to reproduce this bug on different machines.
There are some questions to be confirmed.

(1) Do you use the latest version of binutils(binutils-2.32/binutils-2.31)? I
downloaded the package from here.
https://www.gnu.org/software/binutils/

(2) Please confirm that you have used the option "-t".
The command should be "./c++filt -t < $POC"

(3) Do you confirm this POC with address sanitizer?
Reply | Threaded
Open this post in threaded view
|

[Bug c++/87335] The stack overflow in function cplus_demangle_type in cp-demangle.c:2565 (c++filt -t)

kargl at gcc dot gnu.org
In reply to this post by kargl at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87335

--- Comment #6 from Jonathan Wakely <redi at gcc dot gnu.org> ---
(In reply to Cheng Wen from comment #5)

> (In reply to Jonathan Wakely from comment #4)
> > Are you sure you attached the right file? When I try to demangle the
> > attachment it doesn't crash, the __cxa_demangle file returns -2, meaning the
> > name is not valid. That seems like the right result.
>
> I have tried to reproduce this bug on different machines.
> There are some questions to be confirmed.
>
> (1) Do you use the latest version of binutils(binutils-2.32/binutils-2.31)?
> I downloaded the package from here.
> https://www.gnu.org/software/binutils/

Built from the binutils-gdb git repo:

$ /tmp/binutils/bin/c++filt -v
GNU c++filt (GNU Binutils) 2.31.51.20180918
Copyright (C) 2018 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or (at your option) any later version.
This program has absolutely no warranty.


> (2) Please confirm that you have used the option "-t".
> The command should be "./c++filt -t < $POC"

$ /tmp/binutils/bin/c++filt -t < POC-t | wc
      0       1   26539
$ echo $?
0


> (3) Do you confirm this POC with address sanitizer?

Yes it's linked to libasan

$ ldd /tmp/binutils/bin/c++filt
        linux-vdso.so.1 (0x00007fff0618b000)
        libasan.so.4 => /lib64/libasan.so.4 (0x00007fc372241000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007fc37203d000)
        libc.so.6 => /lib64/libc.so.6 (0x00007fc371c87000)
        librt.so.1 => /lib64/librt.so.1 (0x00007fc371a7f000)
        libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fc371861000)
        libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007fc3714d9000)
        libm.so.6 => /lib64/libm.so.6 (0x00007fc37118e000)
        libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007fc370f77000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fc3731f9000)
Reply | Threaded
Open this post in threaded view
|

[Bug c++/87335] The stack overflow in function cplus_demangle_type in cp-demangle.c:2565 (c++filt -t)

kargl at gcc dot gnu.org
In reply to this post by kargl at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87335

--- Comment #7 from Cheng Wen <wcventure at 126 dot com> ---
(In reply to Jonathan Wakely from comment #6)

Considering the memory size of different machines, maybe more 'P' is needed to
trigger this bug in the input.
Reply | Threaded
Open this post in threaded view
|

[Bug c++/87335] The stack overflow in function cplus_demangle_type in cp-demangle.c:2565 (c++filt -t)

kargl at gcc dot gnu.org
In reply to this post by kargl at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87335

--- Comment #8 from Jonathan Wakely <redi at gcc dot gnu.org> ---
It still works for up to ten million characters:

$ for i in `seq 1 10` ; do printf P ; done | /tmp/binutils/bin/c++filt -t ;
echo
PPPPPPPPPP
$ for i in `seq 1 100` ; do printf P ; done | /tmp/binutils/bin/c++filt -t | wc
      0       1     100
$ for i in `seq 1 1000` ; do printf P ; done | /tmp/binutils/bin/c++filt -t |
wc
      0       1    1000
$ for i in `seq 1 10000` ; do printf P ; done | /tmp/binutils/bin/c++filt -t |
wc
      0       1   10000
$ for i in `seq 1 100000` ; do printf P ; done | /tmp/binutils/bin/c++filt -t |
wc
      0       1  100000
$ for i in `seq 1 1000000` ; do printf P ; done | /tmp/binutils/bin/c++filt -t
| wc
      0       1 1000000
$ for i in `seq 1 10000000` ; do printf P ; done | /tmp/binutils/bin/c++filt -t
| wc
      0       1 10000000
Reply | Threaded
Open this post in threaded view
|

[Bug c++/87335] The stack overflow in function cplus_demangle_type in cp-demangle.c:2565 (c++filt -t)

kargl at gcc dot gnu.org
In reply to this post by kargl at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87335

--- Comment #9 from Cheng Wen <wcventure at 126 dot com> ---
(In reply to Jonathan Wakely from comment #8)

Hi Jonathan,

I debugged with this POC again. I still think it's a problem. I will show you
the debug process as follow.

> $ gdb ./c++filt
> Reading symbols from ./c++filt...done.
> (gdb) set args -t < POC-t
> (gdb) b cp-demangle.c:2565
> Breakpoint 1 at 0x8d5227: file ./cp-demangle.c, line 2565.
> (gdb) start
> (gdb) c
> Continuing.
> Breakpoint 1, cplus_demangle_type (di=0x7fffffffd560) at ./cp-demangle.c:2565
> 2565 cplus_demangle_type (di), NULL);
> (gdb) c
> Continuing.
> Breakpoint 1, cplus_demangle_type (di=0x7fffffffd560) at ./cp-demangle.c:2565
> 2565 cplus_demangle_type (di), NULL);
> ...
> ...
> ...
> (gdb) c
> Continuing.
> Breakpoint 1, cplus_demangle_type (di=0x7fffffffd560) at ./cp-demangle.c:2565
> 2565 cplus_demangle_type (di), NULL);
> (gdb) bt
> #0  cplus_demangle_type (di=0x7fffffffd560) at ./cp-demangle.c:2565
> #1  0x00000000008d523d in cplus_demangle_type (di=0x7fffffffd560) at ./cp-demangle.c:2565
> #2  0x00000000008d523d in cplus_demangle_type (di=0x7fffffffd560) at ./cp-demangle.c:2565
> #3  0x00000000008d523d in cplus_demangle_type (di=0x7fffffffd560) at ./cp-demangle.c:2565
> #4  0x00000000008d523d in cplus_demangle_type (di=0x7fffffffd560) at ./cp-demangle.c:2565
> ...
> ...
> ...
> #456 0x00000000008d523d in cplus_demangle_type (di=0x7fffffffd560) at ./cp-demangle.c:2565
> #457 0x00000000008d523d in cplus_demangle_type (di=0x7fffffffd560) at ./cp-demangle.c:2565
> #458 0x00000000008dd318 in d_demangle_callback (mangled=0x18b2e40 <main.mbuffer> 'P' <repeats 200 times>..., options=283,
>   callback=0x8dc110 <d_growable_string_callback_adapter>, opaque=0x7fffffffd860) at ./cp-demangle.c:6245
> #459 0x00000000008dc84f in d_demangle (mangled=0x18b2e40 <main.mbuffer> 'P' <repeats 200 times>..., options=283,
>   palc=0x7fffffffd9e0) at ./cp-demangle.c:6299
> #460 0x00000000008dc696 in cplus_demangle_v3 (mangled=0x18b2e40 <main.mbuffer> 'P' <repeats 200 times>..., options=283)
>   at ./cp-demangle.c:6456
> #461 0x00000000008b1cf4 in cplus_demangle (mangled=0x18b2e40 <main.mbuffer> 'P' <repeats 200 times>..., options=27)
>   at ./cplus-dem.c:880
> #462 0x0000000000517676 in demangle_it (mangled_name=0x18b2e40 <main.mbuffer> 'P' <repeats 200 times>...) at cxxfilt.c:62
> #463 0x000000000051726a in main (argc=2, argv=0x7fffffffe008) at cxxfilt.c:276


Using gdb to debug it. I set a breakpoint in cp-demangle.c:2565. After reaching
this breakpoint for any time. You can see the stack backtrace.
This will consume a lot of stack memory.
(Caution: the command such as "gdb --args ./c++filt -t < $POC" is not valid.
Please use "gdb ./c++filt", then "set args -t < $POC")

Thanks
Cheng Wen
Reply | Threaded
Open this post in threaded view
|

[Bug c++/87335] The stack overflow in function cplus_demangle_type in cp-demangle.c:2565 (c++filt -t)

kargl at gcc dot gnu.org
In reply to this post by kargl at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87335

Scott Gayou <sgayou at redhat dot com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |sgayou at redhat dot com

--- Comment #10 from Scott Gayou <sgayou at redhat dot com> ---
This reproducer seems to require adjusting the maximum stack size.

i.e.:

$ ulimit -s 8192 && c++filt < poc -t

does NOT crash

whereas:

$ ulimit -s 2048 && c++filt < poc -t
Segmentation fault (core dumped)

This looks to be another potentially duplicated CVE.

See the following:

CVE-2018-18484: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87636
CVE-2018-18701: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87675
CVE-2018-18700: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87681

All appear to be the same root cause.
Reply | Threaded
Open this post in threaded view
|

[Bug c++/87335] The stack overflow in function cplus_demangle_type in cp-demangle.c:2565 (c++filt -t)

kargl at gcc dot gnu.org
In reply to this post by kargl at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87335

--- Comment #11 from Cheng Wen <wcventure at 126 dot com> ---
(In reply to Scott Gayou from comment #10)

> does NOT crash

That depends on your compilation options. Because stack memory is very small,
generally only 1M to 2M. You can debug it with GDB and see the backtrace.

> This looks to be another potentially duplicated CVE.

Unlike several other errors, this error is to call itself. In addition, This
problem was discovered earlier than those CVEs.

> All appear to be the same root cause.

Let's analyze the source code.

struct demangle_component *
cplus_demangle_type (struct d_info *di) {
  switch (peek)
  {
    // ...
    case 'F':
      ret = d_function_type (di); break;
    // ...
    case 'P':
      ret = d_make_comp (di, DEMANGLE_COMPONENT_POINTER,
                         cplus_demangle_type (di), NULL);
      break;
    case 'C':
      ret = d_make_comp (di, DEMANGLE_COMPONENT_COMPLEX,
                         cplus_demangle_type (di), NULL);
      break;
    case 'G':
      ret = d_make_comp (di, DEMANGLE_COMPONENT_IMAGINARY,
                         cplus_demangle_type (di), NULL);
      break;
    // ...
  }
  // ...
}

Intuitively, in some cases, function cplus_demangle_type shows the behavior of
recursive calls. When the function cplus_demangle_type receive character
'P'(The same as 'C' and 'G'), the cplus_demangle_type function making recursive
calls to itself(Line 13, 18, 23). Another situation is that the function
receive character 'F', then there's a recursed stack frame:
cplus_demangle_type, d_bare_function_type, d_function_type(Line 8, 32, 39).

So different stack memory exhaustion can lead to stack memory exhaustion DoS.
That depends on your compilation options. You can use my compilation options.

> 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

If you have any question, please let me know.
Reply | Threaded
Open this post in threaded view
|

[Bug c++/87335] The stack overflow in function cplus_demangle_type in cp-demangle.c:2565 (c++filt -t)

kargl at gcc dot gnu.org
In reply to this post by kargl at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87335

--- Comment #12 from Nick Clifton <nickc at gcc dot gnu.org> ---
Author: nickc
Date: Fri Dec  7 10:33:30 2018
New Revision: 266886

URL: https://gcc.gnu.org/viewcvs?rev=266886&root=gcc&view=rev
Log:
Add a recursion limit to libiberty's demangling code.  The limit is enabled by
default, but can be disabled via a new demangling option.

include * demangle.h (DMGL_NO_RECURSE_LIMIT): Define.
        (DEMANGLE_RECURSION_LIMIT): Define

        PR 87681
        PR 87675
        PR 87636
        PR 87350
        PR 87335
libiberty * cp-demangle.h (struct d_info): Add recursion_level field.
        * cp-demangle.c (d_function_type): Add recursion counter.
        If the recursion limit is reached and the check is not disabled,
        then return with a failure result.
        (cplus_demangle_init_info): Initialise the recursion_level field.
        (d_demangle_callback): If the recursion limit is enabled, check
        for a mangled string that is so long that there is not enough
        stack space for the local arrays.
        * cplus-dem.c (struct work): Add recursion_level field.
        (squangle_mop_up): Set the numb and numk fields to zero.
        (work_stuff_copy_to_from): Handle the case where a btypevec or
        ktypevec field is NULL.
        (demangle_nested_args): Add recursion counter.  If
        the recursion limit is not disabled and reached, return with a
        failure result.

Modified:
    trunk/include/ChangeLog
    trunk/include/demangle.h
    trunk/libiberty/ChangeLog
    trunk/libiberty/cp-demangle.c
    trunk/libiberty/cp-demangle.h
    trunk/libiberty/cplus-dem.c
Reply | Threaded
Open this post in threaded view
|

[Bug c++/87335] The stack overflow in function cplus_demangle_type in cp-demangle.c:2565 (c++filt -t)

kargl at gcc dot gnu.org
In reply to this post by kargl at gcc dot gnu.org
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87335

Nick Clifton <nickc at gcc dot gnu.org> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|WAITING                     |RESOLVED
                 CC|                            |nickc at gcc dot gnu.org
         Resolution|---                         |FIXED

--- Comment #13 from Nick Clifton <nickc at gcc dot gnu.org> ---
Fixed by commit 266886.