xref: /OK3568_Linux_fs/yocto/poky/meta/recipes-devtools/binutils/binutils/0018-CVE-2022-38128-1.patch (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1From f07c08e115e27cddf5a0030dc6332bbee1bd9c6a Mon Sep 17 00:00:00 2001
2From: Alan Modra <amodra@gmail.com>
3Date: Thu, 21 Jul 2022 08:38:14 +0930
4Subject: [PATCH] binutils/dwarf.c: abbrev caching
5
6I'm inclined to think that abbrev caching is counter-productive.  The
7time taken to search the list of abbrevs converted to internal form is
8non-zero, and it's easy to decode the raw abbrevs.  It's especially
9silly to cache empty lists of decoded abbrevs (happens with zero
10padding in .debug_abbrev), or abbrevs as they are displayed when there
11is no further use of those abbrevs.  This patch stops caching in those
12cases.
13
14	* dwarf.c (record_abbrev_list_for_cu): Add free_list param.
15	Put abbrevs on abbrev_lists here.
16	(new_abbrev_list): Delete function.
17	(process_abbrev_set): Return newly allocated list.  Move
18	abbrev base, offset and size checking to..
19	(find_and_process_abbrev_set): ..here, new function.  Handle
20	lookup of cached abbrevs here, and calculate start and end
21	for process_abbrev_set.  Return free_list if newly alloc'd.
22	(process_debug_info): Consolidate cached list lookup, new list
23	alloc and processing into find_and_process_abbrev_set call.
24	Free list when not cached.
25	(display_debug_abbrev): Similarly.
26
27Upstream-Status: Backport [https://sourceware.org/git/?p=binutils-gdb.git;a=commitdiff;h=f07c08e115e27cddf5a0030dc6332bbee1bd9c6a]
28
29Signed-off-by: Pgowda <pgowda.cve@gmail.com>
30---
31 binutils/dwarf.c | 208 +++++++++++++++++++++++++----------------------
32 1 file changed, 110 insertions(+), 98 deletions(-)
33
34diff --git a/binutils/dwarf.c b/binutils/dwarf.c
35index 267ed3bb382..2fc352f74c5 100644
36--- a/binutils/dwarf.c
37+++ b/binutils/dwarf.c
38@@ -882,8 +882,15 @@ static unsigned long  next_free_abbrev_m
39 #define ABBREV_MAP_ENTRIES_INCREMENT   8
40
41 static void
42-record_abbrev_list_for_cu (dwarf_vma start, dwarf_vma end, abbrev_list * list)
43+record_abbrev_list_for_cu (dwarf_vma start, dwarf_vma end,
44+			   abbrev_list *list, abbrev_list *free_list)
45 {
46+  if (free_list != NULL)
47+    {
48+      list->next = abbrev_lists;
49+      abbrev_lists = list;
50+    }
51+
52   if (cu_abbrev_map == NULL)
53     {
54       num_abbrev_map_entries = INITIAL_NUM_ABBREV_MAP_ENTRIES;
55@@ -936,20 +943,6 @@ free_all_abbrevs (void)
56 }
57
58 static abbrev_list *
59-new_abbrev_list (dwarf_vma abbrev_base, dwarf_vma abbrev_offset)
60-{
61-  abbrev_list * list = (abbrev_list *) xcalloc (sizeof * list, 1);
62-
63-  list->abbrev_base = abbrev_base;
64-  list->abbrev_offset = abbrev_offset;
65-
66-  list->next = abbrev_lists;
67-  abbrev_lists = list;
68-
69-  return list;
70-}
71-
72-static abbrev_list *
73 find_abbrev_list_by_abbrev_offset (dwarf_vma abbrev_base,
74 				   dwarf_vma abbrev_offset)
75 {
76@@ -966,7 +959,7 @@ find_abbrev_list_by_abbrev_offset (dwarf
77 /* Find the abbreviation map for the CU that includes OFFSET.
78    OFFSET is an absolute offset from the start of the .debug_info section.  */
79 /* FIXME: This function is going to slow down readelf & objdump.
80-   Consider using a better algorithm to mitigate this effect.  */
81+   Not caching abbrevs is likely the answer.  */
82
83 static  abbrev_map *
84 find_abbrev_map_by_offset (dwarf_vma offset)
85@@ -1033,40 +1026,18 @@ add_abbrev_attr (unsigned long    attrib
86   list->last_abbrev->last_attr = attr;
87 }
88
89-/* Processes the (partial) contents of a .debug_abbrev section.
90-   Returns NULL if the end of the section was encountered.
91-   Returns the address after the last byte read if the end of
92-   an abbreviation set was found.  */
93+/* Return processed (partial) contents of a .debug_abbrev section.
94+   Returns NULL on errors.  */
95
96-static unsigned char *
97+static abbrev_list *
98 process_abbrev_set (struct dwarf_section *section,
99-		    dwarf_vma abbrev_base,
100-		    dwarf_vma abbrev_size,
101-		    dwarf_vma abbrev_offset,
102-		    abbrev_list *list)
103+		    unsigned char *start,
104+		    unsigned char *end)
105 {
106-  if (abbrev_base >= section->size
107-      || abbrev_size > section->size - abbrev_base)
108-    {
109-      /* PR 17531: file:4bcd9ce9.  */
110-      warn (_("Debug info is corrupted, abbrev size (%lx) is larger than "
111-	      "abbrev section size (%lx)\n"),
112-	      (unsigned long) (abbrev_base + abbrev_size),
113-	      (unsigned long) section->size);
114-      return NULL;
115-    }
116-  if (abbrev_offset >= abbrev_size)
117-    {
118-      warn (_("Debug info is corrupted, abbrev offset (%lx) is larger than "
119-	      "abbrev section size (%lx)\n"),
120-	    (unsigned long) abbrev_offset,
121-	    (unsigned long) abbrev_size);
122-      return NULL;
123-    }
124+  abbrev_list *list = xmalloc (sizeof (*list));
125+  list->first_abbrev = NULL;
126+  list->last_abbrev = NULL;
127
128-  unsigned char *start = section->start + abbrev_base;
129-  unsigned char *end = start + abbrev_size;
130-  start += abbrev_offset;
131   while (start < end)
132     {
133       unsigned long entry;
134@@ -1079,14 +1050,18 @@ process_abbrev_set (struct dwarf_section
135       /* A single zero is supposed to end the set according
136 	 to the standard.  If there's more, then signal that to
137 	 the caller.  */
138-      if (start == end)
139-	return NULL;
140-      if (entry == 0)
141-	return start;
142+      if (start == end || entry == 0)
143+	{
144+	  list->start_of_next_abbrevs = start != end ? start : NULL;
145+	  return list;
146+	}
147
148       READ_ULEB (tag, start, end);
149       if (start == end)
150-	return NULL;
151+	{
152+	  free (list);
153+	  return NULL;
154+	}
155
156       children = *start++;
157
158@@ -1121,9 +1096,67 @@ process_abbrev_set (struct dwarf_section
159   /* Report the missing single zero which ends the section.  */
160   error (_(".debug_abbrev section not zero terminated\n"));
161
162+  free (list);
163   return NULL;
164 }
165
166+/* Return a sequence of abbrevs in SECTION starting at ABBREV_BASE
167+   plus ABBREV_OFFSET and finishing at ABBREV_BASE + ABBREV_SIZE.
168+   If FREE_LIST is non-NULL search the already decoded abbrevs on
169+   abbrev_lists first and if found set *FREE_LIST to NULL.  If
170+   searching doesn't find a matching abbrev, set *FREE_LIST to the
171+   newly allocated list.  If FREE_LIST is NULL, no search is done and
172+   the returned abbrev_list is always newly allocated.  */
173+
174+static abbrev_list *
175+find_and_process_abbrev_set (struct dwarf_section *section,
176+			     dwarf_vma abbrev_base,
177+			     dwarf_vma abbrev_size,
178+			     dwarf_vma abbrev_offset,
179+			     abbrev_list **free_list)
180+{
181+  if (free_list)
182+    *free_list = NULL;
183+
184+  if (abbrev_base >= section->size
185+      || abbrev_size > section->size - abbrev_base)
186+    {
187+      /* PR 17531: file:4bcd9ce9.  */
188+      warn (_("Debug info is corrupted, abbrev size (%lx) is larger than "
189+	      "abbrev section size (%lx)\n"),
190+	      (unsigned long) (abbrev_base + abbrev_size),
191+	      (unsigned long) section->size);
192+      return NULL;
193+    }
194+  if (abbrev_offset >= abbrev_size)
195+    {
196+      warn (_("Debug info is corrupted, abbrev offset (%lx) is larger than "
197+	      "abbrev section size (%lx)\n"),
198+	    (unsigned long) abbrev_offset,
199+	    (unsigned long) abbrev_size);
200+      return NULL;
201+    }
202+
203+  unsigned char *start = section->start + abbrev_base + abbrev_offset;
204+  unsigned char *end = section->start + abbrev_base + abbrev_size;
205+  abbrev_list *list = NULL;
206+  if (free_list)
207+    list = find_abbrev_list_by_abbrev_offset (abbrev_base, abbrev_offset);
208+  if (list == NULL)
209+    {
210+      list = process_abbrev_set (section, start, end);
211+      if (list)
212+	{
213+	  list->abbrev_base = abbrev_base;
214+	  list->abbrev_offset = abbrev_offset;
215+	  list->next = NULL;
216+	}
217+      if (free_list)
218+	*free_list = list;
219+    }
220+  return list;
221+}
222+
223 static const char *
224 get_TAG_name (unsigned long tag)
225 {
226@@ -3670,7 +3703,6 @@ process_debug_info (struct dwarf_section
227       dwarf_vma                 cu_offset;
228       unsigned int              offset_size;
229       struct cu_tu_set *        this_set;
230-      abbrev_list *             list;
231       unsigned char *end_cu;
232
233       hdrptr = start;
234@@ -3726,22 +3758,18 @@ process_debug_info (struct dwarf_section
235 	  abbrev_size = this_set->section_sizes [DW_SECT_ABBREV];
236 	}
237
238-      list = find_abbrev_list_by_abbrev_offset (abbrev_base,
239-						compunit.cu_abbrev_offset);
240-      if (list == NULL)
241-	{
242-	  unsigned char *  next;
243-
244-	  list = new_abbrev_list (abbrev_base,
245-				  compunit.cu_abbrev_offset);
246-	  next = process_abbrev_set (&debug_displays[abbrev_sec].section,
247-				     abbrev_base, abbrev_size,
248-				     compunit.cu_abbrev_offset, list);
249-	  list->start_of_next_abbrevs = next;
250-	}
251-
252+      abbrev_list *list;
253+      abbrev_list *free_list;
254+      list = find_and_process_abbrev_set (&debug_displays[abbrev_sec].section,
255+					  abbrev_base, abbrev_size,
256+					  compunit.cu_abbrev_offset,
257+					  &free_list);
258       start = end_cu;
259-      record_abbrev_list_for_cu (cu_offset, start - section_begin, list);
260+      if (list != NULL && list->first_abbrev != NULL)
261+	record_abbrev_list_for_cu (cu_offset, start - section_begin,
262+				   list, free_list);
263+      else if (free_list != NULL)
264+	free_abbrev_list (free_list);
265     }
266
267   for (start = section_begin, unit = 0; start < end; unit++)
268@@ -3757,7 +3785,6 @@ process_debug_info (struct dwarf_section
269       struct cu_tu_set *this_set;
270       dwarf_vma abbrev_base;
271       size_t abbrev_size;
272-      abbrev_list * list = NULL;
273       unsigned char *end_cu;
274
275       hdrptr = start;
276@@ -3936,20 +3963,10 @@ process_debug_info (struct dwarf_section
277 	}
278
279       /* Process the abbrevs used by this compilation unit.  */
280-      list = find_abbrev_list_by_abbrev_offset (abbrev_base,
281-						compunit.cu_abbrev_offset);
282-      if (list == NULL)
283-	{
284-	  unsigned char *next;
285-
286-	  list = new_abbrev_list (abbrev_base,
287-				  compunit.cu_abbrev_offset);
288-	  next = process_abbrev_set (&debug_displays[abbrev_sec].section,
289-				     abbrev_base, abbrev_size,
290-				     compunit.cu_abbrev_offset, list);
291-	  list->start_of_next_abbrevs = next;
292-	}
293-
294+      abbrev_list *list;
295+      list = find_and_process_abbrev_set (&debug_displays[abbrev_sec].section,
296+					  abbrev_base, abbrev_size,
297+					  compunit.cu_abbrev_offset, NULL);
298       level = 0;
299       last_level = level;
300       saved_level = -1;
301@@ -4128,6 +4145,8 @@ process_debug_info (struct dwarf_section
302 	  if (entry->children)
303 	    ++level;
304 	}
305+      if (list != NULL)
306+	free_abbrev_list (list);
307     }
308
309   /* Set num_debug_info_entries here so that it can be used to check if
310@@ -6353,24 +6372,15 @@ display_debug_abbrev (struct dwarf_secti
311
312   do
313     {
314-      abbrev_list *    list;
315-      dwarf_vma        offset;
316-
317-      offset = start - section->start;
318-      list = find_abbrev_list_by_abbrev_offset (0, offset);
319+      dwarf_vma offset = start - section->start;
320+      abbrev_list *list = find_and_process_abbrev_set (section, 0,
321+						       section->size, offset,
322+						       NULL);
323       if (list == NULL)
324-	{
325-	  list = new_abbrev_list (0, offset);
326-	  start = process_abbrev_set (section, 0, section->size, offset, list);
327-	  list->start_of_next_abbrevs = start;
328-	}
329-      else
330-	start = list->start_of_next_abbrevs;
331-
332-      if (list->first_abbrev == NULL)
333-	continue;
334+	break;
335
336-      printf (_("  Number TAG (0x%lx)\n"), (long) offset);
337+      if (list->first_abbrev)
338+	printf (_("  Number TAG (0x%lx)\n"), (long) offset);
339
340       for (entry = list->first_abbrev; entry; entry = entry->next)
341 	{
342@@ -6391,6 +6401,8 @@ display_debug_abbrev (struct dwarf_secti
343 	      putchar ('\n');
344 	    }
345 	}
346+      start = list->start_of_next_abbrevs;
347+      free_abbrev_list (list);
348     }
349   while (start);
350
351