Bug 22384 - heap buffer overflow in print_gnu_property_note
Summary: heap buffer overflow in print_gnu_property_note
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 02:49 UTC by Mingi Cho
Modified: 2017-11-02 17:05 UTC (History)
1 user (show)

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


Attachments
poc of the crash (3.04 KB, application/x-executable)
2017-11-02 02:49 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 02:49:17 UTC
Created attachment 10566 [details]
poc of the crash

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

I think this is a same bug with PR22307.


ASAN output:

./readelf -a $POC

==2365==ERROR: AddressSanitizer: SEGV on unknown address 0xa4c01a64 (pc 0x0824dc7f bp 0xbfffe188 sp 0xbfffdf70 T0)
    #0 0x824dc7e in byte_get_little_endian /home/min/fuzzing/src/binutils/binutils-gdb/binutils/elfcomm.c:148:16
    #1 0x81ced4c in print_gnu_property_note /home/min/fuzzing/src/binutils/binutils-gdb/binutils/readelf.c:16509:27
    #2 0x81cd8ee in print_gnu_note /home/min/fuzzing/src/binutils/binutils-gdb/binutils/readelf.c:16714:7
    #3 0x81c8c6d in process_note /home/min/fuzzing/src/binutils/binutils-gdb/binutils/readelf.c:17574:12
    #4 0x81c6b48 in process_notes_at /home/min/fuzzing/src/binutils/binutils-gdb/binutils/readelf.c:17736:13
    #5 0x81c4da2 in process_corefile_note_segments /home/min/fuzzing/src/binutils/binutils-gdb/binutils/readelf.c:17766:8
    #6 0x81c4b62 in process_note_sections /home/min/fuzzing/src/binutils/binutils-gdb/binutils/readelf.c:17892:12
    #7 0x81722af in process_notes /home/min/fuzzing/src/binutils/binutils-gdb/binutils/readelf.c:17905:12
    #8 0x81486db in process_object /home/min/fuzzing/src/binutils/binutils-gdb/binutils/readelf.c:18176:9
    #9 0x8137e9a in process_file /home/min/fuzzing/src/binutils/binutils-gdb/binutils/readelf.c:18565:13
    #10 0x81367a1 in main /home/min/fuzzing/src/binutils/binutils-gdb/binutils/readelf.c:18637:11
    #11 0xb7d7f636 in __libc_start_main /build/glibc-KM3i_a/glibc-2.23/csu/../csu/libc-start.c:291
    #12 0x805fda7 in _start (/home/min/fuzzing/program/binutils-master-asan/bin/readelf+0x805fda7)


The GDB debugging information is as follows:

(gdb) r -a $POC

Program received signal SIGSEGV, Segmentation fault.
0x080c055e in byte_get_little_endian (field=0xbfa88 <error: Cannot access memory at address 0xbfa88>, size=4)
    at elfcomm.c:148
148       return  ((unsigned long) (field[0]))
(gdb) bt
#0  0x080c055e in byte_get_little_endian (field=0xbfa88 <error: Cannot access memory at address 0xbfa88>, size=4)
    at elfcomm.c:148
#1  0x0808d369 in print_gnu_property_note (pnote=0xbfffeda0) at readelf.c:16509
#2  0x0808c994 in print_gnu_note (pnote=0xbfffeda0) at readelf.c:16714
#3  0x0808a0fe in process_note (pnote=0xbfffeda0, file=0x80fe908) at readelf.c:17574
#4  0x0808990a in process_notes_at (file=0x80fe908, section=0x0, offset=360, length=68) at readelf.c:17736
#5  0x08089353 in process_corefile_note_segments (file=0x80fe908) at readelf.c:17766
#6  0x080892a5 in process_note_sections (file=0x80fe908) at readelf.c:17892
#7  0x0805d3d0 in process_notes (file=0x80fe908) at readelf.c:17905
#8  0x08050dd3 in process_object (file_name=0xbffff2b7 "/tmp/poc", file=0x80fe908) at readelf.c:18176
#9  0x0804a751 in process_file (file_name=0xbffff2b7 "/tmp/poc") at readelf.c:18565
#10 0x08049b81 in main (argc=3, argv=0xbffff0a4) at readelf.c:18637


Proposed patch:

Patch as in PR22307.

--- a/binutils/readelf.c
+++ b/bintuils/readelf.c
@@ -16503,15 +16503,23 @@ print_gnu_property_note (Elf_Internal_Note * pnote)
       return;
     }
 
-  while (1)
+  while (ptr != ptr_end)
     {
       unsigned int j;
-      unsigned int type = byte_get (ptr, 4);
-      unsigned int datasz = byte_get (ptr + 4, 4);
+      unsigned int type;
+      unsigned int datasz;
 
+      if ((size_t) (ptr_end - ptr) < 8)
+  {
+    printf (_("<corrupt descsz: %#lx>\n"), pnote->descsz);
+    break;
+  }
+
+      type = byte_get (ptr, 4);
+      datasz = byte_get (ptr + 4, 4);
       ptr += 8;
 
-      if ((ptr + datasz) > ptr_end)
+      if (datasz > (size_t) (ptr_end - ptr))
        {
          printf (_("<corrupt type (%#x) datasz: %#x>\n"),
                  type, datasz);
@@ -16590,21 +16598,12 @@ print_gnu_property_note (Elf_Internal_Note * pnote)
 
 next:
       ptr += ((datasz + (size - 1)) & ~ (size - 1));
-      if (ptr == ptr_end)
-       break;
-      else
-       {
+
          if (do_wide)
            printf (", ");
          else
            printf ("\n\t");
-       }
 
-      if (ptr > (ptr_end - 8))
-       {
-         printf (_("<corrupt descsz: %#lx>\n"), pnote->descsz);
-         break;
-       }
     }
 
   printf ("\n");


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 cvs-commit@gcc.gnu.org 2017-11-02 17:02:48 UTC
The master branch has been updated by Nick Clifton <nickc@sourceware.org>:

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

commit 6ab2c4ed51f9c4243691755e1b1d2149c6a426f4
Author: Mingi Cho <mgcho.minic@gmail.com>
Date:   Thu Nov 2 17:01:08 2017 +0000

    Work around integer overflows when readelf is checking for corrupt ELF notes when run on a 32-bit host.
    
    	PR 22384
    	* readelf.c (print_gnu_property_note): Improve overflow checks so
    	that they will work on a 32-bit host.
Comment 2 Nick Clifton 2017-11-02 17:05:02 UTC
Hi Mingi,

  Thanks very much for reporting this bug.  And thanks again for providing
  a patch that fixes it.  I have checked the patch in, so all should be good
  now.

Cheers
  Nick