commit 52a93b95ec0771c97e26f0bb28630a271a667bd2 Author: Alan Modra Date: Sun Sep 24 14:37:16 2017 +0930 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 CVE: CVE-2017-15024 Signed-off-by: Thiruvadi Rajaraman Index: git/bfd/dwarf2.c =================================================================== --- git.orig/bfd/dwarf2.c 2017-11-08 12:44:59.198052588 +0530 +++ git/bfd/dwarf2.c 2017-11-08 12:45:10.670155730 +0530 @@ -2273,9 +2273,11 @@ 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; @@ -2285,7 +2287,7 @@ 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. */ @@ -2294,7 +2296,12 @@ /* 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; @@ -2329,9 +2336,10 @@ (*_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 ? */ @@ -2353,6 +2361,7 @@ (*_bfd_error_handler) (_("Dwarf Error: Could not find abbrev number %u."), abbrev_number); bfd_set_error (bfd_error_bad_value); + return FALSE; } else { @@ -2362,6 +2371,15 @@ 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: @@ -2375,7 +2393,9 @@ } 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: @@ -2393,7 +2413,8 @@ } } } - return name; + *pname = name; + return TRUE; } static bfd_boolean @@ -2454,20 +2475,22 @@ 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; @@ -2516,13 +2539,13 @@ 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 { @@ -2541,12 +2564,13 @@ } /* 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; @@ -2565,8 +2589,10 @@ 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: @@ -2691,17 +2717,17 @@ 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; } } Index: git/bfd/ChangeLog =================================================================== --- git.orig/bfd/ChangeLog 2017-11-08 12:45:10.614155229 +0530 +++ git/bfd/ChangeLog 2017-11-08 12:46:55.791054918 +0530 @@ -1,3 +1,13 @@ +2017-09-24 Alan Modra + + 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. + 2017-09-22 H.J. Lu PR binutils/22170