https://sourceware.org/bugzilla/show_bug.cgi?id=34317
Bug ID: 34317
Summary: eu-readelf: heap-buffer-overflow (OOB read) in
print_cu_index_section (.debug_cu_index size table)
Product: elfutils
Version: unspecified
Status: UNCONFIRMED
Severity: normal
Priority: P2
Component: tools
Assignee: unassigned at sourceware dot org
Reporter: sujaltuladhar1231 at gmail dot com
CC: elfutils-devel at sourceware dot org
Target Milestone: ---
eu-readelf reads out of bounds (heap-buffer-overflow READ, CWE-125) while
printing the DWARF package index "Size table" of a crafted
.debug_cu_index / .debug_tu_index section.
Affected: git master (HEAD 53336422478ef7698d6555266b5b735d9c5d0250).
Reachable via: eu-readelf --debug-dump=cu_index FILE (also: eu-readelf -w
FILE)
on an untrusted third-party ELF / .dwp file.
Root cause (src/readelf.c, print_cu_index_section):
The size table holds one row of section_count 4-byte slots per unit, i.e.
unit_count rows. But the bound is computed for a single row only:
const unsigned char *lengths = (offsets +
unit_count * section_count * off_bytes);
const unsigned char *lengths_end = lengths + section_count * 4; /* one row
*/
while the size-table loop iterates one row per used unit, up to unit_count:
const unsigned char *prow = lengths + (row - 1) * section_count * 4; /* row
up to unit_count */
for (size_t j = 0; j < section_count; j++)
uint32_t off = read_4ubyte_unaligned (dbg, prow + j * 4); /* OOB
read */
The maximum address read is lengths + unit_count * section_count * 4, but the
sanity check only validated lengths + section_count * 4 <= dataend. So for
unit_count >= 2 the loop reads (unit_count - 1) * section_count * 4 bytes past
the validated end of the section.
The offset table is not affected: its extent
(unit_count * section_count * off_bytes, which equals lengths) is already
validated against dataend. Only the size table omits the unit_count factor.
Reproduction:
A 632-byte PoC ELF (section_count=8, unit_count=2, slot_count=2, with the
.debug_cu_index placed last so its bytes end at EOF) gives a deterministic
AddressSanitizer report when the section data is backed by an exact-sized
buffer (elf_memory over malloc):
ERROR: AddressSanitizer: heap-buffer-overflow READ of size 4
#0 read_4ubyte_unaligned_1 libdw/memory-access.h
#1 print_cu_index_section src/readelf.c:12434
0 bytes after 632-byte region
(For a normal mmap'd run the small overshoot may read adjacent mapped slack
silently -- still an out-of-bounds read / potential heap info leak, or a crash
when it walks off the mapping.)
Fix (attached as a git format-patch with Signed-off-by; also inline):
- const unsigned char *lengths_end = lengths + section_count * 4;
+ /* The size table has one row of section_count 4-byte slots per unit,
+ just like the offset table, so it spans unit_count rows (not one). */
+ const unsigned char *lengths_end = (lengths +
+ unit_count * section_count * 4);
...
+ || ((unit_count != 0)
+ && (section_count > SIZE_MAX / (4 * (size_t) unit_count)))
After the fix the crafted file is rejected via the existing goto invalid_data
path; valid .dwp files are unaffected.
Verified at HEAD (gcc 13.3, aarch64): unpatched -> ASan heap-buffer-overflow at
readelf.c:12434; patched -> clean "invalid data"; the real
eu-readelf --debug-dump=cu_index behaves identically after the patch, and
run-readelf-{d,n,zdebug} regression tests pass.
Attachments: the git format-patch, the 632-byte PoC ELF, and the full ASan log.
--
You are receiving this mail because:
You are on the CC list for the bug.