https://sourceware.org/bugzilla/show_bug.cgi?id=34573
Bug ID: 34573
Summary: bfd: double free in
_bfd_stab_section_find_nearest_line on the
out-of-memory error path
Product: binutils
Version: 2.48 (HEAD)
Status: UNCONFIRMED
Severity: normal
Priority: P2
Component: binutils
Assignee: unassigned at sourceware dot org
Reporter: zkd18cjb at mail dot ustc.edu.cn
Target Milestone: ---
Created attachment 16966
--> https://sourceware.org/bugzilla/attachment.cgi?id=16966&action=edit
Reproducer and fix for the bfd/syms.c double free: test input source, run
script, observed outputs, and one-line fix patch.
In bfd/syms.c, _bfd_stab_section_find_nearest_line contains a double free on an
error path that is reachable when memory allocation fails while handling a
valid .stab debug section.
Flow:
1. The normal path frees reloc_vector (syms.c:1132) but does not set it to NULL
afterwards. The sibling cleanup slots (out2/out1) in the same function do NULL
their pointers after free.
2. The next allocation, info->indextable = bfd_malloc(amt), can fail under
memory pressure; the code then jumps to out3 (syms.c:1189).
3. The out3 label (syms.c:1082) executes free(reloc_vector) again, i.e. a
double free. glibc aborts with "free(): double free detected in tcache 2"
before any memory corruption occurs.
On the other path that reaches out3 (reloc_count < 0) the pointer is still
live, so the label itself is correct. It is the missing NULL assignment after
the normal-path free that makes the OOM path unsafe.
Steps to reproduce:
- Input: stab_big.o, an ELF64 relocatable object with a 144,000,000-byte .stab
section (N_SO entries + N_UNDF padding, no relocations), assembled from the
attached stab_big.s.
- Commands:
as stab_big.s -o stab_big.o
objdump -dlS stab_big.o # control: rc=0, normal output
ulimit -v 220000; objdump -dlS stab_big.o # attack: rc=134
# stderr: "free(): double free
detected in tcache 2"
The memory limit simulates allocation failure at the indextable malloc; without
the limit the same input completes normally, and inputs without .stab (or
without memory pressure) do not trigger the bug.
Expected vs actual:
- Expected: on malloc failure the function returns false cleanly (the
surrounding cleanup already NULLs every other freed pointer).
- Actual: double free leads to SIGABRT (glibc detection) under memory pressure.
Impact:
Robustness only. Triggering requires a valid large .stab input plus memory
pressure (allocation failure). glibc aborts before the second free has any
effect other than the abort itself.
Suggested fix:
Set reloc_vector = NULL right after free(reloc_vector) on the normal path (one
line, matching the out2/out1 pattern). The patch is attached.
Precedents:
- PR 27797: double free when re-allocating a buffer to size 0
(bfd_realloc_or_free), fixed 2021.
- PR 34275: double free on the error path in ctf_link_deduplicating_per_cu,
fixed 2026.
- 57336e2e4d: libctf, avoid potential double free (set the pointer to NULL
after free), 2022.
- 8e4a500a5c: asan, _bfd_stab_section_find_nearest_line segv, 2022 (same
function, same error-path style).
Tested against binutils master (2.48 HEAD, 2026-08, commit 47149393).
--
You are receiving this mail because:
You are on the CC list for the bug.