Hello,
I am reporting a security vulnerability in GNU Binutils affecting the BFD
library's DLX relocation backend.
*Summary*
The PCREL26 relocation handler elf32_dlx_relocate26() in bfd/elf32-dlx.c
performs a 4-byte read/write at (data + reloc_entry->address) without
validating the offset against the section size. Because the function
returns bfd_reloc_ok unconditionally, the generic bounds check in
bfd/reloc.c is bypassed entirely.
A crafted ELF32 DLX object with an out-of-bounds relocation offset
triggers an arbitrary write into adjacent mmap'd memory when processed
by objdump -g (or any BFD consumer). This has been demonstrated to
achieve arbitrary code execution via FSOP corruption of _IO_2_1_stderr_,
including full ASLR bypass.
*Affected Component*
File: bfd/elf32-dlx.c
Function: elf32_dlx_relocate26()
Versions: All versions through current HEAD (confirmed on git HEAD,
Debian 13, glibc 2.41, x86_64)
CWE: CWE-787 (Out-of-bounds Write)
*Vulnerable Code*
// bfd/elf32-dlx.c — elf32_dlx_relocate26()
insn = bfd_get_32(abfd, data + reloc_entry->address); // OOB read
// ... relocation math ...
bfd_put_32(abfd, insn, data + reloc_entry->address); // OOB write
return bfd_reloc_ok; // bypasses
bounds check
The offset reloc_entry->address is read directly from the untrusted ELF
file and is never checked against input_section->size.
*Exploitation*
When the .debug_info section is >= 128 KB, malloc() uses mmap() to
allocate the section buffer. On x86_64 Linux, this places the buffer
in the same virtual memory region as libc's data segment. The distance
between the buffer and _IO_2_1_stderr_ is deterministic even with ASLR
enabled (measured at 0x21A4D0 across all test runs).
Four OOB PCREL26 relocations are used to corrupt _IO_2_1_stderr_ fields
(FSOP — File Stream Oriented Programming):
1. _flags[0:3] ← command string ("ps\0") → becomes system() argument
2. _IO_write_ptr ← non-zero → triggers _IO_wfile_overflow
3. _wide_data ← pointer to fake struct → redirects vtable dispatch
4. vtable ← _IO_wfile_jumps → enters wide file code path
Execution path when objdump writes to stderr:
_IO_wfile_overflow(stderr)
→ _IO_wdoallocbuf(stderr)
→ stderr->_wide_data->_wide_vtable->__doallocate(stderr)
= system(stderr)
= system("ps")
A standalone proof-of-concept (no GDB, no root) using Linux ptrace to
resolve ASLR at runtime is attached. It has been confirmed to achieve
arbitrary code execution on an unmodified Debian 13 installation.
*Attachements*
poc_generate.py — generates the malicious ELF payload
poc_ptrace.py — standalone exploit with ASLR bypass (no GDB)
Public repository:
https://github.com/4D4J/objdump-Out-Of-Bounds-write
I am happy to provide additional technical details, test cases, or to
coordinate the disclosure timeline with your team.
Regards,
<https://github.com/4D4J/objdump-Out-Of-Bounds-write>Rapido (=