https://sourceware.org/bugzilla/show_bug.cgi?id=34655
Bug ID: 34655
Summary: Heap-buffer-overflow write in MIPS dynamic-relocation
sizing (`bfd/elf64-mips.c`)
Product: binutils
Version: 2.47
Status: UNCONFIRMED
Severity: normal
Priority: P2
Component: binutils
Assignee: unassigned at sourceware dot org
Reporter: hdzhao214 at gmail dot com
Target Milestone: ---
Created attachment 17014
--> https://sourceware.org/bugzilla/attachment.cgi?id=17014&action=edit
The `artifacts.zip` package includes the PoC generation script, the sanitizer
report, the bug report, and the candidate patch
## Vulnerability description
The MIPS-specific upper-bound helper triples the generic relocation-buffer size
in a signed `long` without an overflow check. In a 32-bit build, a crafted
ELF64-MIPS file makes the product wrap to eight bytes. The caller allocates
that tiny buffer, then the canonicalization routine writes relocation pointers
into it.
```c
static long
mips_elf64_get_dynamic_reloc_upper_bound (bfd *abfd)
{
return _bfd_elf_get_dynamic_reloc_upper_bound (abfd) * 3;
}
```
The supplied sparse ELF declares enough dynamic relocations for the
multiplication to wrap, while placing only a few actual relocation records
before the overflowing write.
## Version and commit
GNU Binutils 2.47.50, commit `d715260f420066befb2d30ec8f5befcdf7ecfd84`
(2026-09-08).
## Environment
Ubuntu 24.04.4 LTS on x86_64, using an i686 AddressSanitizer build with 32-bit
`long`; GCC 13.3.0 and Python 3.12.3.
## Steps to reproduce
1. Install the native build prerequisites plus 32-bit compiler and libc
development support:
```sh
sudo apt-get update
sudo apt-get install -y build-essential bison flex texinfo python3 \\
gcc-multilib g++-multilib libc6-dev-i386 \\
libgmp-dev libmpfr-dev libmpc-dev zlib1g-dev
```
2. Obtain the affected revision and make a 32-bit AddressSanitizer build:
```sh
export SRC="$PWD/binutils-gdb"
git clone https://sourceware.org/git/binutils-gdb.git "$SRC"
git -C "$SRC" checkout d715260f420066befb2d30ec8f5befcdf7ecfd84
mkdir "$SRC/build-i686-asan" && cd "$SRC/build-i686-asan"
CC='gcc -m32' CXX='g++ -m32' \\
CFLAGS='-O1 -g -m32 -fsanitize=address -static-libasan
-fno-omit-frame-pointer' \\
LDFLAGS='-m32 -fsanitize=address -static-libasan' \\
"$SRC/configure" --target=i686-linux-gnu --enable-targets=all \\
--enable-64-bit-bfd --disable-gdb --disable-gdbserver --disable-sim \\
--disable-gas --disable-ld --disable-gold --disable-gprof
--disable-gprofng \\
--disable-nls --disable-werror --without-zlib
make -j"$(nproc)" all-binutils
export BUILD="$SRC/build-i686-asan"
```
3. Place the supplied `gen_poc.py` in a writable directory and generate the
sparse input:
```sh
export WORK="$PWD/poc-work"
mkdir -p "$WORK"
cp gen_poc.py "$WORK/"
(cd "$WORK" && python3 gen_poc.py)
```
4. Trigger the fault:
```sh
ASAN_OPTIONS=detect_leaks=0:abort_on_error=1 \\
"$BUILD/binutils/objdump" -R "$WORK/poc.elf" >/dev/null
```
## Sanitizer report
The following is the complete, unmodified contents of `sanitizer_report.txt`.
```text
=================================================================
==4124545==ERROR: AddressSanitizer: heap-buffer-overflow on address 0xe8400058
at pc 0x5e0b51b1 bp 0xfffdb658 sp 0xfffdb648
WRITE of size 4 at 0xe8400058 thread T0
#0 0x5e0b51b0 in _bfd_elf_canonicalize_dynamic_reloc
/home/shootduck/hotracer-experiments/0-day/hotracer/pilot/objdump/2026-09-08-2.47.50-d715260/binutils-gdb/bfd/elf.c:9324
#1 0x5db84aa7 in dump_dynamic_relocs
/home/shootduck/hotracer-experiments/0-day/hotracer/pilot/objdump/2026-09-08-2.47.50-d715260/binutils-gdb/binutils/objdump.c:5656
#2 0x5db84aa7 in dump_bfd
/home/shootduck/hotracer-experiments/0-day/hotracer/pilot/objdump/2026-09-08-2.47.50-d715260/binutils-gdb/binutils/objdump.c:5906
#3 0x5db8670d in display_object_bfd
/home/shootduck/hotracer-experiments/0-day/hotracer/pilot/objdump/2026-09-08-2.47.50-d715260/binutils-gdb/binutils/objdump.c:5971
#4 0x5db8670d in display_any_bfd
/home/shootduck/hotracer-experiments/0-day/hotracer/pilot/objdump/2026-09-08-2.47.50-d715260/binutils-gdb/binutils/objdump.c:6050
#5 0x5db8688b in display_file
/home/shootduck/hotracer-experiments/0-day/hotracer/pilot/objdump/2026-09-08-2.47.50-d715260/binutils-gdb/binutils/objdump.c:6071
#6 0x5db88bc6 in main
/home/shootduck/hotracer-experiments/0-day/hotracer/pilot/objdump/2026-09-08-2.47.50-d715260/binutils-gdb/binutils/objdump.c:6494
#7 0xea0e6c74
(/home/shootduck/hotracer-experiments/0-day/hotracer/pilot/objdump/2026-09-08-2.47.50-d715260/hotracer/poc/task16_access70/sysroot/usr/lib32/libc.so.6+0x24c74)
(BuildId: a6ac4013957ce900e167743cd60a25daff1344bb)
#8 0xea0e6d37 in __libc_start_main
(/home/shootduck/hotracer-experiments/0-day/hotracer/pilot/objdump/2026-09-08-2.47.50-d715260/hotracer/poc/task16_access70/sysroot/usr/lib32/libc.so.6+0x24d37)
(BuildId: a6ac4013957ce900e167743cd60a25daff1344bb)
#9 0x5da40976 in _start
(/home/shootduck/hotracer-experiments/0-day/hotracer/pilot/objdump/2026-09-08-2.47.50-d715260/hotracer/poc/task16_access70/build32-asan/binutils/objdump+0x554976)
(BuildId: 9839e8e682cc83d3dcfdf82f845c1a08101eba79)
0xe8400058 is located 0 bytes after 8-byte region [0xe8400050,0xe8400058)
allocated by thread T0 here:
#0 0x5db097cb in malloc
(/home/shootduck/hotracer-experiments/0-day/hotracer/pilot/objdump/2026-09-08-2.47.50-d715260/hotracer/poc/task16_access70/build32-asan/binutils/objdump+0x61d7cb)
(BuildId: 9839e8e682cc83d3dcfdf82f845c1a08101eba79)
#1 0x5f00dc99 in xmalloc
/home/shootduck/hotracer-experiments/0-day/hotracer/pilot/objdump/2026-09-08-2.47.50-d715260/binutils-gdb/libiberty/xmalloc.c:149
#2 0x5db84a37 in dump_dynamic_relocs
/home/shootduck/hotracer-experiments/0-day/hotracer/pilot/objdump/2026-09-08-2.47.50-d715260/binutils-gdb/binutils/objdump.c:5655
#3 0x5db84a37 in dump_bfd
/home/shootduck/hotracer-experiments/0-day/hotracer/pilot/objdump/2026-09-08-2.47.50-d715260/binutils-gdb/binutils/objdump.c:5906
#4 0x5db8670d in display_object_bfd
/home/shootduck/hotracer-experiments/0-day/hotracer/pilot/objdump/2026-09-08-2.47.50-d715260/binutils-gdb/binutils/objdump.c:5971
#5 0x5db8670d in display_any_bfd
/home/shootduck/hotracer-experiments/0-day/hotracer/pilot/objdump/2026-09-08-2.47.50-d715260/binutils-gdb/binutils/objdump.c:6050
#6 0x5db8688b in display_file
/home/shootduck/hotracer-experiments/0-day/hotracer/pilot/objdump/2026-09-08-2.47.50-d715260/binutils-gdb/binutils/objdump.c:6071
#7 0x5db88bc6 in main
/home/shootduck/hotracer-experiments/0-day/hotracer/pilot/objdump/2026-09-08-2.47.50-d715260/binutils-gdb/binutils/objdump.c:6494
#8 0xea0e6c74
(/home/shootduck/hotracer-experiments/0-day/hotracer/pilot/objdump/2026-09-08-2.47.50-d715260/hotracer/poc/task16_access70/sysroot/usr/lib32/libc.so.6+0x24c74)
(BuildId: a6ac4013957ce900e167743cd60a25daff1344bb)
SUMMARY: AddressSanitizer: heap-buffer-overflow
/home/shootduck/hotracer-experiments/0-day/hotracer/pilot/objdump/2026-09-08-2.47.50-d715260/binutils-gdb/bfd/elf.c:9324
in _bfd_elf_canonicalize_dynamic_reloc
Shadow bytes around the buggy address:
0xe83ffd80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xe83ffe00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xe83ffe80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xe83fff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0xe83fff80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0xe8400000: fa fa fa fa fa fa fa fa fa fa 00[fa]fa fa 04 fa
0xe8400080: fa fa fd fd fa fa fd fd fa fa 00 04 fa fa fd fd
0xe8400100: fa fa fd fd fa fa 00 04 fa fa 00 04 fa fa 00 00
0xe8400180: fa fa 00 01 fa fa 00 04 fa fa 00 01 fa fa 00 00
0xe8400200: fa fa 00 00 fa fa 00 fa fa fa 07 fa fa fa fd fa
0xe8400280: fa fa fd fa fa fa 00 fa fa fa 07 fa fa fa 00 04
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==4124545==ABORTING
```
## Potential fix
Check the generic result and the factor-of-three multiplication against
`LONG_MAX`; return the existing oversized-file error rather than a wrapped
allocation bound.
```diff
diff --git a/bfd/elf64-mips.c b/bfd/elf64-mips.c
@@
- return _bfd_elf_get_dynamic_reloc_upper_bound (abfd) * 3;
+ long size = _bfd_elf_get_dynamic_reloc_upper_bound (abfd);
+ if (size < 0)
+ return size;
+ if (size > LONG_MAX / 3)
+ { bfd_set_error (bfd_error_file_too_big); return -1; }
+ return size * 3;
```
The complete, apply-ready patch is included as `proposed-fix.patch`. It was
applied to a disposable checkout of the stated commit and the supplied proof of
concept was rerun without an AddressSanitizer finding.
--
You are receiving this mail because:
You are on the CC list for the bug.