Bug 21670

Summary: A stack buffer overflow in the nm tool of the GNU Binutils.
Product: binutils Reporter: owl337 <v.owl337>
Component: binutilsAssignee: Not yet assigned to anyone <unassigned>
Status: RESOLVED FIXED    
Severity: critical CC: nickc
Priority: P2    
Version: 2.28   
Target Milestone: ---   
Host: Target:
Build: Last reconfirmed:
Attachments: Triggered by "nm -n POC1"

Description owl337 2017-06-24 14:53:55 UTC
Created attachment 10218 [details]
Triggered by "nm -n POC1"

The debugging information is as follows:

$./nm -n POC1

==94585==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fffffffde3f at pc 0x0000005432ca bp 0x7fffffffdcd0 sp 0x7fffffffdcc8
READ of size 1 at 0x7fffffffde3f thread T0
    #0 0x5432c9  (/home/icy/real/binutils-2.28-asan/install/bin/nm+0x5432c9)
    #1 0x51608a  (/home/icy/real/binutils-2.28-asan/install/bin/nm+0x51608a)
    #2 0x4ec316  (/home/icy/real/binutils-2.28-asan/install/bin/nm+0x4ec316)
    #3 0x4eb734  (/home/icy/real/binutils-2.28-asan/install/bin/nm+0x4eb734)
    #4 0x7ffff6ee582f  (/lib/x86_64-linux-gnu/libc.so.6+0x2082f)
    #5 0x4194b8  (/home/icy/real/binutils-2.28-asan/install/bin/nm+0x4194b8)

Address 0x7fffffffde3f is located in stack of thread T0 at offset 351 in frame
    #0 0x53fe8f  (/home/icy/real/binutils-2.28-asan/install/bin/nm+0x53fe8f)

  This frame has 3 object(s):
    [32, 49) 'sym.i.i'
    [96, 351) 'src.i' <== Memory access at offset 351 overflows this variable
    [416, 420) 'b'
HINT: this may be a false positive if your program uses some custom stack unwind mechanism or swapcontext
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow (/home/icy/real/binutils-2.28-asan/install/bin/nm+0x5432c9) 
Shadow bytes around the buggy address:
  0x10007fff7b70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10007fff7b80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10007fff7b90: 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1
  0x10007fff7ba0: 00 00 01 f2 f2 f2 f2 f2 00 00 00 00 00 00 00 00
  0x10007fff7bb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x10007fff7bc0: 00 00 00 00 00 00 00[07]f2 f2 f2 f2 f2 f2 f2 f2
  0x10007fff7bd0: 04 f3 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00
  0x10007fff7be0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10007fff7bf0: 00 00 00 00 00 00 00 00 f1 f1 f1 f1 00 00 00 00
  0x10007fff7c00: 00 00 00 00 00 00 00 00 00 f3 f3 f3 f3 f3 f3 f3
  0x10007fff7c10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
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
==94585==ABORTING
[Inferior 1 (process 94585) exited with code 01]

Program crash at line tekhex.c:. After multiple cycles, pointer src will point to NULL, macro ISHEX(x) failed to access this NULL value, which cause that problem .

tekhex.c:
 93 #define ISHEX(x)    hex_p(x)
 ...
 269 static bfd_boolean
 270 getvalue (char **srcp, bfd_vma *valuep, char * endp)
 271 {
 272   char *src = *srcp;
 273   bfd_vma value = 0;
 274   unsigned int len;
 275 
 276   if (!ISHEX (*src))
 277     return FALSE;
 278 
 279   len = hex_value (*src++);

libiberty.h:
381 #define _hex_bad        99
382 extern const unsigned char _hex_value[_hex_array_size];
383 extern void hex_init (void);
384 #define hex_p(c)        (hex_value (c) != _hex_bad)
385 /* If you change this, note well: Some code relies on side effects in
386    the argument being performed exactly once.  */
387 #define hex_value(c)    ((unsigned int) _hex_value[(unsigned char) (c)])

the gdb debugging infomation is as follows:
(gdb)set args -n POC1
(gdb)r
...
(gdb) p src
$24 = 0x7fffffffde3f ""
(gdb) n
491			if (!getvalue (&src, &val, src_end))
(gdb) s
getvalue (endp=<optimized out>, srcp=<optimized out>, valuep=<optimized out>) at tekhex.c:276
276	  if (!ISHEX (*src))
(gdb) s

Program received signal SIGSEGV, Segmentation fault.
0xffffffffcd4c2e50 in ?? ()
(gdb) bt
#0  0xffffffffcd4c2e50 in ?? ()
#1  0x00000000005432ca in getvalue (endp=<optimized out>, srcp=<optimized out>, valuep=<optimized out>) at tekhex.c:276
#2  first_phase (abfd=0x61200000bec0, src=<optimized out>, src_end=<optimized out>, type=<optimized out>)
    at tekhex.c:491
#3  pass_over (abfd=<optimized out>, func=<optimized out>) at tekhex.c:550
#4  tekhex_object_p (abfd=<optimized out>) at tekhex.c:615
#5  0x000000000051608b in bfd_check_format_matches (abfd=<optimized out>, format=<optimized out>, 
    matching=<optimized out>) at format.c:311
#6  0x00000000004ec317 in display_file (filename=0x7fffffffe7a9 "id:000025,sig:06,src:000931,op:arith8,pos:245,val:+19")
    at nm.c:1315
#7  0x00000000004eb735 in main (argc=<optimized out>, argv=<optimized out>) at nm.c:1793
(gdb) 

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 cvs-commit@gcc.gnu.org 2017-06-26 14:47:37 UTC
The master branch has been updated by Nick Clifton <nickc@sourceware.org>:

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

commit 04e15b4a9462cb1ae819e878a6009829aab8020b
Author: Nick Clifton <nickc@redhat.com>
Date:   Mon Jun 26 15:46:34 2017 +0100

    Fix address violation parsing a corrupt texhex format file.
    
    	PR binutils/21670
    	* tekhex.c (getvalue): Check for the source pointer exceeding the
    	end pointer before the first byte is read.
Comment 2 Nick Clifton 2017-06-26 14:49:26 UTC
Hi Owl,

  Thanks for reporting this bug.  I have checked in a small patch to fix
  the problem, which was a simple case of not checking for a buffer overrun
  early enough.

Cheers
  Nick