https://sourceware.org/bugzilla/show_bug.cgi?id=34894
Bug ID: 34894
Summary: ld -r: unchecked i386 relocation offset in
elf_i386_relocate_section reads and writes past the
section contents buffer
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: ---
For a relocatable link, elf_i386_scan_relocs() returns (bfd/elf32-i386.c:1541)
before its "bad reloc offset" check (:1596). elf_i386_relocate_section() then
adjusts the addend of a REL relocation against a local STT_SECTION symbol whose
section has a non-zero output_offset, and never checks r_offset against the
input section size:
2222 bfd_byte *where = contents + rel->r_offset;
2243 addend = bfd_get_32 (input_bfd, where);
2281 bfd_put_32 (input_bfd, addend, where);
So a crafted ELF32 i386 object makes "ld -r" read-modify-write 4 bytes at an
offset taken from the file, measured from the 16 KiB contents buffer. Offsets
inside the buffer corrupt it silently; larger offsets run past the heap block
or into unmapped memory.
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-i386-reloc-offset.tar.gz): prefix.s, reloc.s, mk.sh
and the generated objects. prefix.o only
gives the next .data a non-zero output_offset. base.o has one R_386_32 against
the local .data section symbol at r_offset 1. bad16k.o and bad.o are base.o
with
r_offset 0x4000 and 0x100000.
$ ld -m elf_i386 -r -o out.o prefix.o base.o # exit 0
$ ld -m elf_i386 -r -o out.o prefix.o bad.o # SIGSEGV, exit 139
$ ld -m elf_i386 -r -o out.o prefix.o bad16k.o # exit 0, silent
ASan, bad16k.o:
ERROR: AddressSanitizer: heap-buffer-overflow on address 0x529000009200
READ of size 1 at 0x529000009200 thread T0
#0 bfd_getl32 bfd/libbfd.c:846
#1 elf_i386_relocate_section bfd/elf32-i386.c:2243
#2 elf_link_input_bfd bfd/elflink.c:11984
#3 _bfd_elf_final_link bfd/elflink.c:13247
#4 ldwrite ld/ldwrite.c:548
#5 main ld/ldmain.c:1001
0x529000009200 is located 0 bytes to the right of 16384-byte region
allocated by: bfd_malloc bfd/libbfd.c:291 <- _bfd_elf_final_link
bfd/elflink.c:13122
With bad.o, ASan reports a SEGV on READ in bfd_getl32 from elf32-i386.c:2243.
Valgrind on the release build with bad16k.o reports "Invalid read of size 4 ...
elf_i386_relocate_section (elf32-i386.c:2243)" and the matching invalid write
at
:2281, both just past the 16,384-byte block. base.o is clean in both builds.
The relocatable-link branch dates from ab96bf03fd98 (PR 3958, 2.18). PR 34444
fixed a similar problem in elf_x86_64_relocate_section; this i386 path is
still unfixed.
The fix is probably the relocation-offset range check that
elf_i386_scan_relocs()
already does for final links, applied in relocate_section before "where" is
formed.
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.