]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
libdw: Fix out-of-bounds read in DW_FORM_indirect form length parsing
authorSayed Kaif <skaif@digiscrypt.com>
Sun, 12 Jul 2026 05:14:46 +0000 (10:44 +0530)
committerMark Wielaard <mark@klomp.org>
Sun, 12 Jul 2026 11:12:17 +0000 (13:12 +0200)
__libdw_form_val_compute_len handles DW_FORM_indirect by reading the
real form as an uleb128 and then computing the length of a value of
that form.  The guard that rejects a nested DW_FORM_indirect or a
DW_FORM_implicit_const inspected *valp instead of the decoded form
value u128.

After get_uleb128 the cursor valp may point right at the end of the CU
data (get_uleb128 advances up to the section end), so dereferencing
*valp reads one byte past the buffer.  A DW_FORM_indirect attribute
whose inner form uleb128 ends exactly at cu->endp triggers a one-byte
out-of-bounds read.  This path is reached from dwarf_child() and
dwarf_getattrs() while skipping attribute values, which rely on
__libdw_form_val_len doing a safe bounds check.

Besides the overread, comparing *valp (the first byte of the value
data) rather than u128 (the form) is wrong: it can spuriously reject a
valid attribute whose value happens to start with 0x16 or 0x21.
Compare u128, which is already the decoded form and needs no further
dereference.

* libdw/libdw_form.c (__libdw_form_val_compute_len): Check the
decoded form u128 instead of dereferencing *valp for the nested
DW_FORM_indirect / DW_FORM_implicit_const guard.

Signed-off-by: Sayed Kaif <skaif@digiscrypt.com>
libdw/libdw_form.c

index 400454401b66ce298b8bdab643b14798eb6f0a56..24622d7e5f515167e246dea7794265b8018a5fb1 100644 (file)
@@ -126,7 +126,7 @@ __libdw_form_val_compute_len (struct Dwarf_CU *cu, unsigned int form,
       if (valp >= endp)
        goto invalid;
       get_uleb128 (u128, valp, endp);
-      if (*valp == DW_FORM_indirect || *valp == DW_FORM_implicit_const)
+      if (u128 == DW_FORM_indirect || u128 == DW_FORM_implicit_const)
        return (size_t) -1;
       result = __libdw_form_val_len (cu, u128, valp);
       if (result != (size_t) -1)