From 9d34f1d7c828a40dd8457cd5e23bfa6821e36e28 Mon Sep 17 00:00:00 2001 From: pancake Date: Sat, 3 Apr 2021 03:49:07 +0200 Subject: [PATCH] Fix #18534 - infinite recursion (stack exhaustion) in dwarf --- libr/anal/dwarf_process.c | 50 ++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/libr/anal/dwarf_process.c b/libr/anal/dwarf_process.c index 319b5e032b..34d59e28b3 100644 --- a/libr/anal/dwarf_process.c +++ b/libr/anal/dwarf_process.c @@ -1,4 +1,4 @@ -/* radare - LGPL - Copyright 2012-2020 - houndthe */ +/* radare - LGPL - Copyright 2012-2021 - houndthe */ #include "base_types.h" #include @@ -254,12 +254,25 @@ static st32 parse_array_type(Context *ctx, ut64 idx, RStrBuf *strbuf) { * TODO make cache for type entries, one type is usually referenced * multiple times which means it's parsed multiple times instead of once */ -static st32 parse_type (Context *ctx, const ut64 offset, RStrBuf *strbuf, ut64 *size) { +static st32 parse_type(Context *ctx, const ut64 offset, RStrBuf *strbuf, ut64 *size, HtUP **visited) { r_return_val_if_fail (strbuf, -1); RBinDwarfDie *die = ht_up_find (ctx->die_map, offset, NULL); if (!die) { return -1; } + bool root = false; + + if (!visited) { + root = true; + SetU *su = set_u_new (); + visited = malloc (sizeof (void*)); + *visited = su; + } + if (visited && set_u_contains (*visited, offset)) { + eprintf ("anal.dwarf.parse_type: infinite recursion detected.\n"); + return -1; + } + set_u_add (*visited, offset); st32 type_idx; st32 tag; @@ -276,7 +289,7 @@ static st32 parse_type (Context *ctx, const ut64 offset, RStrBuf *strbuf, ut64 * r_strbuf_append (strbuf, "void"); r_strbuf_append (strbuf, " *"); } else { - tag = parse_type (ctx, die->attr_values[type_idx].reference, strbuf, size); + tag = parse_type (ctx, die->attr_values[type_idx].reference, strbuf, size, visited); if (tag == DW_TAG_subroutine_type) { strbuf_rev_prepend_char (strbuf, "(*)", '('); } else if (tag == DW_TAG_pointer_type) { @@ -305,7 +318,7 @@ static st32 parse_type (Context *ctx, const ut64 offset, RStrBuf *strbuf, ut64 * if (type_idx == -1) { r_strbuf_append (strbuf, "void"); } else { - parse_type (ctx, die->attr_values[type_idx].reference, strbuf, size); + parse_type (ctx, die->attr_values[type_idx].reference, strbuf, size, visited); } r_strbuf_append (strbuf, " ("); if (die->has_children) { // has parameters @@ -315,48 +328,51 @@ static st32 parse_type (Context *ctx, const ut64 offset, RStrBuf *strbuf, ut64 * case DW_TAG_array_type: type_idx = find_attr_idx (die, DW_AT_type); if (type_idx != -1) { - parse_type (ctx, die->attr_values[type_idx].reference, strbuf, size); + parse_type (ctx, die->attr_values[type_idx].reference, strbuf, size, visited); } parse_array_type (ctx, die - ctx->all_dies, strbuf); break; case DW_TAG_const_type: type_idx = find_attr_idx (die, DW_AT_type); if (type_idx != -1) { - parse_type (ctx, die->attr_values[type_idx].reference, strbuf, size); + parse_type (ctx, die->attr_values[type_idx].reference, strbuf, size, visited); } r_strbuf_append (strbuf, " const"); break; case DW_TAG_volatile_type: type_idx = find_attr_idx (die, DW_AT_type); if (type_idx != -1) { - parse_type (ctx, die->attr_values[type_idx].reference, strbuf, size); + parse_type (ctx, die->attr_values[type_idx].reference, strbuf, size, visited); } r_strbuf_append (strbuf, " volatile"); break; case DW_TAG_restrict_type: type_idx = find_attr_idx (die, DW_AT_type); if (type_idx != -1) { - parse_type (ctx, die->attr_values[type_idx].reference, strbuf, size); + parse_type (ctx, die->attr_values[type_idx].reference, strbuf, size, visited); } r_strbuf_append (strbuf, " restrict"); break; case DW_TAG_rvalue_reference_type: type_idx = find_attr_idx (die, DW_AT_type); if (type_idx != -1) { - parse_type (ctx, die->attr_values[type_idx].reference, strbuf, size); + parse_type (ctx, die->attr_values[type_idx].reference, strbuf, size, visited); } r_strbuf_append (strbuf, " &&"); break; case DW_TAG_reference_type: type_idx = find_attr_idx (die, DW_AT_type); if (type_idx != -1) { - parse_type (ctx, die->attr_values[type_idx].reference, strbuf, size); + parse_type (ctx, die->attr_values[type_idx].reference, strbuf, size, visited); } r_strbuf_append (strbuf, " &"); break; default: break; } + if (root) { + set_u_free (*visited); + } return (st32)die->tag; } @@ -391,7 +407,7 @@ static RAnalStructMember *parse_struct_member (Context *ctx, ut64 idx, RAnalStru } break; case DW_AT_type: - parse_type (ctx, value->reference, &strbuf, &size); + parse_type (ctx, value->reference, &strbuf, &size, NULL); free (type); type = r_strbuf_drain_nofree (&strbuf); if (!type || !*type) { @@ -587,7 +603,7 @@ static void parse_enum_type(Context *ctx, ut64 idx) { if (type_attr_idx != -1) { RStrBuf strbuf; r_strbuf_init (&strbuf); - parse_type (ctx, die->attr_values[type_attr_idx].reference, &strbuf, &base_type->size); + parse_type (ctx, die->attr_values[type_attr_idx].reference, &strbuf, &base_type->size, NULL); base_type->type = r_strbuf_drain_nofree (&strbuf); } @@ -655,7 +671,7 @@ static void parse_typedef(Context *ctx, ut64 idx) { } break; case DW_AT_type: - parse_type (ctx, value->reference, &strbuf, &size); + parse_type (ctx, value->reference, &strbuf, &size, NULL); free (type); type = r_strbuf_drain_nofree (&strbuf); if (!type) { @@ -747,7 +763,7 @@ static void get_spec_die_type(Context *ctx, RBinDwarfDie *die, RStrBuf *ret_type st32 attr_idx = find_attr_idx (die, DW_AT_type); if (attr_idx != -1) { ut64 size = 0; - parse_type (ctx, die->attr_values[attr_idx].reference, ret_type, &size); + parse_type (ctx, die->attr_values[attr_idx].reference, ret_type, &size, NULL); } } @@ -785,7 +801,7 @@ static void parse_abstract_origin(Context *ctx, ut64 offset, RStrBuf *type, cons has_linkage_name = true; break; case DW_AT_type: - parse_type (ctx, val->reference, type, &size); + parse_type (ctx, val->reference, type, &size, NULL); break; default: break; @@ -1187,7 +1203,7 @@ static st32 parse_function_args_and_vars(Context *ctx, ut64 idx, RStrBuf *args, has_linkage_name = true; break; case DW_AT_type: - parse_type (ctx, val->reference, &type, NULL); + parse_type (ctx, val->reference, &type, NULL, NULL); break; // abstract origin is supposed to have omitted information case DW_AT_abstract_origin: @@ -1379,7 +1395,7 @@ static void parse_function(Context *ctx, ut64 idx) { break; } case DW_AT_type: - parse_type (ctx, val->reference, &ret_type, NULL); + parse_type (ctx, val->reference, &ret_type, NULL, NULL); break; case DW_AT_virtuality: fcn.is_method = true; /* method specific attr */