https://sourceware.org/bugzilla/show_bug.cgi?id=34654

            Bug ID: 34654
           Summary: Heap-buffer-overflow write in ELF synthetic-symbol
                    construction (`bfd/elf.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 17013
  --> https://sourceware.org/bugzilla/attachment.cgi?id=17013&action=edit
The `artifacts.zip` package includes the PoC generation script, the sanitizer
report, the bug report, and the candidate patch

## Vulnerability description

`_bfd_elf_get_synthetic_symtab` computes one allocation size for both an
`asymbol` array and the generated `name@plt+addend` strings. On a 32-bit build,
attacker-controlled dynamic-symbol names make the cumulative `size_t size`
wrap. The small allocation is then followed by unbounded copies of addend text,
and `memcpy` writes past its end.

```c
size = count * sizeof (asymbol);
for (...) {
  size += strlen ((*p->sym_ptr_ptr)->name) + sizeof ("@plt");
  if (p->addend != 0)
    size += sizeof ("+0x") - 1 + 8;
}
s = *ret = bfd_malloc (size);
```

The supplied big-endian PPC ELF shares very long string-table entries to make
the arithmetic wrap with a relatively compact input.

## 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 (32-bit
`size_t`), 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_ppc_synth_overflow.py` in a writable directory and
generate the input:

   ```sh
   export WORK="$PWD/poc-work"
   mkdir -p "$WORK"
   python3 gen_ppc_synth_overflow.py "$WORK/evil_ppc32_plt.elf"
   ```

4. Trigger the fault:

   ```sh
   ASAN_OPTIONS=detect_leaks=0:abort_on_error=1 \\
     "$BUILD/binutils/objdump" -d "$WORK/evil_ppc32_plt.elf" >/dev/null
   ```

## Sanitizer report

The following is the complete, unmodified contents of `sanitizer_report.txt`.

```text
=================================================================
==2500255==ERROR: AddressSanitizer: heap-buffer-overflow on address 0xe7b03ec8
at pc 0x5c712017 bp 0xff9ee838 sp 0xff9ee40c
WRITE of size 8 at 0xe7b03ec8 thread T0
    #0 0x5c712016 in memcpy
(/home/shootduck/hotracer-experiments/0-day/hotracer/pilot/objdump/2026-09-08-2.47.50-d715260/hotracer/poc/task12_access34/build32-asan/binutils/objdump+0xef016)
(BuildId: 470c59223d09ac1bd1019052b101518a1f12b5cf)
    #1 0x5c9eece7 in memcpy
/usr/include/x86_64-linux-gnu/bits/string_fortified.h:29
    #2 0x5c9eece7 in _bfd_elf_get_synthetic_symtab
/home/shootduck/hotracer-experiments/0-day/hotracer/pilot/objdump/2026-09-08-2.47.50-d715260/binutils-gdb/bfd/elf.c:13488
    #3 0x5cb014cd in ppc_elf_get_synthetic_symtab
/home/shootduck/hotracer-experiments/0-day/hotracer/pilot/objdump/2026-09-08-2.47.50-d715260/binutils-gdb/bfd/elf32-ppc.c:1818
    #4 0x5c801a26 in dump_bfd
/home/shootduck/hotracer-experiments/0-day/hotracer/pilot/objdump/2026-09-08-2.47.50-d715260/binutils-gdb/binutils/objdump.c:5878
    #5 0x5c805012 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
    #6 0x5c805012 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
    #7 0x5c805190 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
    #8 0x5c807489 in main
/home/shootduck/hotracer-experiments/0-day/hotracer/pilot/objdump/2026-09-08-2.47.50-d715260/binutils-gdb/binutils/objdump.c:6494
    #9 0xf4767c74 
(/home/shootduck/hotracer-experiments/0-day/hotracer/pilot/objdump/2026-09-08-2.47.50-d715260/hotracer/poc/task12_access34/sysroot/usr/lib32/libc.so.6+0x24c74)
(BuildId: a6ac4013957ce900e167743cd60a25daff1344bb)
    #10 0xf4767d37 in __libc_start_main
(/home/shootduck/hotracer-experiments/0-day/hotracer/pilot/objdump/2026-09-08-2.47.50-d715260/hotracer/poc/task12_access34/sysroot/usr/lib32/libc.so.6+0x24d37)
(BuildId: a6ac4013957ce900e167743cd60a25daff1344bb)
    #11 0x5c6c2916 in _start
(/home/shootduck/hotracer-experiments/0-day/hotracer/pilot/objdump/2026-09-08-2.47.50-d715260/hotracer/poc/task12_access34/build32-asan/binutils/objdump+0x9f916)
(BuildId: 470c59223d09ac1bd1019052b101518a1f12b5cf)

0xe7b03ec8 is located 0 bytes after 1608-byte region [0xe7b03880,0xe7b03ec8)
allocated by thread T0 here:
    #0 0x5c78b76b in malloc
(/home/shootduck/hotracer-experiments/0-day/hotracer/pilot/objdump/2026-09-08-2.47.50-d715260/hotracer/poc/task12_access34/build32-asan/binutils/objdump+0x16876b)
(BuildId: 470c59223d09ac1bd1019052b101518a1f12b5cf)
    #1 0x5c943c07 in bfd_malloc
/home/shootduck/hotracer-experiments/0-day/hotracer/pilot/objdump/2026-09-08-2.47.50-d715260/binutils-gdb/bfd/libbfd.c:291
    #2 0x5c9eee0c in _bfd_elf_get_synthetic_symtab
/home/shootduck/hotracer-experiments/0-day/hotracer/pilot/objdump/2026-09-08-2.47.50-d715260/binutils-gdb/bfd/elf.c:13449
    #3 0x5cb014cd in ppc_elf_get_synthetic_symtab
/home/shootduck/hotracer-experiments/0-day/hotracer/pilot/objdump/2026-09-08-2.47.50-d715260/binutils-gdb/bfd/elf32-ppc.c:1818
    #4 0x5c801a26 in dump_bfd
/home/shootduck/hotracer-experiments/0-day/hotracer/pilot/objdump/2026-09-08-2.47.50-d715260/binutils-gdb/binutils/objdump.c:5878
    #5 0x5c805012 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
    #6 0x5c805012 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
    #7 0x5c805190 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
    #8 0x5c807489 in main
/home/shootduck/hotracer-experiments/0-day/hotracer/pilot/objdump/2026-09-08-2.47.50-d715260/binutils-gdb/binutils/objdump.c:6494
    #9 0xf4767c74 
(/home/shootduck/hotracer-experiments/0-day/hotracer/pilot/objdump/2026-09-08-2.47.50-d715260/hotracer/poc/task12_access34/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/hotracer/poc/task12_access34/build32-asan/binutils/objdump+0xef016)
(BuildId: 470c59223d09ac1bd1019052b101518a1f12b5cf) in memcpy
Shadow bytes around the buggy address:
  0xe7b03c00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0xe7b03c80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0xe7b03d00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0xe7b03d80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0xe7b03e00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0xe7b03e80: 00 00 00 00 00 00 00 00 00[fa]fa fa fa fa fa fa
  0xe7b03f00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0xe7b03f80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0xe7b04000: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0xe7b04080: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0xe7b04100: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
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
==2500255==ABORTING
```

## Potential fix

Use a wide count and reject every overflowing component of the allocation
calculation before allocating. This leaves valid synthetic symbols unchanged
and reports an oversized malformed input as `bfd_error_file_too_big`.

```diff
diff --git a/bfd/elf.c b/bfd/elf.c
@@
-  size = count * sizeof (asymbol);
+  if (count > (size_t) -1 / sizeof (*s))
+    { bfd_set_error (bfd_error_file_too_big); return -1; }
+  size = (size_t) count * sizeof (*s);
@@
-  size += strlen (...) + sizeof ("@plt");
+  if (len > (size_t) -1 - sizeof ("@plt")
+      || size > (size_t) -1 - len - sizeof ("@plt"))
+    { bfd_set_error (bfd_error_file_too_big); return -1; }
+  size += len + sizeof ("@plt");
```

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