Hi,

This is a design question, not a patch series. I have not started an
implementation and would like maintainer direction before doing so.

While reviewing the libdw DWARF parsers, I noticed an asymmetry in the
reading layer.

get_uleb128/get_sleb128 take an end pointer, and explicitly named unchecked
LEB variants exist for already validated input. The incrementing fixed-width
readers, however, such as:

  read_2ubyte_unaligned_inc
  read_3ubyte_unaligned_inc
  read_4ubyte_unaligned_inc
  read_8ubyte_unaligned_inc
  read_addr_unaligned_inc

do not take an end pointer. Each caller must perform its own bounds check
before the read. This creates a caller-discipline requirement that has
occasionally been missed.

Examples involving this fixed-width-read pattern include:

  - .debug_macro line_offset before read_addr_unaligned_inc,
  - .debug_str_offsets unit_length before a fixed four-byte read,
  - .debug_rnglists unit_length before a fixed four-byte read,
  - .debug_loclists unit_length before a fixed four-byte read.

There are also related one-byte cursor cases, such as minimum_instr_len via
*linep++ and the CFI advance_loc1 fix via *program++. These have a similar
caller-side boundary-check requirement but are not uses of the fixed-width
reader macros.

I want to be precise: this proposal concerns the fixed-width-read subclass,
not every possible libdw bounds error, and I am not claiming that all recent
parser fixes share one root cause.

Sayed, you have recently contributed several bounds fixes in this area. I am
asking whether a central helper could complement that work rather than cut
across or supersede it.

A preliminary source census found about 42 incrementing fixed-width read
call
sites in libdw. For the sites reviewed, an end, limit, bytes_end, or
equivalent
boundary was already available in the surrounding parser, so a checked
reader
would not appear to require new boundary plumbing.

One possible shape, expressed in existing project style rather than as a new
public API, would be:

  - a checked fixed-width reader receives the cursor and end boundary;
  - a short read follows the caller's existing goto/error path, similar to
    cfi_assert or "goto invalid";
  - the cursor advances only after a complete successful read;
  - explicitly named _unchecked variants remain for proven prevalidated
paths,
    mirroring the existing LEB checked/unchecked split;
  - migration could be staged, starting with historically affected parsers;
  - the current ambiguous raw forms could eventually be restricted if that
is
    considered desirable.

Valid-input behavior and the public ABI/API should remain unchanged. The
intent
would only be to reject truncated input earlier and more uniformly. Any
implementation would also include before/after measurements for line-program
and CFI parsing.

I would appreciate your guidance on the following:

  1. Would you prefer a central checked fixed-width reader family, or
continued
     explicit caller-side checks?

  2. Should failure use a cfi_assert/goto-style macro, a bool-returning
inline
     helper, or another existing project idiom?

  3. Should an initial effort cover only libdw, or all users of these shared
     macros, including libdwfl, readelf and libcpu?

  4. Would a checked-by-default plus explicitly named _unchecked split be
     acceptable, following the existing LEB design?

  5. Would you prefer one complete conversion or a staged series beginning
with
     the historically affected parser families?

If you would rather continue handling these checks locally on a case-by-case
basis, that is also a perfectly reasonable answer, and I will not pursue the
larger change.

Thanks,
Karan

Reply via email to