From d842b34140feaf18d1848bd7d039e2ed1d7d4d35 Mon Sep 17 00:00:00 2001 From: Thiruvadi Rajaraman Date: Wed, 8 Nov 2017 13:41:00 +0530 Subject: binutils: CVE-2017-15024 Source: binutils-gdb.git MR: 76524 Type: Security Fix Disposition: Backport from binutils master ChangeID: 5f22a66eabb228b655605b964ecd350aee700806 Description: 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. Affects: <= 2.29 Signed-off-by: Thiruvadi Rajaraman Reviewed-by: Armin Kuster Signed-off-by: Armin Kuster Signed-off-by: Armin Kuster --- meta/recipes-devtools/binutils/binutils-2.27.inc | 1 + .../binutils/binutils/CVE-2017-15024.patch | 241 +++++++++++++++++++++ 2 files changed, 242 insertions(+) create mode 100644 meta/recipes-devtools/binutils/binutils/CVE-2017-15024.patch diff --git a/meta/recipes-devtools/binutils/binutils-2.27.inc b/meta/recipes-devtools/binutils/binutils-2.27.inc index b1669a4ef0..ae43d2a5d2 100644 --- a/meta/recipes-devtools/binutils/binutils-2.27.inc +++ b/meta/recipes-devtools/binutils/binutils-2.27.inc @@ -101,6 +101,7 @@ SRC_URI = "\ file://CVE-2017-9955_8.patch \ file://CVE-2017-9955_9.patch \ file://CVE-2017-14729.patch \ + file://CVE-2017-15024.patch \ " S = "${WORKDIR}/git" diff --git a/meta/recipes-devtools/binutils/binutils/CVE-2017-15024.patch b/meta/recipes-devtools/binutils/binutils/CVE-2017-15024.patch new file mode 100644 index 0000000000..ef42b13597 --- /dev/null +++ b/meta/recipes-devtools/binutils/binutils/CVE-2017-15024.patch @@ -0,0 +1,241 @@ +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 -- cgit 1.2.3-korg