https://sourceware.org/bugzilla/show_bug.cgi?id=34896
Bug ID: 34896
Summary: ld: PE/COFF .drectve without a terminating NUL is read
and written past its buffer (cofflink.c get_name,
deffilep.y def_file_add_directive)
Product: binutils
Version: 2.48 (HEAD)
Status: UNCONFIRMED
Severity: normal
Priority: P2
Component: ld
Assignee: unassigned at sourceware dot org
Reporter: martin.mirchev at u dot nus.edu
Target Milestone: ---
process_embedded_commands() (bfd/cofflink.c) copies .drectve into a buffer of
exactly sec->size bytes. For "-attr" it calls get_name(), which scans for a
NUL or space and then stores a NUL, with no end-of-buffer check:
1389 while (*ptr == ' ')
1392 while (*ptr && *ptr != ' ')
1394 *ptr = 0;
When the section ends inside the directive, both the scan and the NUL store
land past the heap block. The PE emulations also parse the same directives
earlier in def_file_add_directive() (ld/deffilep.y:1085), which reads
param[len] past the end of the same kind of unterminated copy.
Tested on master 1ec1cee48577c7b1960ddce5a6054b3f9fab6ef5 (GNU ld
2.47.50.20261027, --enable-targets=all). Release: Ubuntu 22.04 gcc 11
-g -O2. ASan: -O1 -g -fsanitize=address,undefined.
Attached (all files in ld-coff-drectve-oob.tar.gz): m.bad5.o, a PE/COFF x86-64
object whose 5-byte .drectve is exactly
"-attr" (sha256
af6871df3c6c81685d54fdb9373de5f481b7f42f6cf2b9478f5f026b897ba831),
with m.c and make.sh (objcopy -O pe-x86-64 --add-section, then set the section
size to 5). Control: m.ctrl12.o, the same object with a 12-byte .drectve
"-stack 4096 ".
$ ld -m i386pep -e main -o out.exe m.bad5.o
Warning: corrupt .drectve at end of def file
(exit 0; the out-of-bounds accesses are silent in the release build)
Valgrind on the release build (7 errors):
Invalid read of size 1 at def_file_add_directive (deffilep.y:1085)
by process_def_file_and_drectve (pe-dll.c:757)
Invalid read of size 1 at get_name (cofflink.c:1389)
by process_embedded_commands (cofflink.c:1437)
by _bfd_coff_link_input_bfd (cofflink.c:1600)
Invalid write of size 1 at get_name (cofflink.c:1394)
by process_embedded_commands (cofflink.c:1437)
block allocated at bfd_get_full_section_contents (compress.c:763)
<- process_embedded_commands (cofflink.c:1413)
(a second read/write pair from the second get_name call, an invalid read at
cofflink.c:1442, and one in bfd_hash_hash (hash.c:520))
ASan stops at the first of these:
ERROR: AddressSanitizer: heap-buffer-overflow on address 0x502000000655
READ of size 1 at 0x502000000655 thread T0
#0 def_file_add_directive ld/deffilep.y:1085
#1 process_def_file_and_drectve ld/pe-dll.c:757
#2 pep_dll_build_sections ld/pe-dll.c:3872
#3 gldi386pep_after_open ld/ei386pep.c:1403
#4 ldemul_after_open ld/ldemul.c:80
#5 lang_process ld/ldlang.c:8815
#6 main ld/ldmain.c:971
0x502000000655 is located 0 bytes to the right of 5-byte region
allocated by: xmalloc <- process_def_file_and_drectve ld/pe-dll.c:754
The control is clean in the release build, under ASan and under valgrind
(0 errors).
Both parsers should bound their scans by the section size (or work on a
NUL-terminated copy) instead of assuming .drectve ends in a NUL or space.
This issue was found by an LLM-Enhanced Static Analysis Engine and verified
manually.
--
You are receiving this mail because:
You are on the CC list for the bug.