0014-CVE-2022-38128-1.patch 11 KB

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