Bug 20905

Summary: Heap buffer overflow in bfd/peicode.h
Product: binutils Reporter: Thuan Pham <thuanpv>
Component: binutilsAssignee: Not yet assigned to anyone <unassigned>
Status: RESOLVED FIXED    
Severity: normal CC: boehme.marcel, nickc
Priority: P2    
Version: 2.28   
Target Milestone: ---   
Host: Target:
Build: Last reconfirmed:

Description Thuan Pham 2016-12-02 06:29:31 UTC
Dear all,
Using AFLFast (https://github.com/mboehme/aflfast), a fork of AFL, with ASAN enabled we found a heap buffer overflow in bfd/peicode.h. 

The bug was found on Ubuntu 14.04 64-bit & binutils was checked out from https://github.com/bminor/binutils-gdb repository. Its commit is  268ebe95201d2ebdcf68cad9dc67ff6d1e25be9e (Fri Nov 18 14:15:12 2016).

To reproduce:

printf "\x00\x00\xff\xff\x00\x00\x4c\x01\xfb\x5b\x89\x7a\x02\x00\x00\x00\x3a\x7a\x7a\x7a\x7a\x84\x7a\x7a\x7a\x7a\x7e\x5b\x01\x00\x5b\x09\x09\xe6\xff\x00\x00\x00\x7f\xff\x8b\xb3\x09\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x2d\x09\x00\x80\x24\x29\x41\x02\x00\x00\x99\x20\x02\x40" > fd

addr2line -e fd

OR

size @- fd

OR

strings -w -d fd

When we run "strings -w -d fd", ASAN says:

==139869==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x62100001dce0 at pc 0x7f5482b026d3 bp 0x7ffd60c03920 sp 0x7ffd60c030d0
READ of size 4049 at 0x62100001dce0 thread T0
    #0 0x7f5482b026d2  (/usr/lib/x86_64-linux-gnu/libasan.so.3+0x3c6d2)
    #1 0x560beb in pe_ILF_object_p ../../bfd/peicode.h:1272
    #2 0x560beb in pe_bfd_object_p ../../bfd/peicode.h:1407
    #3 0x41848c in bfd_check_format_matches ../../bfd/format.c:311
    #4 0x40b137 in strings_object_file ../../binutils/strings.c:411
    #5 0x40b137 in strings_file ../../binutils/strings.c:454
    #6 0x40b137 in main ../../binutils/strings.c:321
    #7 0x7f5481807f44 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21f44)
    #8 0x40c376  (/home/ubuntu/subjects/binutils-asan/obj-asan/binutils/strings+0x40c376)

0x62100001dce0 is located 0 bytes to the right of 4064-byte region [0x62100001cd00,0x62100001dce0)
allocated by thread T0 here:
    #0 0x7f5482b883a8 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.3+0xc23a8)
    #1 0x671e38 in objalloc_create ../../libiberty/objalloc.c:95
    #2 0x41f61b in _bfd_new_bfd ../../bfd/opncls.c:73
    #3 0x41fb71 in bfd_fopen ../../bfd/opncls.c:199
    #4 0x40b122 in strings_object_file ../../binutils/strings.c:402
    #5 0x40b122 in strings_file ../../binutils/strings.c:454
    #6 0x40b122 in main ../../binutils/strings.c:321
    #7 0x7f5481807f44 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21f44)

SUMMARY: AddressSanitizer: heap-buffer-overflow (/usr/lib/x86_64-linux-gnu/libasan.so.3+0x3c6d2) 
Shadow bytes around the buggy address:
  0x0c427fffbb40: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c427fffbb50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c427fffbb60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c427fffbb70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c427fffbb80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c427fffbb90: 00 00 00 00 00 00 00 00 00 00 00 00[fa]fa fa fa
  0x0c427fffbba0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c427fffbbb0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c427fffbbc0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c427fffbbd0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c427fffbbe0: 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
  Left alloca redzone:     ca
  Right alloca redzone:    cb

After checking the code in peicode.h and debugging it in GDB, we found that although the size to allocate ptr is just 36 but after calling bfd_bread, the string length of ptr is much bigger than that. So, ASAN detects the heap buffer overflow in the call strlen(sym_name). The bug allows source_dll pointing to some location outside the boundary of symbol_name/ptr and it could lead to some bad thing if source_dll is not checked & used properly.

  ptr = (bfd_byte *) bfd_alloc (abfd, size);
  if (ptr == NULL)
    return NULL;

  if (bfd_bread (ptr, size, abfd) != size)
    {
      bfd_release (abfd, ptr);
      return NULL;
    }

  symbol_name = (char *) ptr;
  source_dll  = symbol_name + strlen (symbol_name) + 1;

Best regards,
Thuan
Comment 1 Sourceware Commits 2016-12-05 16:36:02 UTC
The master branch has been updated by Nick Clifton <nickc@sourceware.org>:

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

commit fa6631b4eecfcca00c13b9594e6336dffd40982f
Author: Nick Clifton <nickc@redhat.com>
Date:   Mon Dec 5 16:34:45 2016 +0000

    Fix seg-fault in the binutils utilities when reading a corrupt input file.
    
    	PR binutils/20905
    	* peicode.h (pe_ILF_object_p): Use strnlen to avoid running over
    	the end of the string buffer.
Comment 2 Nick Clifton 2016-12-05 16:37:40 UTC
Hi Thuan,

  Thanks for reporting this bug.  I have checked in a patch to prevent the code from trying to read of the end of buffer, which should fix this problem.

Cheers
  Nick
Comment 3 Thuan Pham 2017-04-13 06:14:22 UTC
This is CVE-2017-7226