Bug 21665 - Multiple heap based buffer overflow in the objdump tool of the GNU Binutils.
Summary: Multiple heap based buffer overflow in the objdump tool of the GNU Binutils.
Status: RESOLVED FIXED
Alias: None
Product: binutils
Classification: Unclassified
Component: binutils (show other bugs)
Version: 2.28
: P2 critical
Target Milestone: 2.29
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-06-23 15:01 UTC by owl337
Modified: 2017-07-01 23:04 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed: 2017-06-26 00:00:00


Attachments
./objdump -S $POC (65.15 KB, application/x-rar)
2017-06-23 15:01 UTC, owl337
Details

Note You need to log in before you can comment on or make changes to this bug.
Description owl337 2017-06-23 15:01:10 UTC
Created attachment 10217 [details]
./objdump  -S $POC

The first heap overflow debug information is below:

$ ./objdump -S POC1

...


Disassembly of section .init:

0000000000401ab0 <.init>:
=================================================================
==14591==ERROR: AddressSanitizer: heap-buffer-overflow on address 0xf4c00bf4 at pc 0xf72e3c75 bp 0xffa3a548 sp 0xffa3a11c
READ of size 148 at 0xf4c00bf4 thread T0
    #0 0xf72e3c74 in __asan_memcpy (/usr/lib32/libasan.so.2+0x8ac74)
    #1 0xf72e3e2f in memcpy (/usr/lib32/libasan.so.2+0x8ae2f)
    #2 0x824edca in get_build_id /home/icy/real/binutils-2.28/bfd/opncls.c:1833
    #3 0x825e675 in get_build_id /home/icy/real/binutils-2.28/bfd/opncls.c:1782
    #4 0x825e675 in get_build_id_name /home/icy/real/binutils-2.28/bfd/opncls.c:1875
    #5 0x825e675 in find_separate_debug_file /home/icy/real/binutils-2.28/bfd/opncls.c:1386
    #6 0x825e675 in bfd_follow_build_id_debuglink /home/icy/real/binutils-2.28/bfd/opncls.c:1989
    #7 0x84c132d in _bfd_dwarf2_slurp_debug_info dwarf2.c:3920
    #8 0x84c6a40 in _bfd_dwarf2_find_nearest_line dwarf2.c:4115
    #9 0x839a408 in _bfd_elf_find_nearest_line /home/icy/real/binutils-2.28/bfd/elf.c:8565
    #10 0x8073c06 in show_line objdump.c:1434
    #11 0x8073c06 in disassemble_bytes objdump.c:1728
    #12 0x8073c06 in disassemble_section objdump.c:2241
    #13 0x82641fc in bfd_map_over_sections /home/icy/real/binutils-2.28/bfd/section.c:1395
    #14 0x8068597 in disassemble_data objdump.c:2375
    #15 0x8068597 in dump_bfd objdump.c:3469
    #16 0x806b0ce in display_object_bfd objdump.c:3526
    #17 0x806b0ce in display_any_bfd objdump.c:3615
    #18 0x8056562 in display_file objdump.c:3636
    #19 0x8056562 in main objdump.c:3919
    #20 0xf70b479d in __libc_start_main (/lib32/libc.so.6+0x1879d)
    #21 0x805944b  (/home/icy/real/binutils-2.28/binutils/objdump+0x805944b)

0xf4c00bf4 is located 0 bytes to the right of 36-byte region [0xf4c00bd0,0xf4c00bf4)
allocated by thread T0 here:
    #0 0xf72eff06 in malloc (/usr/lib32/libasan.so.2+0x96f06)
    #1 0x8247518 in bfd_malloc /home/icy/real/binutils-2.28/bfd/libbfd.c:184

SUMMARY: AddressSanitizer: heap-buffer-overflow ??:0 __asan_memcpy
Shadow bytes around the buggy address:
  0x3e980120: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x3e980130: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x3e980140: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x3e980150: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x3e980160: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x3e980170: fa fa fa fa fa fa fa fa fa fa 00 00 00 00[04]fa
  0x3e980180: fa fa fd fd fd fd fd fd fa fa fd fd fd fd fd fd
  0x3e980190: fa fa fd fd fd fd fd fd fa fa 00 00 00 00 04 fa
  0x3e9801a0: fa fa fd fd fd fd fd fd fa fa 00 00 00 00 04 fa
  0x3e9801b0: fa fa fd fd fd fd fd fd fa fa 00 00 00 00 04 fa
  0x3e9801c0: fa fa fd fd fd fd fd fd fa fa 00 00 00 00 04 fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Heap right redzone:      fb
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack partial redzone:   f4
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
==14591==ABORTING

Crash happended at line bfd/opncls.c:1833. The function tries to copy inote.descsz bytes from  inote.descdata to build_id->data, but it didn't take the situation that value inote.descsz is larger than inote.descdata into account.

1771 static struct bfd_build_id *
1772 get_build_id (bfd *abfd)
1773 {
...
1825   build_id = bfd_alloc (abfd, sizeof (struct bfd_build_id) + inote.descsz);
1826   if (build_id == NULL)
1827     {
1828       free (contents);
1829       return NULL;
1830     }
1831 
1832   build_id->size = inote.descsz;
1833   memcpy (build_id->data, inote.descdata, inote.descsz);
1834   abfd->build_id = build_id;
1835   free (contents);
1836 
1837   return build_id;
1838 }
...





The second heap overflow debug information is below:

$ ./objdump  -S POC2
fuzz/objdump/output/crashes/id:000008,sig:06,src:000000,op:flip1,pos:92180:     file format elf64-x86-64

Disassembly of section .init:

0000000000401ab0 <.init>:
      401ab0:	be be be be be       	mov    $0xbebebebe,%esi
      401ab5:	be be be be be       	mov    $0xbebebebe,%esi
      401aba:	be be be be be       	mov    $0xbebebebe,%esi
      401abf:	be be be be be       	mov    $0xbebebebe,%esi
      401ac4:	be be be be be       	mov    $0xbebebebe,%esi
      401ac9:	be                   	.byte 0xbe
=================================================================
==96445==ERROR: AddressSanitizer: heap-buffer-overflow on address 0xf4300b0a at pc 0x0807eefe bp 0xffad0b58 sp 0xffad0b48
READ of size 1 at 0xf4300b0a thread T0
    #0 0x807eefd in disassemble_bytes objdump.c:1692
    #1 0x807eefd in disassemble_section objdump.c:2241
    #2 0x82641fc in bfd_map_over_sections /home/icy/real/binutils-2.28/bfd/section.c:1395
    #3 0x8068597 in disassemble_data objdump.c:2375
    #4 0x8068597 in dump_bfd objdump.c:3469
    #5 0x806b0ce in display_object_bfd objdump.c:3526
    #6 0x806b0ce in display_any_bfd objdump.c:3615
    #7 0x8056562 in display_file objdump.c:3636
    #8 0x8056562 in main objdump.c:3919
    #9 0xf6fbc79d in __libc_start_main (/lib32/libc.so.6+0x1879d)
    #10 0x805944b  (/home/icy/real/binutils-2.28/binutils/objdump+0x805944b)

0xf4300b0a is located 0 bytes to the right of 26-byte region [0xf4300af0,0xf4300b0a)
allocated by thread T0 here:
    #0 0xf71f7f06 in malloc (/usr/lib32/libasan.so.2+0x96f06)
    #1 0x88832a7 in xmalloc xmalloc.c:148

SUMMARY: AddressSanitizer: heap-buffer-overflow objdump.c:1692 disassemble_bytes
Shadow bytes around the buggy address:
  0x3e860110: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x3e860120: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x3e860130: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x3e860140: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x3e860150: fa fa fa fa fa fa fa fa fd fd fd fd fa fa 00 00
=>0x3e860160: 00[02]fa fa 00 00 00 04 fa fa 00 00 00 04 fa fa
  0x3e860170: fd fd fd fd fa fa 00 00 03 fa fa fa 00 00 05 fa
  0x3e860180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x3e860190: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x3e8601a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x3e8601b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Heap right redzone:      fb
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack partial redzone:   f4
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
==96445==ABORTING

The array data accesses uninitialized memory in line objdump.c:1692.

1615 static void
1616 disassemble_bytes (struct disassemble_info * inf,
...
1687       aux->reloc = NULL;
1688 
1689       /* If we see more than SKIP_ZEROES octets of zeroes, we just
1690          print `...'.  */
1691       for (z = addr_offset * opb; z < stop_offset * opb; z++)
1692         if (data[z] != 0)
1693           break;
1694       if (! disassemble_zeroes
...

Credits:

This vulnerability is detected by team OWL337, with our custom fuzzer collAFL. Please contact ganshuitao@gmail.com   and chaoz@tsinghua.edu.cn if you need more info about the team, the tool or the vulnerability.
Comment 1 Sourceware Commits 2017-06-26 14:26:36 UTC
The master branch has been updated by Nick Clifton <nickc@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=cfd14a500e0485374596234de4db10e88ebc7618

commit cfd14a500e0485374596234de4db10e88ebc7618
Author: Nick Clifton <nickc@redhat.com>
Date:   Mon Jun 26 15:25:08 2017 +0100

    Fix address violations when atempting to parse fuzzed binaries.
    
    	PR binutils/21665
    bfd	* opncls.c (get_build_id): Check that the section is beig enough
    	to contain the whole note.
    	* compress.c (bfd_get_full_section_contents): Check for and reject
    	a section whoes size is greater than the size of the entire file.
    	* elf32-v850.c (v850_elf_copy_notes): Allow for the ouput to not
    	contain a notes section.
    
    binutils* objdump.c (disassemble_section): Skip any section that is bigger
    	than the entire file.
Comment 2 Nick Clifton 2017-06-26 14:33:08 UTC
Hi Owl,

  Thanks for reporting these bugs.  I have checked in a patch which should
  address both issues, but if you find that either of the files still causes
  faults when you test them please feel free to reopen this PR.

Cheers
  Nick
Comment 3 H.J. Lu 2017-06-26 15:21:47 UTC
(In reply to cvs-commit@gcc.gnu.org from comment #1)
> The master branch has been updated by Nick Clifton <nickc@sourceware.org>:
> 
> https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;
> h=cfd14a500e0485374596234de4db10e88ebc7618
> 
> commit cfd14a500e0485374596234de4db10e88ebc7618
> Author: Nick Clifton <nickc@redhat.com>
> Date:   Mon Jun 26 15:25:08 2017 +0100
> 
>     Fix address violations when atempting to parse fuzzed binaries.
>     
>     	PR binutils/21665
>     bfd	* opncls.c (get_build_id): Check that the section is beig enough
>     	to contain the whole note.
>     	* compress.c (bfd_get_full_section_contents): Check for and reject
>     	a section whoes size is greater than the size of the entire file.
>     	* elf32-v850.c (v850_elf_copy_notes): Allow for the ouput to not
>     	contain a notes section.
>     
>     binutils* objdump.c (disassemble_section): Skip any section that is
> bigger
>     	than the entire file.

This patch caused:

FAIL: Build libfoo.so with compressed debug sections
FAIL: Build libbar.so with compressed debug sections
FAIL: Build libfoozlib.so with compressed debug sections with zlib-gabi
FAIL: Build libbarzlib.so with compressed debug sections with zlib-gabi
FAIL: Build libzlibfoo.so with zlib compressed debug sections
FAIL: Build libgnufoo.so with zlib-gnu compressed debug sections
FAIL: Build libgabifoo.so with zlib-gabi compressed debug sections
FAIL: Build gabiend.o with zlib-gabi compressed debug sections
FAIL: Run normal with libfoo.so with compressed debug sections
FAIL: Run normal with libfoozlib.so with compressed debug sections with zlib-gabi
FAIL: Run zlibnormal with libzlibfoo.so with zlib compressed debug sections
FAIL: Run zlibnormal with libfoozlib.so with zlib compressed debug sections
FAIL: Run gnunormal with libgnufoo.so with zlib-gnu compressed debug sections
FAIL: Run gnunormal with libfoozlib.so with zlib-gnu compressed debug sections
FAIL: Run gabinormal with libgabifoo.so with zlib-gabi compressed debug sections
FAIL: Run gabinormal with libfoozlib.so with zlib-gabi compressed debug sections
FAIL: Link with zlib-gabi compressed debug input
FAIL: Link -r with zlib-gabi compressed debug output
FAIL: Link with zlib compressed debug output
FAIL: Link with zlib-gnu compressed debug output
FAIL: Link with zlib-gabi compressed debug output

with GCC 4.2 on x86-64.
Comment 4 Sourceware Commits 2017-06-26 16:31:33 UTC
The master branch has been updated by H.J. Lu <hjl@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=0630b49c470ca2e3c3f74da4c7e4ff63440dd71f

commit 0630b49c470ca2e3c3f74da4c7e4ff63440dd71f
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Mon Jun 26 09:24:49 2017 -0700

    Check file size before getting section contents
    
    Don't check the section size in bfd_get_full_section_contents since
    the size of a decompressed section may be larger than the file size.
    Instead, check file size in _bfd_generic_get_section_contents.
    
    	PR binutils/21665
    	* compress.c (bfd_get_full_section_contents): Don't check the
    	file size here.
    	* libbfd.c (_bfd_generic_get_section_contents): Check for and
    	reject a section whoes size + offset is greater than the size
    	of the entire file.
    	(_bfd_generic_get_section_contents_in_window): Likewise.
Comment 5 H.J. Lu 2017-06-26 16:35:33 UTC
Fixed for 2.29.
Comment 6 Sourceware Commits 2017-06-26 22:49:19 UTC
The master branch has been updated by H.J. Lu <hjl@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=1f473e3d0ad285195934e6a077c7ed32afe66437

commit 1f473e3d0ad285195934e6a077c7ed32afe66437
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Mon Jun 26 15:47:16 2017 -0700

    Add a missing line to _bfd_generic_get_section_contents_in_window
    
    	PR binutils/21665
    	* libbfd.c (_bfd_generic_get_section_contents_in_window): Add
    	a missing line.
Comment 7 Sourceware Commits 2017-06-26 23:25:26 UTC
The master branch has been updated by Pedro Alves <palves@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=ab27f80c5dceaa23c4ba7f62c0d5d22a5d5dd7a1

commit ab27f80c5dceaa23c4ba7f62c0d5d22a5d5dd7a1
Author: Pedro Alves <palves@redhat.com>
Date:   Tue Jun 27 00:21:25 2017 +0100

    Fix GDB regressions caused by previous bfd_get_section_contents changes
    
    Ref: https://sourceware.org/ml/binutils/2017-06/msg00343.html
    
    bfd/ChangeLog:
    2017-06-26  Pedro Alves  <palves@redhat.com>
    
    	PR binutils/21665
    	* libbfd.c (_bfd_generic_get_section_contents): Add "count", not
    	"sz".
Comment 8 Sourceware Commits 2017-06-27 00:18:15 UTC
The master branch has been updated by Alan Modra <amodra@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=7211ae501eb0de1044983f2dfb00091a58fbd66c

commit 7211ae501eb0de1044983f2dfb00091a58fbd66c
Author: Alan Modra <amodra@gmail.com>
Date:   Tue Jun 27 09:45:04 2017 +0930

    More fixes for bfd_get_section_contents change
    
    	PR binutils/21665
    	* libbfd.c (_bfd_generic_get_section_contents): Delete abort.
    	Use unsigned file pointer type, and remove cast.
    	* libbfd.c (_bfd_generic_get_section_contents_in_window): Likewise.
    	Add "count", not "sz".
Comment 9 Sourceware Commits 2017-06-27 05:17:53 UTC
The master branch has been updated by Alan Modra <amodra@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=ea9aafc41a764e4e2dbb88a7b031e886b481b99a

commit ea9aafc41a764e4e2dbb88a7b031e886b481b99a
Author: Alan Modra <amodra@gmail.com>
Date:   Tue Jun 27 14:43:49 2017 +0930

    Warning fix
    
    	PR binutils/21665
    	* libbfd.c (_bfd_generic_get_section_contents): Warning fix.
    	(_bfd_generic_get_section_contents_in_window): Likewise.
Comment 10 Sourceware Commits 2017-06-30 10:04:50 UTC
The master branch has been updated by Nick Clifton <nickc@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=60a02042bacf8d25814430080adda61ed086bca6

commit 60a02042bacf8d25814430080adda61ed086bca6
Author: Nick Clifton <nickc@redhat.com>
Date:   Fri Jun 30 11:03:37 2017 +0100

    Fix failures in MMIX linker tests introduced by fix for PR 21665.
    
    	PR binutils/21665
    	* objdump.c (disassemble_section): Move check for an overlarge
    	section to just before the allocation of memory.  Do not check
    	section size against file size, but instead use an arbitrary 2Gb
    	limit.  Issue a warning message if the section is too big.
Comment 11 Sourceware Commits 2017-07-01 23:04:17 UTC
The master branch has been updated by Alan Modra <amodra@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=bae7501e87ab614115d9d3213b4dd18d96e604db

commit bae7501e87ab614115d9d3213b4dd18d96e604db
Author: Alan Modra <amodra@gmail.com>
Date:   Sat Jul 1 21:58:10 2017 +0930

    Use bfd_malloc_and_get_section
    
    It's nicer than xmalloc followed by bfd_get_section_contents, since
    xmalloc exits on failure and needs a check that its size_t arg doesn't
    lose high bits when converted from bfd_size_type.
    
    	PR binutils/21665
    	* objdump.c (strtab): Make var a bfd_byte*.
    	(disassemble_section): Don't limit malloc size.  Instead, use
    	bfd_malloc_and_get_section.
    	(read_section_stabs): Use bfd_malloc_and_get_section.  Return
    	bfd_byte*.
    	(find_stabs_section): Remove now unnecessary cast.
    	* objcopy.c (copy_object): Use bfd_malloc_and_get_section.  Free
    	contents on error return.
    	* nlmconv.c (copy_sections): Use bfd_malloc_and_get_section.