Bug 22386 - Integer overflow in print_debug_frame ()
Summary: Integer overflow in print_debug_frame ()
Status: RESOLVED FIXED
Alias: None
Product: binutils
Classification: Unclassified
Component: binutils (show other bugs)
Version: 2.30
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2017-11-02 12:43 UTC by Mingi Cho
Modified: 2017-11-03 14:05 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments
POC file (2.97 KB, application/x-executable)
2017-11-02 12:43 UTC, Mingi Cho
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Mingi Cho 2017-11-02 12:43:51 UTC
Created attachment 10569 [details]
POC file

Triggered by "./readelf -w $POC"
Tested on Ubuntu 16.04 (x86)

An integer overflow is occurred when processing corrupted elf file.


ASAN output:

./readelf -w $POC

==14407==ERROR: AddressSanitizer: heap-buffer-overflow on address 0xb4803295 at pc 0x081f11ad bp 0xbff83328 sp 0xbff8331c
READ of size 1 at 0xb4803295 thread T0
    #0 0x81f11ac in display_debug_frames /home/min/fuzzing/src/binutils/binutils-gdb/binutils/dwarf.c:7433:20
    #1 0x81c4355 in display_debug_section /home/min/fuzzing/src/binutils/binutils-gdb/binutils/readelf.c:13399:16
    #2 0x8172193 in process_section_contents /home/min/fuzzing/src/binutils/binutils-gdb/binutils/readelf.c:13485:10
    #3 0x81486c0 in process_object /home/min/fuzzing/src/binutils/binutils-gdb/binutils/readelf.c:18173:9
    #4 0x8137e9a in process_file /home/min/fuzzing/src/binutils/binutils-gdb/binutils/readelf.c:18565:13
    #5 0x81367a1 in main /home/min/fuzzing/src/binutils/binutils-gdb/binutils/readelf.c:18637:11
    #6 0xb7507636 in __libc_start_main /build/glibc-KM3i_a/glibc-2.23/csu/../csu/libc-start.c:291
    #7 0x805fda7 in _start (/home/min/fuzzing/program/binutils-master-asan/bin/readelf+0x805fda7)

0xb4803295 is located 0 bytes to the right of 341-byte region [0xb4803140,0xb4803295)
allocated by thread T0 here:
    #0 0x81040e4 in __interceptor_malloc (/home/min/fuzzing/program/binutils-master-asan/bin/readelf+0x81040e4)
    #1 0x81384ba in get_data /home/min/fuzzing/src/binutils/binutils-gdb/binutils/readelf.c:415:9
    #2 0x81347f4 in load_specific_debug_section /home/min/fuzzing/src/binutils/binutils-gdb/binutils/readelf.c:13200:38
    #3 0x81c42c4 in display_debug_section /home/min/fuzzing/src/binutils/binutils-gdb/binutils/readelf.c:13392:6
    #4 0x8172193 in process_section_contents /home/min/fuzzing/src/binutils/binutils-gdb/binutils/readelf.c:13485:10
    #5 0x81486c0 in process_object /home/min/fuzzing/src/binutils/binutils-gdb/binutils/readelf.c:18173:9
    #6 0x8137e9a in process_file /home/min/fuzzing/src/binutils/binutils-gdb/binutils/readelf.c:18565:13
    #7 0x81367a1 in main /home/min/fuzzing/src/binutils/binutils-gdb/binutils/readelf.c:18637:11
    #8 0xb7507636 in __libc_start_main /build/glibc-KM3i_a/glibc-2.23/csu/../csu/libc-start.c:291

SUMMARY: AddressSanitizer: heap-buffer-overflow /home/min/fuzzing/src/binutils/binutils-gdb/binutils/dwarf.c:7433:20 in display_debug_frames
Shadow bytes around the buggy address:
  0x36900600: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x36900610: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x36900620: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
  0x36900630: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x36900640: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x36900650: 00 00[05]fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x36900660: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x36900670: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x36900680: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fa fa
  0x36900690: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
  0x369006a0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
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
==14407==ABORTING


The GDB debugging information is as follows:

(gdb) r -w $POC

(gdb) bt
Breakpoint 4, display_debug_frames (section=0x8366c84 <debug_displays+420>, file=0xb5003d80) at dwarf.c:7432
7432		      for (i = 0; i < augmentation_data_len; ++i)
(gdb) bt
#0  display_debug_frames (section=0x8366c84 <debug_displays+420>, file=0xb5003d80) at dwarf.c:7432
#1  0x081c4356 in display_debug_section (shndx=18, section=0xb4602d90, file=0xb5003d80) at readelf.c:13399
#2  0x08172194 in process_section_contents (file=0xb5003d80) at readelf.c:13485
#3  0x081486c1 in process_object (file_name=0xbffff284 "/home/min/Downloads/test", file=0xb5003d80)
    at readelf.c:18173
#4  0x08137e9b in process_file (file_name=0xbffff284 "/home/min/Downloads/test") at readelf.c:18565
#5  0x081367a2 in main (argc=3, argv=0xbffff064) at readelf.c:18637
(gdb) p start
$18 = (unsigned char *) 0x27e6046a ""
(gdb) p end
$19 = (unsigned char *) 0xb5003994 ""
(gdb) p augmentation_data_len 
$20 = 1927662487


Proposed patch:

Check if variable start is overflowed.

--- a/home/min/fuzzing/src/binutils/binutils-gdb/binutils/dwarf.c
+++ b/home/min/Downloads/dwarf.c
@@ -7401,7 +7401,7 @@ display_debug_frames (struct dwarf_section *section,
              augmentation_data = start;
              start += augmentation_data_len;
              /* PR 17512: file: 722-8446-0.004.  */
-             if (start >= end || ((signed long) augmentation_data_len) < 0)
+             if (start >= end || ((signed long) augmentation_data_len) < 0 || augmentation_data > start)
                {
                  warn (_("Corrupt augmentation data length: %lx\n"),
                        augmentation_data_len);


Credits:

This vulnerability was discovered by Mingi Cho and Taekyoung Kwon of the Information Security Lab, Yonsei University. Please contact mgcho.minic@gmail.com and taekyoung@yonsei.ac.kr if you need more information about the vulnerability and the lab.
Comment 1 Sourceware Commits 2017-11-03 13:58:26 UTC
The master branch has been updated by Nick Clifton <nickc@sourceware.org>:

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

commit bf59c5d5f4f5b8b4da1f5f605cfa546f8029b43d
Author: Nick Clifton <nickc@redhat.com>
Date:   Fri Nov 3 13:57:15 2017 +0000

    Fix integer overflow problems when reading an ELF binary with corrupt augmentation data.
    
    	PR 22386
    	* dwarf.c (read_cie): Use bfd_size_type for
    	augmentation_data_len.
    	(display_augmentation_data): New function.
    	(display_debug_frames): Use it.
    	Check for integer overflow when testing augmentation_data_len.
Comment 2 Nick Clifton 2017-11-03 14:05:07 UTC
Hi Mingi,

  Thanks for the bug report.  I was unable to reproduce the exact failure
  that you reported, but I did find something similar.  The patch you have
  supplied does help, but I also found that there was a problem trying to
  read a 64-bit LEB128-encoded value into a 32-bit variable.  So I have 
  extended the patch to cover that.

Cheers
  Nick

PS.  You might find it interesting to create some test binaries with very
  large LEB128 values in them (more than 128 bits say) and see how the 
  various tools in the binutils suite cope with them.