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.

Reply via email to