Found by afl-fuzz. An array type (indirectly) referring to itself in the DIE tree could blow up the stack when dwarf_aggregate_size was called. Limit the recursion depth to MAX_DEPTH (256) entries.
Signed-off-by: Mark Wielaard <m...@klomp.org> --- libdw/ChangeLog | 8 ++++++++ libdw/dwarf_aggregate_size.c | 28 +++++++++++++++++++--------- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/libdw/ChangeLog b/libdw/ChangeLog index 754a7e15..131084c6 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,3 +1,11 @@ +2018-06-18 Mark Wielaard <m...@klomp.org> + + * dwarf_aggregate_size.c (array_size): New depth argument. Use + aggregate_size instead of dwarf_aggregate_size and pass depth. + (aggregate_size): New depth argument. Check depth isn't bigger + than MAX_DEPTH (256). Pass depth to recursive calls. + (dwarf_aggregate_size): ass zero as depth to aggregate_size. + 2018-06-18 Mark Wielaard <m...@klomp.org> * dwarf_peel_type.c (dwarf_peel_type): Limit modifier chain to 64. diff --git a/libdw/dwarf_aggregate_size.c b/libdw/dwarf_aggregate_size.c index d20db71a..75105e4d 100644 --- a/libdw/dwarf_aggregate_size.c +++ b/libdw/dwarf_aggregate_size.c @@ -46,13 +46,17 @@ get_type (Dwarf_Die *die, Dwarf_Attribute *attr_mem, Dwarf_Die *type_mem) return type; } +static int aggregate_size (Dwarf_Die *die, Dwarf_Word *size, + Dwarf_Die *type_mem, int depth); + static int array_size (Dwarf_Die *die, Dwarf_Word *size, - Dwarf_Attribute *attr_mem, Dwarf_Die *type_mem) + Dwarf_Attribute *attr_mem, int depth) { Dwarf_Word eltsize; - if (INTUSE(dwarf_aggregate_size) (get_type (die, attr_mem, type_mem), - &eltsize) != 0) + Dwarf_Die type_mem, aggregate_type_mem; + if (aggregate_size (get_type (die, attr_mem, &type_mem), &eltsize, + &aggregate_type_mem, depth) != 0) return -1; /* An array can have DW_TAG_subrange_type or DW_TAG_enumeration_type @@ -167,11 +171,14 @@ array_size (Dwarf_Die *die, Dwarf_Word *size, } static int -aggregate_size (Dwarf_Die *die, Dwarf_Word *size, Dwarf_Die *type_mem) +aggregate_size (Dwarf_Die *die, Dwarf_Word *size, + Dwarf_Die *type_mem, int depth) { Dwarf_Attribute attr_mem; - if (die == NULL) +/* Arrays of arrays of subrange types of arrays... Don't recurse too deep. */ +#define MAX_DEPTH 256 + if (die == NULL || depth++ >= MAX_DEPTH) return -1; if (INTUSE(dwarf_attr_integrate) (die, DW_AT_byte_size, &attr_mem) != NULL) @@ -180,11 +187,14 @@ aggregate_size (Dwarf_Die *die, Dwarf_Word *size, Dwarf_Die *type_mem) switch (INTUSE(dwarf_tag) (die)) { case DW_TAG_subrange_type: - return aggregate_size (get_type (die, &attr_mem, type_mem), - size, type_mem); /* Tail call. */ + { + Dwarf_Die aggregate_type_mem; + return aggregate_size (get_type (die, &attr_mem, type_mem), + size, &aggregate_type_mem, depth); + } case DW_TAG_array_type: - return array_size (die, size, &attr_mem, type_mem); + return array_size (die, size, &attr_mem, depth); /* Assume references and pointers have pointer size if not given an explicit DW_AT_byte_size. */ @@ -207,7 +217,7 @@ dwarf_aggregate_size (Dwarf_Die *die, Dwarf_Word *size) if (INTUSE (dwarf_peel_type) (die, &die_mem) != 0) return -1; - return aggregate_size (&die_mem, size, &type_mem); + return aggregate_size (&die_mem, size, &type_mem, 0); } INTDEF (dwarf_aggregate_size) OLD_VERSION (dwarf_aggregate_size, ELFUTILS_0.144) -- 2.17.0