[Bug gdb/34358] New: [gdb] out-of-bounds read parsing a DW_OP_entry_value breg(0) nested block

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=34358

            Bug ID: 34358
           Summary: [gdb] out-of-bounds read parsing a DW_OP_entry_value
                    breg(0) nested block
           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: ---

dwarf_block_to_dwarf_reg_deref (gdb/dwarf2/expr.c) recognizes the restricted
nested blocks that DW_OP_entry_value accepts. Its documented contract is:

    /* If BLOCK contains DW_FORM_block* with just DW_OP_breg*(0) and
DW_OP_deref*
       return the DWARF register number.  Otherwise return -1.  ... */

After reading the breg register and its SLEB offset, it dispatches on the next
byte to find the required DW_OP_deref / DW_OP_deref_size, without first
checking
that a byte remains:

    buf = gdb_read_sleb128 (buf, buf_end, &offset);
    if (buf == NULL)
      return -1;
    if (offset != 0)
      return -1;

    if (*buf == DW_OP_deref)
      {
        buf++;
        *deref_size_return = -1;
      }
    else if (*buf == DW_OP_deref_size)
      {
        buf++;
        if (buf >= buf_end)
          return -1;
        *deref_size_return = *buf++;
      }
    else
      return -1;

When the block ends right after the offset byte, gdb_read_sleb128 leaves
buf == buf_end. There is then no dereference opcode, which is precisely the
"Otherwise return -1" case; but instead of returning -1, the code evaluates
if (*buf == DW_OP_deref) and reads one byte past the end of the block.

The neighboring branches guard exactly this situation (buf >= buf_end after the
breg byte, and again after DW_OP_deref_size); the dispatch right after the SLEB
read is the one place that does not. Because the block is a view into the
surrounding DWARF expression buffer, a block positioned at the end of that
buffer makes this a read past the allocation, observable as a heap-buffer-
overflow read under AddressSanitizer.

A bounds check (buf >= buf_end) after the SLEB read addresses both aspects: it
avoids the out-of-bounds read, and it makes a block with no trailing
dereference
opcode return -1, as the contract already promises.

-- 
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.