Bug 20906

Summary: LD: ld crashes for malformed inputs
Product: binutils Reporter: Marcel Böhme <boehme.marcel>
Component: ldAssignee: Not yet assigned to anyone <unassigned>
Status: RESOLVED FIXED    
Severity: normal CC: nickc, thuanpv
Priority: P2    
Version: 2.28   
Target Milestone: ---   
Host: Target:
Build: Last reconfirmed:

Description Marcel Böhme 2016-12-02 07:19:50 UTC
Dear all,

The following bug was found with AFLFast, a fork of AFL, in a 24 hour fuzzing session on Binutils. Thanks also to Van-Thuan Pham.

The linker crashes with an invalid write of size 1 for the following execution on 14.04 x86_64 for Binutils v2.24 and trunk. It does not crash on Ubuntu 16.04 x86_64 Binutils v2.26.1 or trunk but the invalid write is still there.

$ printf "\x6b\x22\x17\x1d\x00\x7f\x00\x00\x00\x00\x00\x52\x6e\x71\x1d\x00\x00\x01\x00\x00\x00\x00\x00\x00\x52\x6b\x22\x00\xdf\x12\xef\x17\x66\x52\x6b\x22\x17\x1d\x00\x6b\x22\x00\xdf\x2e\xef\x00\x69" > test
$ ./ld test
*** Error in `/home/ubuntu/subjects/binutils-gdb/ld/ld-new': malloc(): memory corruption: 0x000000000188a6e0 ***
Aborted

ASAN reports it sometimes as use-after-free and sometimes as heap-based buffer overflow:
=================================================================
==8360==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60200000c828 at pc 0x000000413f9e bp 0x7ffd709c9a00 sp 0x7ffd709c99f8
WRITE of size 1 at 0x60200000c828 thread T0
    #0 0x413f9d in yylex /home/ubuntu/subjects/binutils-gdb/obj-asan/ld/ldlex.l:420
    #1 0x404901 in yyparse /home/ubuntu/subjects/binutils-gdb/obj-asan/ld/ldgram.c:2298
    #2 0x43845e in load_symbols ../../ld/ldlang.c:2818
    #3 0x43c299 in open_input_bfds ../../ld/ldlang.c:3346
    #4 0x4568f7 in lang_process ../../ld/ldlang.c:6871
    #5 0x465a39 in main ../../ld/ldmain.c:428
    #6 0x7fdb8cba8f44 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21f44)
    #7 0x403968  (/home/ubuntu/subjects/binutils-gdb/obj-asan/ld/ld-new+0x403968)

0x60200000c828 is located 8 bytes to the left of 2-byte region [0x60200000c830,0x60200000c832)
allocated by thread T0 here:
    #0 0x7fdb8df293a8 in __interceptor_malloc (/usr/lib/x86_64-linux-gnu/libasan.so.3+0xc23a8)
    #1 0x92547b in xmalloc ../../libiberty/xmalloc.c:148
    #2 0x92571a in xstrdup ../../libiberty/xstrdup.c:34
    #3 0x413ba4 in yylex /home/ubuntu/subjects/binutils-gdb/obj-asan/ld/ldlex.l:379
    #4 0x404901 in yyparse /home/ubuntu/subjects/binutils-gdb/obj-asan/ld/ldgram.c:2298
    #5 0x43845e in load_symbols ../../ld/ldlang.c:2818
    #6 0x43c299 in open_input_bfds ../../ld/ldlang.c:3346
    #7 0x4568f7 in lang_process ../../ld/ldlang.c:6871
    #8 0x465a39 in main ../../ld/ldmain.c:428
    #9 0x7fdb8cba8f44 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x21f44)

SUMMARY: AddressSanitizer: heap-buffer-overflow /home/ubuntu/subjects/binutils-gdb/obj-asan/ld/ldlex.l:420 in yylex

The stacktraces vary significantly for different fuzzing inputs but it is always the call to yyparse that crashes the linker.

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

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

commit 406bd128dba2a59d0736839fc87a59bce319076c
Author: Nick Clifton <nickc@redhat.com>
Date:   Mon Dec 5 16:00:43 2016 +0000

    Fix seg-fault in linker when passed a bogus input script.
    
    	PR ld/20906
    	* ldlex.l: Check for bogus strings in linker scripts.
Comment 2 Nick Clifton 2016-12-05 16:26:49 UTC
Hi Marcel,

  Thanks for reporting this bug.

  I have checked in a small patch to the linker script parser which should fix the problem.

Cheers
  Nick
Comment 3 Thuan Pham 2017-04-13 06:15:01 UTC
This is CVE-2017-7227
Comment 4 Sourceware Commits 2021-11-03 06:40:26 UTC
The master branch has been updated by Alan Modra <amodra@sourceware.org>:

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

commit 6ef4fa071e2c25b71e81a91646b43378cf957388
Author: Alan Modra <amodra@gmail.com>
Date:   Wed Nov 3 16:21:42 2021 +1030

    asan: dlltool buffer overflow: embedded NUL in string
    
    yyleng gives the pattern length, xstrdup just copies up to the NUL.
    So it is quite possible writing at an index of yyleng-2 overflows
    the xstrdup allocated string buffer.  xmemdup quite handily avoids
    this problem, even writing the terminating NUL over the trailing
    quote.  Use it in ldlex.l too where we'd already had a report of this
    problem and fixed it by hand, and to implement xmemdup0 in gas.
    
    binutils/
            * deflex.l (single and double quote strings): Use xmemdup.
    gas/
            * as.h (xmemdup0): Use xmemdup.
    ld/
            PR 20906
            * ldlex.l (double quote string): Use xmemdup.