https://sourceware.org/bugzilla/show_bug.cgi?id=34874
Bug ID: 34874
Summary: ld: OUTPUT_FORMAT in a linker script causes
heap-buffer-overflow in x86 and generic ELF
after_open_output hooks
Product: binutils
Version: 2.48 (HEAD)
Status: UNCONFIRMED
Severity: normal
Priority: P2
Component: ld
Assignee: unassigned at sourceware dot org
Reporter: harshit7kr at gmail dot com
Target Milestone: ---
A linker script can retarget the output BFD with OUTPUT_FORMAT after the
emulation has been selected. The x86 emulation's after_open_output hook
and ld's generic ELF hook (ldelf_after_open_output) still run afterwards.
Each assumes the output link hash table matches what it expects, and
each accesses memory out of bounds when it does not.
Tested at commit be7a7615a84471cea567ea8d60a192356316a0f8,
x86_64-pc-linux-gnu, gcc 16, built with --enable-targets=all and
-fsanitize=address.
Neither defect is visible without AddressSanitizer.
--- Case 1: out-of-bounds write (x86 emulation) ---
Reproducer:
$ printf '.globl _start\n_start:\n\tnop\n' > foo.s
$ as --64 foo.s -o foo.o
$ cat script
OUTPUT_FORMAT("elf64-bpfle")
OUTPUT_ARCH(bpf)
SECTIONS { .text : { *(.text) } }
$ ld -melf_x86_64 -T script -o out foo.o
Result:
ERROR: AddressSanitizer: heap-buffer-overflow
WRITE of size 8 at 0x7cdf98be0960 thread T0
#0 in bfd_elf_linker_x86_set_options bfd/elfxx-x86.c:5042
#1 in elf_x86_after_open_output ld/eelf_x86_64.c:67
The write lands 424 bytes past a 1848-byte region.
Cause: bfd_elf_linker_x86_set_options takes the target id from the
output BFD's backend data. After OUTPUT_FORMAT retargets the output,
both that id and the link hash table belong to the foreign backend, so
the id comparison in the elf_x86_hash_table macro (bfd/elfxx-x86.h)
passes and the foreign table is treated as struct
elf_x86_link_hash_table. The write to htab->params then overflows the
heap block.
--- Case 2: out-of-bounds read (generic ELF hook) ---
Same reproducer, with a script that selects an ELF format that uses the
generic link hash table:
OUTPUT_FORMAT("elf64-nfp")
OUTPUT_ARCH(nfp)
SECTIONS { .text : { *(.text) } }
Result:
ERROR: AddressSanitizer: heap-buffer-overflow
READ of size 4 at 0x7bbb947e0150 thread T0
#0 in elf_hash_table_id bfd/elf-bfd.h:833
#1 in ldelf_after_open_output ld/ldelf.c:82
Cause: ldelf_after_open_output only checks that the output BFD is ELF
flavour, and assumes that implies an ELF link hash table. Some ELF
flavours use the generic hash table, which is smaller, so reading
hash_table_id goes past the end of it.
--- Fix ---
Two patches, with a regression test (ld-x86-64/arch-confusion.exp):
1. bfd: elfxx-x86: reject non-x86 target ids in elf_x86_hash_table
2. ld: do not read ELF fields from a generic link hash table
Series on the list (v1):
https://patchwork.sourceware.org/project/binutils/list/?series=68008
Series on the list (v2):
https://patchwork.sourceware.org/project/binutils/list/?series=67920
Notes:
- Triggering requires a linker script whose OUTPUT_FORMAT differs from
the emulation's format, so it needs a crafted script.
- Separate pre-existing bug found while sweeping other emulations:
-mm68hc11elf with OUTPUT_FORMAT("elf32-little") crashes in
m68hc11elf_after_allocation (stub_file is NULL). Not touched by
these patches; will be reported separately.
--
You are receiving this mail because:
You are on the CC list for the bug.