execute_cfi walks a CFI instruction stream delimited by program and end. The outer loop condition (program < end) only guarantees that the opcode byte is present. The DW_CFA_advance_loc1 case then reads a one-byte operand with
operand = *program++; without first checking that another byte is available. The sibling cases DW_CFA_advance_loc2/4/8 all guard their fixed-size reads with cfi_assert (program + N <= end), and readelf's own CFI printer guards advance_loc1 with an equivalent check, but this path was missing it. A crafted or truncated FDE/CIE whose instruction stream ends exactly on a DW_CFA_advance_loc1 opcode therefore causes a one-byte read past the end of the CFI data buffer. Add the matching bounds check so malformed input is rejected with DWARF_E_INVALID_CFI instead. Signed-off-by: Sayed Kaif <[email protected]> --- diff --git a/libdw/cfi.c b/libdw/cfi.c index 743bfc0..a960724 100644 --- a/libdw/cfi.c +++ b/libdw/cfi.c @@ -146,6 +146,7 @@ execute_cfi (Dwarf_CFI *cache, /* These cases move LOC, i.e. "create a new table row". */ case DW_CFA_advance_loc1: + cfi_assert (program + 1 <= end); operand = *program++; FALLTHROUGH; case DW_CFA_advance_loc + 0 ... DW_CFA_advance_loc + CFI_PRIMARY_MAX: -- 2.52.0
