From 52a93b95ec0771c97e26f0bb28630a271a667bd2 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Sun, 24 Sep 2017 14:37:16 +0930 Subject: [PATCH] PR22187, infinite loop in find_abstract_instance_name This patch prevents the simple case of infinite recursion in find_abstract_instance_name by ensuring that the attributes being processed are not the same as the previous call. The patch also does a little cleanup, and leaves in place some changes to the nested_funcs array that I made when I wrongly thought looping might occur in scan_unit_for_symbols. PR 22187 * dwarf2.c (find_abstract_instance_name): Add orig_info_ptr and pname param. Return status. Make name const. Don't abort, return an error. Formatting. Exit if current info_ptr matches orig_info_ptr. Update callers. (scan_unit_for_symbols): Start at nesting_level of zero. Make nested_funcs an array of structs for extensibility. Formatting. Upstream-Status: Backport Affects: <= 2.29.1 CVE: CVE-2017-15024 Signed-off-by: Armin Kuster --- bfd/ChangeLog | 10 ++++++++ bfd/dwarf2.c | 76 +++++++++++++++++++++++++++++++++++++++-------------------- 2 files changed, 61 insertions(+), 25 deletions(-) Index: git/bfd/dwarf2.c =================================================================== --- git.orig/bfd/dwarf2.c +++ git/bfd/dwarf2.c @@ -2823,9 +2823,11 @@ lookup_symbol_in_variable_table (struct return FALSE; } -static char * +static bfd_boolean find_abstract_instance_name (struct comp_unit *unit, + bfd_byte *orig_info_ptr, struct attribute *attr_ptr, + const char **pname, bfd_boolean *is_linkage) { bfd *abfd = unit->abfd; @@ -2835,7 +2837,7 @@ find_abstract_instance_name (struct comp struct abbrev_info *abbrev; bfd_uint64_t die_ref = attr_ptr->u.val; struct attribute attr; - char *name = NULL; + const char *name = NULL; /* DW_FORM_ref_addr can reference an entry in a different CU. It is an offset from the .debug_info section, not the current CU. */ @@ -2844,7 +2846,12 @@ find_abstract_instance_name (struct comp /* We only support DW_FORM_ref_addr within the same file, so any relocations should be resolved already. */ if (!die_ref) - abort (); + { + _bfd_error_handler + (_("Dwarf Error: Abstract instance DIE ref zero.")); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } info_ptr = unit->sec_info_ptr + die_ref; info_ptr_end = unit->end_ptr; @@ -2879,9 +2886,10 @@ find_abstract_instance_name (struct comp _bfd_error_handler (_("Dwarf Error: Unable to read alt ref %u."), die_ref); bfd_set_error (bfd_error_bad_value); - return NULL; + return FALSE; } - info_ptr_end = unit->stash->alt_dwarf_info_buffer + unit->stash->alt_dwarf_info_size; + info_ptr_end = (unit->stash->alt_dwarf_info_buffer + + unit->stash->alt_dwarf_info_size); /* FIXME: Do we need to locate the correct CU, in a similar fashion to the code in the DW_FORM_ref_addr case above ? */ @@ -2904,6 +2912,7 @@ find_abstract_instance_name (struct comp _bfd_error_handler (_("Dwarf Error: Could not find abbrev number %u."), abbrev_number); bfd_set_error (bfd_error_bad_value); + return FALSE; } else { @@ -2913,6 +2922,15 @@ find_abstract_instance_name (struct comp info_ptr, info_ptr_end); if (info_ptr == NULL) break; + /* It doesn't ever make sense for DW_AT_specification to + refer to the same DIE. Stop simple recursion. */ + if (info_ptr == orig_info_ptr) + { + _bfd_error_handler + (_("Dwarf Error: Abstract instance recursion detected.")); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } switch (attr.name) { case DW_AT_name: @@ -2926,7 +2944,9 @@ find_abstract_instance_name (struct comp } break; case DW_AT_specification: - name = find_abstract_instance_name (unit, &attr, is_linkage); + if (!find_abstract_instance_name (unit, info_ptr, &attr, + pname, is_linkage)) + return FALSE; break; case DW_AT_linkage_name: case DW_AT_MIPS_linkage_name: @@ -2944,7 +2964,8 @@ find_abstract_instance_name (struct comp } } } - return name; + *pname = name; + return TRUE; } static bfd_boolean @@ -3005,20 +3026,22 @@ scan_unit_for_symbols (struct comp_unit bfd *abfd = unit->abfd; bfd_byte *info_ptr = unit->first_child_die_ptr; bfd_byte *info_ptr_end = unit->stash->info_ptr_end; - int nesting_level = 1; - struct funcinfo **nested_funcs; + int nesting_level = 0; + struct nest_funcinfo { + struct funcinfo *func; + } *nested_funcs; int nested_funcs_size; /* Maintain a stack of in-scope functions and inlined functions, which we can use to set the caller_func field. */ nested_funcs_size = 32; - nested_funcs = (struct funcinfo **) - bfd_malloc (nested_funcs_size * sizeof (struct funcinfo *)); + nested_funcs = (struct nest_funcinfo *) + bfd_malloc (nested_funcs_size * sizeof (*nested_funcs)); if (nested_funcs == NULL) return FALSE; - nested_funcs[nesting_level] = 0; + nested_funcs[nesting_level].func = 0; - while (nesting_level) + while (nesting_level >= 0) { unsigned int abbrev_number, bytes_read, i; struct abbrev_info *abbrev; @@ -3076,13 +3099,13 @@ scan_unit_for_symbols (struct comp_unit BFD_ASSERT (!unit->cached); if (func->tag == DW_TAG_inlined_subroutine) - for (i = nesting_level - 1; i >= 1; i--) - if (nested_funcs[i]) + for (i = nesting_level; i-- != 0; ) + if (nested_funcs[i].func) { - func->caller_func = nested_funcs[i]; + func->caller_func = nested_funcs[i].func; break; } - nested_funcs[nesting_level] = func; + nested_funcs[nesting_level].func = func; } else { @@ -3102,12 +3125,13 @@ scan_unit_for_symbols (struct comp_unit } /* No inline function in scope at this nesting level. */ - nested_funcs[nesting_level] = 0; + nested_funcs[nesting_level].func = 0; } for (i = 0; i < abbrev->num_attrs; ++i) { - info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit, info_ptr, info_ptr_end); + info_ptr = read_attribute (&attr, &abbrev->attrs[i], + unit, info_ptr, info_ptr_end); if (info_ptr == NULL) goto fail; @@ -3126,8 +3150,10 @@ scan_unit_for_symbols (struct comp_unit case DW_AT_abstract_origin: case DW_AT_specification: - func->name = find_abstract_instance_name (unit, &attr, - &func->is_linkage); + if (!find_abstract_instance_name (unit, info_ptr, &attr, + &func->name, + &func->is_linkage)) + goto fail; break; case DW_AT_name: @@ -3254,17 +3280,17 @@ scan_unit_for_symbols (struct comp_unit if (nesting_level >= nested_funcs_size) { - struct funcinfo **tmp; + struct nest_funcinfo *tmp; nested_funcs_size *= 2; - tmp = (struct funcinfo **) + tmp = (struct nest_funcinfo *) bfd_realloc (nested_funcs, - nested_funcs_size * sizeof (struct funcinfo *)); + nested_funcs_size * sizeof (*nested_funcs)); if (tmp == NULL) goto fail; nested_funcs = tmp; } - nested_funcs[nesting_level] = 0; + nested_funcs[nesting_level].func = 0; } }