Hi Sayed,

On Sun, Jul 12, 2026 at 10:44:46AM +0530, Sayed Kaif wrote:
> __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.

Thanks, this was an obvious thinko in my original commit 09184fc04f3c
("libdw: Document and handle DW_FORM_indirect in
__libdw_form_val_compute_len").

Probably never caught because the use of DW_FORM_indirect is really
rare. And an actual double indirect should never happen.

> Signed-off-by: Sayed Kaif <[email protected]>
> ---
> diff --git a/libdw/libdw_form.c b/libdw/libdw_form.c
> index 4004544..24622d7 100644
> --- a/libdw/libdw_form.c
> +++ b/libdw/libdw_form.c
> @@ -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)

Pushed as https://sourceware.org/cgit/elfutils/commit/?id=f19bf3a9f1b1

Thanks,

Mark

Reply via email to