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

Reply via email to