[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.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.