[Bug gdb/34352] New: [gdb] gdb overflows composite piece-size arithmetic for DW_OP_piece / DW_OP_bit_piece
firmiana402 at gmail dot com via Gdb-prs <[email protected]>
| Newsgroups | gmane.comp.gdb.bugs.discuss |
|---|---|
| Message-ID | <[email protected]/bugzilla/> |
https://sourceware.org/bugzilla/show_bug.cgi?id=34352
Bug ID: 34352
Summary: [gdb] gdb overflows composite piece-size arithmetic
for DW_OP_piece / DW_OP_bit_piece
Product: gdb
Version: HEAD
Status: UNCONFIRMED
Severity: normal
Priority: P2
Component: gdb
Assignee: unassigned at sourceware dot org
Reporter: firmiana402 at gmail dot com
Target Milestone: ---
GDB's guard against an oversized composite location computes the total piece
size with 64-bit arithmetic that can overflow. A gigantic malformed piece list
wraps down to a small (often zero) size, so the guard is bypassed and the
composite is accepted instead of rejected.
The guard is in dwarf_expr_context::fetch_result (gdb/dwarf2/expr.c):
ULONGEST bit_size = 0;
for (dwarf_expr_piece &piece : this->m_pieces)
bit_size += piece.size;
/* Complain if the expression is larger than the size of the outer type.
*/
if (bit_size > 8 * type->length ())
invalid_synthetic_pointer ();
Two paths reach it with a wrapped bit_size:
- DW_OP_piece — execute_stack_op scales the byte operand with
add_piece (8 * size, 0, op). size is uint64_t, so 8 * size overflows once
size >= 2^61; 0x2000000000000000 * 8 == 2^64 stores piece.size == 0.
- DW_OP_bit_piece — the bit operand is stored verbatim, but the
bit_size += piece.size sum wraps: two pieces of 0x8000000000000000 bits add
up to 2^64 == 0.
Either way the wrap defeats the very bit_size > 8 * type->length () check that
is meant to reject an oversized composite.
## Minimal Cases
Raw DWARF expressions (this is about consumer-side validation of malformed
input):
DW_OP_lit0
DW_OP_piece 0x2000000000000000
DW_OP_lit0
DW_OP_bit_piece 0x8000000000000000 0
DW_OP_lit0
DW_OP_bit_piece 0x8000000000000000 0
Each describes a composite vastly larger than any real object. Per DWARF v5
§2.6.1.2 ([DWARF5.pdf](https://dwarfstd.org/doc/DWARF5.pdf)), DW_OP_piece gives
a size in bytes and DW_OP_bit_piece a size in bits.
GDB's own bit_size > 8 * type->length () guard is meant to reject exactly
these, but the overflow makes bit_size wrap to a small value, so both pass
validation and are accepted.
Once accepted, GDB composes a value from the malformed pieces: it allocates a
contents buffer and reads each piece's location. That work is bounded — the
transfer is clamped to the outer type size and the allocation is capped by
max-value-size (64 KiB by default) — so it is not a memory-safety or
unbounded-allocation issue. But GDB still performs a real allocation and issues
a possibly bogus memory read (e.g. at an address taken from the malformed
expression) for input it should have rejected, and that cost scales with the
outer type up to the max-value-size limit.
## Potential Fix
GDB should bounds-check the DW_OP_piece / DW_OP_bit_piece size operand
before the bit-size arithmetic, so an oversized piece is rejected up
front instead of overflowing the internal total.
--
You are receiving this mail because:
You are on the CC list for the bug.