diff options
Diffstat (limited to 'meta/recipes-devtools/binutils/binutils/0018-CVE-2022-38128-1.patch')
-rw-r--r-- | meta/recipes-devtools/binutils/binutils/0018-CVE-2022-38128-1.patch | 350 |
1 files changed, 350 insertions, 0 deletions
diff --git a/meta/recipes-devtools/binutils/binutils/0018-CVE-2022-38128-1.patch b/meta/recipes-devtools/binutils/binutils/0018-CVE-2022-38128-1.patch new file mode 100644 index 0000000000..0a490d86b3 --- /dev/null +++ b/meta/recipes-devtools/binutils/binutils/0018-CVE-2022-38128-1.patch @@ -0,0 +1,350 @@ +From f07c08e115e27cddf5a0030dc6332bbee1bd9c6a Mon Sep 17 00:00:00 2001 +From: Alan Modra <amodra@gmail.com> +Date: Thu, 21 Jul 2022 08:38:14 +0930 +Subject: [PATCH] binutils/dwarf.c: abbrev caching + +I'm inclined to think that abbrev caching is counter-productive. The +time taken to search the list of abbrevs converted to internal form is +non-zero, and it's easy to decode the raw abbrevs. It's especially +silly to cache empty lists of decoded abbrevs (happens with zero +padding in .debug_abbrev), or abbrevs as they are displayed when there +is no further use of those abbrevs. This patch stops caching in those +cases. + + * dwarf.c (record_abbrev_list_for_cu): Add free_list param. + Put abbrevs on abbrev_lists here. + (new_abbrev_list): Delete function. + (process_abbrev_set): Return newly allocated list. Move + abbrev base, offset and size checking to.. + (find_and_process_abbrev_set): ..here, new function. Handle + lookup of cached abbrevs here, and calculate start and end + for process_abbrev_set. Return free_list if newly alloc'd. + (process_debug_info): Consolidate cached list lookup, new list + alloc and processing into find_and_process_abbrev_set call. + Free list when not cached. + (display_debug_abbrev): Similarly. + +Upstream-Status: Backport [https://sourceware.org/git/?p=binutils-gdb.git;a=commitdiff;h=f07c08e115e27cddf5a0030dc6332bbee1bd9c6a] + +Signed-off-by: Pgowda <pgowda.cve@gmail.com> +--- + binutils/dwarf.c | 208 +++++++++++++++++++++++++---------------------- + 1 file changed, 110 insertions(+), 98 deletions(-) + +diff --git a/binutils/dwarf.c b/binutils/dwarf.c +index 267ed3bb382..2fc352f74c5 100644 +--- a/binutils/dwarf.c ++++ b/binutils/dwarf.c +@@ -882,8 +882,15 @@ static unsigned long next_free_abbrev_m + #define ABBREV_MAP_ENTRIES_INCREMENT 8 + + static void +-record_abbrev_list_for_cu (dwarf_vma start, dwarf_vma end, abbrev_list * list) ++record_abbrev_list_for_cu (dwarf_vma start, dwarf_vma end, ++ abbrev_list *list, abbrev_list *free_list) + { ++ if (free_list != NULL) ++ { ++ list->next = abbrev_lists; ++ abbrev_lists = list; ++ } ++ + if (cu_abbrev_map == NULL) + { + num_abbrev_map_entries = INITIAL_NUM_ABBREV_MAP_ENTRIES; +@@ -936,20 +943,6 @@ free_all_abbrevs (void) + } + + static abbrev_list * +-new_abbrev_list (dwarf_vma abbrev_base, dwarf_vma abbrev_offset) +-{ +- abbrev_list * list = (abbrev_list *) xcalloc (sizeof * list, 1); +- +- list->abbrev_base = abbrev_base; +- list->abbrev_offset = abbrev_offset; +- +- list->next = abbrev_lists; +- abbrev_lists = list; +- +- return list; +-} +- +-static abbrev_list * + find_abbrev_list_by_abbrev_offset (dwarf_vma abbrev_base, + dwarf_vma abbrev_offset) + { +@@ -966,7 +959,7 @@ find_abbrev_list_by_abbrev_offset (dwarf + /* Find the abbreviation map for the CU that includes OFFSET. + OFFSET is an absolute offset from the start of the .debug_info section. */ + /* FIXME: This function is going to slow down readelf & objdump. +- Consider using a better algorithm to mitigate this effect. */ ++ Not caching abbrevs is likely the answer. */ + + static abbrev_map * + find_abbrev_map_by_offset (dwarf_vma offset) +@@ -1033,40 +1026,18 @@ add_abbrev_attr (unsigned long attrib + list->last_abbrev->last_attr = attr; + } + +-/* Processes the (partial) contents of a .debug_abbrev section. +- Returns NULL if the end of the section was encountered. +- Returns the address after the last byte read if the end of +- an abbreviation set was found. */ ++/* Return processed (partial) contents of a .debug_abbrev section. ++ Returns NULL on errors. */ + +-static unsigned char * ++static abbrev_list * + process_abbrev_set (struct dwarf_section *section, +- dwarf_vma abbrev_base, +- dwarf_vma abbrev_size, +- dwarf_vma abbrev_offset, +- abbrev_list *list) ++ unsigned char *start, ++ unsigned char *end) + { +- if (abbrev_base >= section->size +- || abbrev_size > section->size - abbrev_base) +- { +- /* PR 17531: file:4bcd9ce9. */ +- warn (_("Debug info is corrupted, abbrev size (%lx) is larger than " +- "abbrev section size (%lx)\n"), +- (unsigned long) (abbrev_base + abbrev_size), +- (unsigned long) section->size); +- return NULL; +- } +- if (abbrev_offset >= abbrev_size) +- { +- warn (_("Debug info is corrupted, abbrev offset (%lx) is larger than " +- "abbrev section size (%lx)\n"), +- (unsigned long) abbrev_offset, +- (unsigned long) abbrev_size); +- return NULL; +- } ++ abbrev_list *list = xmalloc (sizeof (*list)); ++ list->first_abbrev = NULL; ++ list->last_abbrev = NULL; + +- unsigned char *start = section->start + abbrev_base; +- unsigned char *end = start + abbrev_size; +- start += abbrev_offset; + while (start < end) + { + unsigned long entry; +@@ -1079,14 +1050,18 @@ process_abbrev_set (struct dwarf_section + /* A single zero is supposed to end the set according + to the standard. If there's more, then signal that to + the caller. */ +- if (start == end) +- return NULL; +- if (entry == 0) +- return start; ++ if (start == end || entry == 0) ++ { ++ list->start_of_next_abbrevs = start != end ? start : NULL; ++ return list; ++ } + + READ_ULEB (tag, start, end); + if (start == end) +- return NULL; ++ { ++ free (list); ++ return NULL; ++ } + + children = *start++; + +@@ -1121,9 +1096,67 @@ process_abbrev_set (struct dwarf_section + /* Report the missing single zero which ends the section. */ + error (_(".debug_abbrev section not zero terminated\n")); + ++ free (list); + return NULL; + } + ++/* Return a sequence of abbrevs in SECTION starting at ABBREV_BASE ++ plus ABBREV_OFFSET and finishing at ABBREV_BASE + ABBREV_SIZE. ++ If FREE_LIST is non-NULL search the already decoded abbrevs on ++ abbrev_lists first and if found set *FREE_LIST to NULL. If ++ searching doesn't find a matching abbrev, set *FREE_LIST to the ++ newly allocated list. If FREE_LIST is NULL, no search is done and ++ the returned abbrev_list is always newly allocated. */ ++ ++static abbrev_list * ++find_and_process_abbrev_set (struct dwarf_section *section, ++ dwarf_vma abbrev_base, ++ dwarf_vma abbrev_size, ++ dwarf_vma abbrev_offset, ++ abbrev_list **free_list) ++{ ++ if (free_list) ++ *free_list = NULL; ++ ++ if (abbrev_base >= section->size ++ || abbrev_size > section->size - abbrev_base) ++ { ++ /* PR 17531: file:4bcd9ce9. */ ++ warn (_("Debug info is corrupted, abbrev size (%lx) is larger than " ++ "abbrev section size (%lx)\n"), ++ (unsigned long) (abbrev_base + abbrev_size), ++ (unsigned long) section->size); ++ return NULL; ++ } ++ if (abbrev_offset >= abbrev_size) ++ { ++ warn (_("Debug info is corrupted, abbrev offset (%lx) is larger than " ++ "abbrev section size (%lx)\n"), ++ (unsigned long) abbrev_offset, ++ (unsigned long) abbrev_size); ++ return NULL; ++ } ++ ++ unsigned char *start = section->start + abbrev_base + abbrev_offset; ++ unsigned char *end = section->start + abbrev_base + abbrev_size; ++ abbrev_list *list = NULL; ++ if (free_list) ++ list = find_abbrev_list_by_abbrev_offset (abbrev_base, abbrev_offset); ++ if (list == NULL) ++ { ++ list = process_abbrev_set (section, start, end); ++ if (list) ++ { ++ list->abbrev_base = abbrev_base; ++ list->abbrev_offset = abbrev_offset; ++ list->next = NULL; ++ } ++ if (free_list) ++ *free_list = list; ++ } ++ return list; ++} ++ + static const char * + get_TAG_name (unsigned long tag) + { +@@ -3670,7 +3703,6 @@ process_debug_info (struct dwarf_section + dwarf_vma cu_offset; + unsigned int offset_size; + struct cu_tu_set * this_set; +- abbrev_list * list; + unsigned char *end_cu; + + hdrptr = start; +@@ -3726,22 +3758,18 @@ process_debug_info (struct dwarf_section + abbrev_size = this_set->section_sizes [DW_SECT_ABBREV]; + } + +- list = find_abbrev_list_by_abbrev_offset (abbrev_base, +- compunit.cu_abbrev_offset); +- if (list == NULL) +- { +- unsigned char * next; +- +- list = new_abbrev_list (abbrev_base, +- compunit.cu_abbrev_offset); +- next = process_abbrev_set (&debug_displays[abbrev_sec].section, +- abbrev_base, abbrev_size, +- compunit.cu_abbrev_offset, list); +- list->start_of_next_abbrevs = next; +- } +- ++ abbrev_list *list; ++ abbrev_list *free_list; ++ list = find_and_process_abbrev_set (&debug_displays[abbrev_sec].section, ++ abbrev_base, abbrev_size, ++ compunit.cu_abbrev_offset, ++ &free_list); + start = end_cu; +- record_abbrev_list_for_cu (cu_offset, start - section_begin, list); ++ if (list != NULL && list->first_abbrev != NULL) ++ record_abbrev_list_for_cu (cu_offset, start - section_begin, ++ list, free_list); ++ else if (free_list != NULL) ++ free_abbrev_list (free_list); + } + + for (start = section_begin, unit = 0; start < end; unit++) +@@ -3757,7 +3785,6 @@ process_debug_info (struct dwarf_section + struct cu_tu_set *this_set; + dwarf_vma abbrev_base; + size_t abbrev_size; +- abbrev_list * list = NULL; + unsigned char *end_cu; + + hdrptr = start; +@@ -3936,20 +3963,10 @@ process_debug_info (struct dwarf_section + } + + /* Process the abbrevs used by this compilation unit. */ +- list = find_abbrev_list_by_abbrev_offset (abbrev_base, +- compunit.cu_abbrev_offset); +- if (list == NULL) +- { +- unsigned char *next; +- +- list = new_abbrev_list (abbrev_base, +- compunit.cu_abbrev_offset); +- next = process_abbrev_set (&debug_displays[abbrev_sec].section, +- abbrev_base, abbrev_size, +- compunit.cu_abbrev_offset, list); +- list->start_of_next_abbrevs = next; +- } +- ++ abbrev_list *list; ++ list = find_and_process_abbrev_set (&debug_displays[abbrev_sec].section, ++ abbrev_base, abbrev_size, ++ compunit.cu_abbrev_offset, NULL); + level = 0; + last_level = level; + saved_level = -1; +@@ -4128,6 +4145,8 @@ process_debug_info (struct dwarf_section + if (entry->children) + ++level; + } ++ if (list != NULL) ++ free_abbrev_list (list); + } + + /* Set num_debug_info_entries here so that it can be used to check if +@@ -6353,24 +6372,15 @@ display_debug_abbrev (struct dwarf_secti + + do + { +- abbrev_list * list; +- dwarf_vma offset; +- +- offset = start - section->start; +- list = find_abbrev_list_by_abbrev_offset (0, offset); ++ dwarf_vma offset = start - section->start; ++ abbrev_list *list = find_and_process_abbrev_set (section, 0, ++ section->size, offset, ++ NULL); + if (list == NULL) +- { +- list = new_abbrev_list (0, offset); +- start = process_abbrev_set (section, 0, section->size, offset, list); +- list->start_of_next_abbrevs = start; +- } +- else +- start = list->start_of_next_abbrevs; +- +- if (list->first_abbrev == NULL) +- continue; ++ break; + +- printf (_(" Number TAG (0x%lx)\n"), (long) offset); ++ if (list->first_abbrev) ++ printf (_(" Number TAG (0x%lx)\n"), (long) offset); + + for (entry = list->first_abbrev; entry; entry = entry->next) + { +@@ -6391,6 +6401,8 @@ display_debug_abbrev (struct dwarf_secti + putchar ('\n'); + } + } ++ start = list->start_of_next_abbrevs; ++ free_abbrev_list (list); + } + while (start); + |