Bug 87602

Summary: Integer Overflow in cplus-dem.c in c++filt in bintuils which leads to Undefined-behavior(OOM in this POC)
Product: gcc Reporter: Cheng Wen <wcventure>
Component: demanglerAssignee: Not yet assigned to anyone <unassigned>
Status: RESOLVED DUPLICATE    
Severity: normal CC: webrown.cpp
Priority: P3    
Version: unknown   
Target Milestone: ---   
Host: Target:
Build: Known to work:
Known to fail: Last reconfirmed:
Bug Depends on: 83472    
Bug Blocks:    
Attachments: POC_input

Description Cheng Wen 2018-10-12 20:14:04 UTC
Created attachment 44830 [details]
POC_input

Hi. We are doing research on Fuzz testing. Our fuzzer caught an Out of Memory problem in program c++filt of the latest binutils(v2.31.1) code base, a malicious input of format strings will cause the LargeMmapAllocator faults and I have confirmed it with address sanitizer too. This Bug is caused by Integer Overflow.

The way to reproduce the bug:
I have provided the POC file and the input(_rttt4tttt6__H7666666666666666666__c). Please use the "./c++filt < $POC" to reproduce the bug. Another way to reproduce this bug is type "c++filt _rttt4tttt6__H7666666666666666666__c" directly. If you have any questions, please let me know.


The ASAN dumps the stack trace as follows:
cplus-dem.c:3597:10: runtime error: signed integer overflow: 766666666 * 10 cannot be represented in type 'int'
SUMMARY: AddressSanitizer: undefined-behavior cplus-dem.c:3597:10 in
==13543==WARNING: AddressSanitizer failed to allocate 0xfffffffd6ff55550 bytes
==13543==AddressSanitizer's allocator is terminating the process instead of returning 0
==13543==If you don't like this behavior set allocator_may_return_null=1
==13543==AddressSanitizer CHECK failed: /build/llvm-toolchain-3.8-_PD09B/llvm-toolchain-3.8-3.8/projects/compiler-rt/lib/sanitizer_common/sanitizer_allocator.cc:147 "((0))
)" (0x0, 0x0)
    #0 0x4c2a2d  (/media/hjwang/01D3344861A8D2E0/wcventure/Project/binutils_latest_AFL_ASAN/build/bin/c++filt+0x4c2a2d)
    #1 0x4c9653  (/media/hjwang/01D3344861A8D2E0/wcventure/Project/binutils_latest_AFL_ASAN/build/bin/c++filt+0x4c9653)
    #2 0x4c71d6  (/media/hjwang/01D3344861A8D2E0/wcventure/Project/binutils_latest_AFL_ASAN/build/bin/c++filt+0x4c71d6)
    #3 0x41efec  (/media/hjwang/01D3344861A8D2E0/wcventure/Project/binutils_latest_AFL_ASAN/build/bin/c++filt+0x41efec)
    #4 0x4b9401  (/media/hjwang/01D3344861A8D2E0/wcventure/Project/binutils_latest_AFL_ASAN/build/bin/c++filt+0x4b9401)
    #5 0x21e42be  (/media/hjwang/01D3344861A8D2E0/wcventure/Project/binutils_latest_AFL_ASAN/build/bin/c++filt+0x21e42be)
    #6 0x1ffc3b7  (/media/hjwang/01D3344861A8D2E0/wcventure/Project/binutils_latest_AFL_ASAN/build/bin/c++filt+0x1ffc3b7)
    #7 0x1fe8a17  (/media/hjwang/01D3344861A8D2E0/wcventure/Project/binutils_latest_AFL_ASAN/build/bin/c++filt+0x1fe8a17)
    #8 0x2039f37  (/media/hjwang/01D3344861A8D2E0/wcventure/Project/binutils_latest_AFL_ASAN/build/bin/c++filt+0x2039f37)
    #9 0x1fcbb2c  (/media/hjwang/01D3344861A8D2E0/wcventure/Project/binutils_latest_AFL_ASAN/build/bin/c++filt+0x1fcbb2c)
    #10 0x1fb8b23  (/media/hjwang/01D3344861A8D2E0/wcventure/Project/binutils_latest_AFL_ASAN/build/bin/c++filt+0x1fb8b23)
    #11 0x4eef03  (/media/hjwang/01D3344861A8D2E0/wcventure/Project/binutils_latest_AFL_ASAN/build/bin/c++filt+0x4eef03)
    #12 0x4ed203  (/media/hjwang/01D3344861A8D2E0/wcventure/Project/binutils_latest_AFL_ASAN/build/bin/c++filt+0x4ed203)
    #13 0x7f49e9d5182f  (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #14 0x419318  (/media/hjwang/01D3344861A8D2E0/wcventure/Project/binutils_latest_AFL_ASAN/build/bin/c++filt+0x419318)

Aborted
Comment 1 Cheng Wen 2018-10-15 09:12:37 UTC
In cplus-dem.c:3597
   n *= 10;
   n += *p - '0';
   p++;
This testcase will set n = 766666666. 766666666 * 10 cannot be represented in type 'int', which make n have a Integer overflow problem. This problem leads to undefined-behavior.


I will show you the debug process as follow:

> $ gdb --args ./c++filt _rttt4tttt6__H7666666666666666666_
> (gdb) start
> Temporary breakpoint 1 at 0x4ea9a6: file cxxfilt.c, line 172.
> Starting program: /build/bin/c++filt _rttt4tttt6__H7666666666666666666__c
> [Thread debugging using libthread_db enabled]
> Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
> Temporary breakpoint 1, main (argc=2, argv=0x7fffffffdff8) at cxxfilt.c:172
> 172     {
> (gdb) b cplus-dem.c:3597
> Breakpoint 2 at 0x20171b4: file ./cplus-dem.c, line 3597.
> (gdb) c
> Continuing.
> Breakpoint 2, get_count (type=<optimized out>, count=<optimized out>) at ./cplus-dem.c:3597
> 3597                  n *= 10;
> (gdb) n
> cplus-dem.c:3597:10: runtime error: signed integer overflow: 766666666 * 10 cannot be represented in type 'int'
> SUMMARY: AddressSanitizer: undefined-behavior cplus-dem.c:3597:10 in
> 3598                  n += *p - '0';
> (gdb) n
> 3599                  p++;
Comment 2 Cheng Wen 2018-10-16 14:21:15 UTC
I have further analyzed this bug. The variable n in function get_count (const char **type, int *count) have an Integer overflow problem. The value pass to the variable count.

> do
> {
>   n *= 10;
>   n += *p - '0';
>   p++;
>   }
>   while (ISDIGIT ((unsigned char)*p));
>   if (*p == '_')
>   {
>     *type = p + 1;
>     *count = n;
>   }

After that in XNEWVEC (char *, r); pass the *count as parameter

> work->tmpl_argvec = XNEWVEC (char *, r);

Finally malloc the negative size in /libiberty/./xmalloc.c:147:12.
Comment 3 Andrew Pinski 2018-10-31 06:47:28 UTC
Dup of bug 83472.

*** This bug has been marked as a duplicate of bug 83472 ***