diff options
4 files changed, 751 insertions, 0 deletions
diff --git a/meta/recipes-devtools/binutils/binutils-2.38.inc b/meta/recipes-devtools/binutils/binutils-2.38.inc index 0a4a0d7bc1..30a34d7ba4 100644 --- a/meta/recipes-devtools/binutils/binutils-2.38.inc +++ b/meta/recipes-devtools/binutils/binutils-2.38.inc | |||
| @@ -43,5 +43,8 @@ SRC_URI = "\ | |||
| 43 | file://0018-CVE-2022-38128-2.patch \ | 43 | file://0018-CVE-2022-38128-2.patch \ |
| 44 | file://0018-CVE-2022-38128-3.patch \ | 44 | file://0018-CVE-2022-38128-3.patch \ |
| 45 | file://0019-CVE-2022-4285.patch \ | 45 | file://0019-CVE-2022-4285.patch \ |
| 46 | file://0020-CVE-2023-22608-1.patch \ | ||
| 47 | file://0020-CVE-2023-22608-2.patch \ | ||
| 48 | file://0020-CVE-2023-22608-3.patch \ | ||
| 46 | " | 49 | " |
| 47 | S = "${WORKDIR}/git" | 50 | S = "${WORKDIR}/git" |
diff --git a/meta/recipes-devtools/binutils/binutils/0020-CVE-2023-22608-1.patch b/meta/recipes-devtools/binutils/binutils/0020-CVE-2023-22608-1.patch new file mode 100644 index 0000000000..18d4ac5f9d --- /dev/null +++ b/meta/recipes-devtools/binutils/binutils/0020-CVE-2023-22608-1.patch | |||
| @@ -0,0 +1,506 @@ | |||
| 1 | From 116aac1447ee92df25599859293752648e3c6ea0 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: "Steinar H. Gunderson" <sesse@google.com> | ||
| 3 | Date: Fri, 20 May 2022 16:10:34 +0200 | ||
| 4 | Subject: [PATCH] add a trie to map quickly from address range to compilation | ||
| 5 | MIME-Version: 1.0 | ||
| 6 | Content-Type: text/plain; charset=UTF-8 | ||
| 7 | Content-Transfer-Encoding: 8bit | ||
| 8 | |||
| 9 | unit | ||
| 10 | MIME-Version: 1.0 | ||
| 11 | Content-Type: text/plain; charset=UTF-8 | ||
| 12 | Content-Transfer-Encoding: 8bit | ||
| 13 | |||
| 14 | When using perf to profile large binaries, _bfd_dwarf2_find_nearest_line() | ||
| 15 | becomes a hotspot, as perf wants to get line number information | ||
| 16 | (for inline-detection purposes) for each and every sample. In Chromium | ||
| 17 | in particular (the content_shell binary), this entails going through | ||
| 18 | 475k address ranges, which takes a long time when done repeatedly. | ||
| 19 | |||
| 20 | Add a radix-256 trie over the address space to quickly map address to | ||
| 21 | compilation unit spaces; for content_shell, which is 1.6 GB when some | ||
| 22 | (but not full) debug information turned is on, we go from 6 ms to | ||
| 23 | 0.006 ms (6 µs) for each lookup from address to compilation unit, a 1000x | ||
| 24 | speedup. | ||
| 25 | |||
| 26 | There is a modest RAM increase of 180 MB in this binary (the existing | ||
| 27 | linked list over ranges uses about 10 MB, and the entire perf job uses | ||
| 28 | between 2-3 GB for a medium-size profile); for smaller binaries with few | ||
| 29 | ranges, there should be hardly any extra RAM usage at all. | ||
| 30 | |||
| 31 | Upstream-Status: Backport [https://sourceware.org/git/?p=binutils-gdb.git;a=commitdiff;h=b43771b045fb5616da3964f2994eefbe8ae70d32] | ||
| 32 | |||
| 33 | CVE: CVE-2023-22608 | ||
| 34 | |||
| 35 | Signed-off-by: Yash Shinde <Yash.Shinde@windriver.com> | ||
| 36 | |||
| 37 | --- | ||
| 38 | bfd/dwarf2.c | 326 ++++++++++++++++++++++++++++++++++++++++++++++++--- | ||
| 39 | 1 file changed, 312 insertions(+), 14 deletions(-) | ||
| 40 | |||
| 41 | diff --git a/bfd/dwarf2.c b/bfd/dwarf2.c | ||
| 42 | index fdf071c3..0ae50a37 100644 | ||
| 43 | --- a/bfd/dwarf2.c | ||
| 44 | +++ b/bfd/dwarf2.c | ||
| 45 | @@ -82,6 +82,77 @@ struct adjusted_section | ||
| 46 | bfd_vma adj_vma; | ||
| 47 | }; | ||
| 48 | |||
| 49 | +/* A trie to map quickly from address range to compilation unit. | ||
| 50 | + | ||
| 51 | + This is a fairly standard radix-256 trie, used to quickly locate which | ||
| 52 | + compilation unit any given address belongs to. Given that each compilation | ||
| 53 | + unit may register hundreds of very small and unaligned ranges (which may | ||
| 54 | + potentially overlap, due to inlining and other concerns), and a large | ||
| 55 | + program may end up containing hundreds of thousands of such ranges, we cannot | ||
| 56 | + scan through them linearly without undue slowdown. | ||
| 57 | + | ||
| 58 | + We use a hybrid trie to avoid memory explosion: There are two types of trie | ||
| 59 | + nodes, leaves and interior nodes. (Almost all nodes are leaves, so they | ||
| 60 | + take up the bulk of the memory usage.) Leaves contain a simple array of | ||
| 61 | + ranges (high/low address) and which compilation unit contains those ranges, | ||
| 62 | + and when we get to a leaf, we scan through it linearly. Interior nodes | ||
| 63 | + contain pointers to 256 other nodes, keyed by the next byte of the address. | ||
| 64 | + So for a 64-bit address like 0x1234567abcd, we would start at the root and go | ||
| 65 | + down child[0x00]->child[0x00]->child[0x01]->child[0x23]->child[0x45] etc., | ||
| 66 | + until we hit a leaf. (Nodes are, in general, leaves until they exceed the | ||
| 67 | + default allocation of 16 elements, at which point they are converted to | ||
| 68 | + interior node if possible.) This gives us near-constant lookup times; | ||
| 69 | + the only thing that can be costly is if there are lots of overlapping ranges | ||
| 70 | + within a single 256-byte segment of the binary, in which case we have to | ||
| 71 | + scan through them all to find the best match. | ||
| 72 | + | ||
| 73 | + For a binary with few ranges, we will in practice only have a single leaf | ||
| 74 | + node at the root, containing a simple array. Thus, the scheme is efficient | ||
| 75 | + for both small and large binaries. | ||
| 76 | + */ | ||
| 77 | + | ||
| 78 | +/* Experiments have shown 16 to be a memory-efficient default leaf size. | ||
| 79 | + The only case where a leaf will hold more memory than this, is at the | ||
| 80 | + bottomost level (covering 256 bytes in the binary), where we'll expand | ||
| 81 | + the leaf to be able to hold more ranges if needed. | ||
| 82 | + */ | ||
| 83 | +#define TRIE_LEAF_SIZE 16 | ||
| 84 | + | ||
| 85 | +/* All trie_node pointers will really be trie_leaf or trie_interior, | ||
| 86 | + but they have this common head. */ | ||
| 87 | +struct trie_node | ||
| 88 | +{ | ||
| 89 | + /* If zero, we are an interior node. | ||
| 90 | + Otherwise, how many ranges we have room for in this leaf. */ | ||
| 91 | + unsigned int num_room_in_leaf; | ||
| 92 | +}; | ||
| 93 | + | ||
| 94 | +struct trie_leaf | ||
| 95 | +{ | ||
| 96 | + struct trie_node head; | ||
| 97 | + unsigned int num_stored_in_leaf; | ||
| 98 | + struct { | ||
| 99 | + struct comp_unit *unit; | ||
| 100 | + bfd_vma low_pc, high_pc; | ||
| 101 | + } ranges[TRIE_LEAF_SIZE]; | ||
| 102 | +}; | ||
| 103 | + | ||
| 104 | +struct trie_interior | ||
| 105 | +{ | ||
| 106 | + struct trie_node head; | ||
| 107 | + struct trie_node *children[256]; | ||
| 108 | +}; | ||
| 109 | + | ||
| 110 | +static struct trie_node *alloc_trie_leaf (bfd *abfd) | ||
| 111 | +{ | ||
| 112 | + struct trie_leaf *leaf = | ||
| 113 | + bfd_zalloc (abfd, sizeof (struct trie_leaf)); | ||
| 114 | + if (leaf == NULL) | ||
| 115 | + return NULL; | ||
| 116 | + leaf->head.num_room_in_leaf = TRIE_LEAF_SIZE; | ||
| 117 | + return &leaf->head; | ||
| 118 | +} | ||
| 119 | + | ||
| 120 | struct dwarf2_debug_file | ||
| 121 | { | ||
| 122 | /* The actual bfd from which debug info was loaded. Might be | ||
| 123 | @@ -139,6 +210,9 @@ struct dwarf2_debug_file | ||
| 124 | /* A list of all previously read comp_units. */ | ||
| 125 | struct comp_unit *all_comp_units; | ||
| 126 | |||
| 127 | + /* A list of all previously read comp_units with no ranges (yet). */ | ||
| 128 | + struct comp_unit *all_comp_units_without_ranges; | ||
| 129 | + | ||
| 130 | /* Last comp unit in list above. */ | ||
| 131 | struct comp_unit *last_comp_unit; | ||
| 132 | |||
| 133 | @@ -147,6 +221,9 @@ struct dwarf2_debug_file | ||
| 134 | |||
| 135 | /* Hash table to map offsets to decoded abbrevs. */ | ||
| 136 | htab_t abbrev_offsets; | ||
| 137 | + | ||
| 138 | + /* Root of a trie to map addresses to compilation units. */ | ||
| 139 | + struct trie_node *trie_root; | ||
| 140 | }; | ||
| 141 | |||
| 142 | struct dwarf2_debug | ||
| 143 | @@ -220,6 +297,11 @@ struct comp_unit | ||
| 144 | /* Chain the previously read compilation units. */ | ||
| 145 | struct comp_unit *next_unit; | ||
| 146 | |||
| 147 | + /* Chain the previously read compilation units that have no ranges yet. | ||
| 148 | + We scan these separately when we have a trie over the ranges. | ||
| 149 | + Unused if arange.high != 0. */ | ||
| 150 | + struct comp_unit *next_unit_without_ranges; | ||
| 151 | + | ||
| 152 | /* Likewise, chain the compilation unit read after this one. | ||
| 153 | The comp units are stored in reversed reading order. */ | ||
| 154 | struct comp_unit *prev_unit; | ||
| 155 | @@ -296,6 +378,10 @@ struct comp_unit | ||
| 156 | |||
| 157 | /* TRUE if symbols are cached in hash table for faster lookup by name. */ | ||
| 158 | bool cached; | ||
| 159 | + | ||
| 160 | + /* Used when iterating over trie leaves to know which units we have | ||
| 161 | + already seen in this iteration. */ | ||
| 162 | + bool mark; | ||
| 163 | }; | ||
| 164 | |||
| 165 | /* This data structure holds the information of an abbrev. */ | ||
| 166 | @@ -1766,9 +1852,189 @@ concat_filename (struct line_info_table *table, unsigned int file) | ||
| 167 | return strdup (filename); | ||
| 168 | } | ||
| 169 | |||
| 170 | +/* Number of bits in a bfd_vma. */ | ||
| 171 | +#define VMA_BITS (8 * sizeof (bfd_vma)) | ||
| 172 | + | ||
| 173 | +/* Check whether [low1, high1) can be combined with [low2, high2), | ||
| 174 | + i.e., they touch or overlap. */ | ||
| 175 | +static bool ranges_overlap (bfd_vma low1, | ||
| 176 | + bfd_vma high1, | ||
| 177 | + bfd_vma low2, | ||
| 178 | + bfd_vma high2) | ||
| 179 | +{ | ||
| 180 | + if (low1 == low2 || high1 == high2) | ||
| 181 | + return true; | ||
| 182 | + | ||
| 183 | + /* Sort so that low1 is below low2. */ | ||
| 184 | + if (low1 > low2) | ||
| 185 | + { | ||
| 186 | + bfd_vma tmp; | ||
| 187 | + | ||
| 188 | + tmp = low1; | ||
| 189 | + low1 = low2; | ||
| 190 | + low2 = tmp; | ||
| 191 | + | ||
| 192 | + tmp = high1; | ||
| 193 | + high1 = high2; | ||
| 194 | + high2 = tmp; | ||
| 195 | + } | ||
| 196 | + | ||
| 197 | + /* We touch iff low2 == high1. | ||
| 198 | + We overlap iff low2 is within [low1, high1). */ | ||
| 199 | + return (low2 <= high1); | ||
| 200 | +} | ||
| 201 | + | ||
| 202 | +/* Insert an address range in the trie mapping addresses to compilation units. | ||
| 203 | + Will return the new trie node (usually the same as is being sent in, but | ||
| 204 | + in case of a leaf-to-interior conversion, or expansion of a leaf, it may be | ||
| 205 | + different), or NULL on failure. | ||
| 206 | + */ | ||
| 207 | +static struct trie_node *insert_arange_in_trie(bfd *abfd, | ||
| 208 | + struct trie_node *trie, | ||
| 209 | + bfd_vma trie_pc, | ||
| 210 | + unsigned int trie_pc_bits, | ||
| 211 | + struct comp_unit *unit, | ||
| 212 | + bfd_vma low_pc, | ||
| 213 | + bfd_vma high_pc) | ||
| 214 | +{ | ||
| 215 | + bfd_vma clamped_low_pc, clamped_high_pc; | ||
| 216 | + int ch, from_ch, to_ch; | ||
| 217 | + bool is_full_leaf = false; | ||
| 218 | + | ||
| 219 | + /* See if we can extend any of the existing ranges. This merging | ||
| 220 | + isn't perfect (if merging opens up the possibility of merging two existing | ||
| 221 | + ranges, we won't find them), but it takes the majority of the cases. */ | ||
| 222 | + if (trie->num_room_in_leaf > 0) | ||
| 223 | + { | ||
| 224 | + struct trie_leaf *leaf = (struct trie_leaf *) trie; | ||
| 225 | + unsigned int i; | ||
| 226 | + | ||
| 227 | + for (i = 0; i < leaf->num_stored_in_leaf; ++i) | ||
| 228 | + { | ||
| 229 | + if (leaf->ranges[i].unit == unit && | ||
| 230 | + ranges_overlap(low_pc, high_pc, | ||
| 231 | + leaf->ranges[i].low_pc, leaf->ranges[i].high_pc)) | ||
| 232 | + { | ||
| 233 | + if (low_pc < leaf->ranges[i].low_pc) | ||
| 234 | + leaf->ranges[i].low_pc = low_pc; | ||
| 235 | + if (high_pc > leaf->ranges[i].high_pc) | ||
| 236 | + leaf->ranges[i].high_pc = high_pc; | ||
| 237 | + return trie; | ||
| 238 | + } | ||
| 239 | + } | ||
| 240 | + | ||
| 241 | + is_full_leaf = leaf->num_stored_in_leaf == trie->num_room_in_leaf; | ||
| 242 | + } | ||
| 243 | + | ||
| 244 | + /* If we're a leaf with no more room and we're _not_ at the bottom, | ||
| 245 | + convert to an interior node. */ | ||
| 246 | + if (is_full_leaf && trie_pc_bits < VMA_BITS) | ||
| 247 | + { | ||
| 248 | + const struct trie_leaf *leaf = (struct trie_leaf *) trie; | ||
| 249 | + unsigned int i; | ||
| 250 | + | ||
| 251 | + trie = bfd_zalloc (abfd, sizeof (struct trie_interior)); | ||
| 252 | + if (!trie) | ||
| 253 | + return NULL; | ||
| 254 | + is_full_leaf = false; | ||
| 255 | + | ||
| 256 | + /* TODO: If we wanted to save a little more memory at the cost of | ||
| 257 | + complexity, we could have reused the old leaf node as one of the | ||
| 258 | + children of the new interior node, instead of throwing it away. */ | ||
| 259 | + for (i = 0; i < leaf->num_stored_in_leaf; ++i) | ||
| 260 | + { | ||
| 261 | + if (!insert_arange_in_trie (abfd, trie, trie_pc, trie_pc_bits, | ||
| 262 | + leaf->ranges[i].unit, leaf->ranges[i].low_pc, | ||
| 263 | + leaf->ranges[i].high_pc)) | ||
| 264 | + return NULL; | ||
| 265 | + } | ||
| 266 | + } | ||
| 267 | + | ||
| 268 | + /* If we're a leaf with no more room and we _are_ at the bottom, | ||
| 269 | + we have no choice but to just make it larger. */ | ||
| 270 | + if (is_full_leaf) | ||
| 271 | + { | ||
| 272 | + const struct trie_leaf *leaf = (struct trie_leaf *) trie; | ||
| 273 | + unsigned int new_room_in_leaf = trie->num_room_in_leaf * 2; | ||
| 274 | + struct trie_leaf *new_leaf; | ||
| 275 | + | ||
| 276 | + new_leaf = bfd_zalloc (abfd, | ||
| 277 | + sizeof (struct trie_leaf) + | ||
| 278 | + (new_room_in_leaf - TRIE_LEAF_SIZE) * sizeof (leaf->ranges[0])); | ||
| 279 | + new_leaf->head.num_room_in_leaf = new_room_in_leaf; | ||
| 280 | + new_leaf->num_stored_in_leaf = leaf->num_stored_in_leaf; | ||
| 281 | + | ||
| 282 | + memcpy (new_leaf->ranges, | ||
| 283 | + leaf->ranges, | ||
| 284 | + leaf->num_stored_in_leaf * sizeof (leaf->ranges[0])); | ||
| 285 | + trie = &new_leaf->head; | ||
| 286 | + is_full_leaf = false; | ||
| 287 | + | ||
| 288 | + /* Now the insert below will go through. */ | ||
| 289 | + } | ||
| 290 | + | ||
| 291 | + /* If we're a leaf (now with room), we can just insert at the end. */ | ||
| 292 | + if (trie->num_room_in_leaf > 0) | ||
| 293 | + { | ||
| 294 | + struct trie_leaf *leaf = (struct trie_leaf *) trie; | ||
| 295 | + | ||
| 296 | + unsigned int i = leaf->num_stored_in_leaf++; | ||
| 297 | + leaf->ranges[i].unit = unit; | ||
| 298 | + leaf->ranges[i].low_pc = low_pc; | ||
| 299 | + leaf->ranges[i].high_pc = high_pc; | ||
| 300 | + return trie; | ||
| 301 | + } | ||
| 302 | + | ||
| 303 | + /* Now we are definitely an interior node, so recurse into all | ||
| 304 | + the relevant buckets. */ | ||
| 305 | + | ||
| 306 | + /* Clamp the range to the current trie bucket. */ | ||
| 307 | + clamped_low_pc = low_pc; | ||
| 308 | + clamped_high_pc = high_pc; | ||
| 309 | + if (trie_pc_bits > 0) | ||
| 310 | + { | ||
| 311 | + bfd_vma bucket_high_pc = | ||
| 312 | + trie_pc + ((bfd_vma)-1 >> trie_pc_bits); /* Inclusive. */ | ||
| 313 | + if (clamped_low_pc < trie_pc) | ||
| 314 | + clamped_low_pc = trie_pc; | ||
| 315 | + if (clamped_high_pc > bucket_high_pc) | ||
| 316 | + clamped_high_pc = bucket_high_pc; | ||
| 317 | + } | ||
| 318 | + | ||
| 319 | + /* Insert the ranges in all buckets that it spans. */ | ||
| 320 | + from_ch = (clamped_low_pc >> (VMA_BITS - trie_pc_bits - 8)) & 0xff; | ||
| 321 | + to_ch = ((clamped_high_pc - 1) >> (VMA_BITS - trie_pc_bits - 8)) & 0xff; | ||
| 322 | + for (ch = from_ch; ch <= to_ch; ++ch) | ||
| 323 | + { | ||
| 324 | + struct trie_interior *interior = (struct trie_interior *) trie; | ||
| 325 | + struct trie_node *child = interior->children[ch]; | ||
| 326 | + | ||
| 327 | + if (child == NULL) | ||
| 328 | + { | ||
| 329 | + child = alloc_trie_leaf (abfd); | ||
| 330 | + if (!child) | ||
| 331 | + return NULL; | ||
| 332 | + } | ||
| 333 | + child = insert_arange_in_trie (abfd, | ||
| 334 | + child, | ||
| 335 | + trie_pc + ((bfd_vma)ch << (VMA_BITS - trie_pc_bits - 8)), | ||
| 336 | + trie_pc_bits + 8, | ||
| 337 | + unit, | ||
| 338 | + low_pc, | ||
| 339 | + high_pc); | ||
| 340 | + if (!child) | ||
| 341 | + return NULL; | ||
| 342 | + | ||
| 343 | + interior->children[ch] = child; | ||
| 344 | + } | ||
| 345 | + | ||
| 346 | + return trie; | ||
| 347 | +} | ||
| 348 | + | ||
| 349 | + | ||
| 350 | static bool | ||
| 351 | -arange_add (const struct comp_unit *unit, struct arange *first_arange, | ||
| 352 | - bfd_vma low_pc, bfd_vma high_pc) | ||
| 353 | +arange_add (struct comp_unit *unit, struct arange *first_arange, | ||
| 354 | + struct trie_node **trie_root, bfd_vma low_pc, bfd_vma high_pc) | ||
| 355 | { | ||
| 356 | struct arange *arange; | ||
| 357 | |||
| 358 | @@ -1776,6 +2042,19 @@ arange_add (const struct comp_unit *unit, struct arange *first_arange, | ||
| 359 | if (low_pc == high_pc) | ||
| 360 | return true; | ||
| 361 | |||
| 362 | + if (trie_root != NULL) | ||
| 363 | + { | ||
| 364 | + *trie_root = insert_arange_in_trie (unit->file->bfd_ptr, | ||
| 365 | + *trie_root, | ||
| 366 | + 0, | ||
| 367 | + 0, | ||
| 368 | + unit, | ||
| 369 | + low_pc, | ||
| 370 | + high_pc); | ||
| 371 | + if (*trie_root == NULL) | ||
| 372 | + return false; | ||
| 373 | + } | ||
| 374 | + | ||
| 375 | /* If the first arange is empty, use it. */ | ||
| 376 | if (first_arange->high == 0) | ||
| 377 | { | ||
| 378 | @@ -2410,7 +2689,8 @@ decode_line_info (struct comp_unit *unit) | ||
| 379 | low_pc = address; | ||
| 380 | if (address > high_pc) | ||
| 381 | high_pc = address; | ||
| 382 | - if (!arange_add (unit, &unit->arange, low_pc, high_pc)) | ||
| 383 | + if (!arange_add (unit, &unit->arange, &unit->file->trie_root, | ||
| 384 | + low_pc, high_pc)) | ||
| 385 | goto line_fail; | ||
| 386 | break; | ||
| 387 | case DW_LNE_set_address: | ||
| 388 | @@ -3134,7 +3414,7 @@ find_abstract_instance (struct comp_unit *unit, | ||
| 389 | |||
| 390 | static bool | ||
| 391 | read_ranges (struct comp_unit *unit, struct arange *arange, | ||
| 392 | - bfd_uint64_t offset) | ||
| 393 | + struct trie_node **trie_root, bfd_uint64_t offset) | ||
| 394 | { | ||
| 395 | bfd_byte *ranges_ptr; | ||
| 396 | bfd_byte *ranges_end; | ||
| 397 | @@ -3169,7 +3449,7 @@ read_ranges (struct comp_unit *unit, struct arange *arange, | ||
| 398 | base_address = high_pc; | ||
| 399 | else | ||
| 400 | { | ||
| 401 | - if (!arange_add (unit, arange, | ||
| 402 | + if (!arange_add (unit, arange, trie_root, | ||
| 403 | base_address + low_pc, base_address + high_pc)) | ||
| 404 | return false; | ||
| 405 | } | ||
| 406 | @@ -3179,7 +3459,7 @@ read_ranges (struct comp_unit *unit, struct arange *arange, | ||
| 407 | |||
| 408 | static bool | ||
| 409 | read_rnglists (struct comp_unit *unit, struct arange *arange, | ||
| 410 | - bfd_uint64_t offset) | ||
| 411 | + struct trie_node **trie_root, bfd_uint64_t offset) | ||
| 412 | { | ||
| 413 | bfd_byte *rngs_ptr; | ||
| 414 | bfd_byte *rngs_end; | ||
| 415 | @@ -3253,19 +3533,19 @@ read_rnglists (struct comp_unit *unit, struct arange *arange, | ||
| 416 | return false; | ||
| 417 | } | ||
| 418 | |||
| 419 | - if (!arange_add (unit, arange, low_pc, high_pc)) | ||
| 420 | + if (!arange_add (unit, arange, trie_root, low_pc, high_pc)) | ||
| 421 | return false; | ||
| 422 | } | ||
| 423 | } | ||
| 424 | |||
| 425 | static bool | ||
| 426 | read_rangelist (struct comp_unit *unit, struct arange *arange, | ||
| 427 | - bfd_uint64_t offset) | ||
| 428 | + struct trie_node **trie_root, bfd_uint64_t offset) | ||
| 429 | { | ||
| 430 | if (unit->version <= 4) | ||
| 431 | - return read_ranges (unit, arange, offset); | ||
| 432 | + return read_ranges (unit, arange, trie_root, offset); | ||
| 433 | else | ||
| 434 | - return read_rnglists (unit, arange, offset); | ||
| 435 | + return read_rnglists (unit, arange, trie_root, offset); | ||
| 436 | } | ||
| 437 | |||
| 438 | static struct funcinfo * | ||
| 439 | @@ -3563,7 +3843,8 @@ scan_unit_for_symbols (struct comp_unit *unit) | ||
| 440 | |||
| 441 | case DW_AT_ranges: | ||
| 442 | if (is_int_form (&attr) | ||
| 443 | - && !read_rangelist (unit, &func->arange, attr.u.val)) | ||
| 444 | + && !read_rangelist (unit, &func->arange, | ||
| 445 | + &unit->file->trie_root, attr.u.val)) | ||
| 446 | goto fail; | ||
| 447 | break; | ||
| 448 | |||
| 449 | @@ -3679,7 +3960,8 @@ scan_unit_for_symbols (struct comp_unit *unit) | ||
| 450 | |||
| 451 | if (func && high_pc != 0) | ||
| 452 | { | ||
| 453 | - if (!arange_add (unit, &func->arange, low_pc, high_pc)) | ||
| 454 | + if (!arange_add (unit, &func->arange, &unit->file->trie_root, | ||
| 455 | + low_pc, high_pc)) | ||
| 456 | goto fail; | ||
| 457 | } | ||
| 458 | } | ||
| 459 | @@ -3874,7 +4156,8 @@ parse_comp_unit (struct dwarf2_debug *stash, | ||
| 460 | |||
| 461 | case DW_AT_ranges: | ||
| 462 | if (is_int_form (&attr) | ||
| 463 | - && !read_rangelist (unit, &unit->arange, attr.u.val)) | ||
| 464 | + && !read_rangelist (unit, &unit->arange, | ||
| 465 | + &unit->file->trie_root, attr.u.val)) | ||
| 466 | return NULL; | ||
| 467 | break; | ||
| 468 | |||
| 469 | @@ -3916,7 +4199,8 @@ parse_comp_unit (struct dwarf2_debug *stash, | ||
| 470 | high_pc += low_pc; | ||
| 471 | if (high_pc != 0) | ||
| 472 | { | ||
| 473 | - if (!arange_add (unit, &unit->arange, low_pc, high_pc)) | ||
| 474 | + if (!arange_add (unit, &unit->arange, &unit->file->trie_root, | ||
| 475 | + low_pc, high_pc)) | ||
| 476 | return NULL; | ||
| 477 | } | ||
| 478 | |||
| 479 | @@ -4747,6 +5031,14 @@ _bfd_dwarf2_slurp_debug_info (bfd *abfd, bfd *debug_bfd, | ||
| 480 | if (!stash->alt.abbrev_offsets) | ||
| 481 | return false; | ||
| 482 | |||
| 483 | + stash->f.trie_root = alloc_trie_leaf (abfd); | ||
| 484 | + if (!stash->f.trie_root) | ||
| 485 | + return false; | ||
| 486 | + | ||
| 487 | + stash->alt.trie_root = alloc_trie_leaf (abfd); | ||
| 488 | + if (!stash->alt.trie_root) | ||
| 489 | + return false; | ||
| 490 | + | ||
| 491 | *pinfo = stash; | ||
| 492 | |||
| 493 | if (debug_bfd == NULL) | ||
| 494 | @@ -4918,6 +5210,12 @@ stash_comp_unit (struct dwarf2_debug *stash, struct dwarf2_debug_file *file) | ||
| 495 | each->next_unit = file->all_comp_units; | ||
| 496 | file->all_comp_units = each; | ||
| 497 | |||
| 498 | + if (each->arange.high == 0) | ||
| 499 | + { | ||
| 500 | + each->next_unit_without_ranges = file->all_comp_units_without_ranges; | ||
| 501 | + file->all_comp_units_without_ranges = each->next_unit_without_ranges; | ||
| 502 | + } | ||
| 503 | + | ||
| 504 | file->info_ptr += length; | ||
| 505 | return each; | ||
| 506 | } | ||
diff --git a/meta/recipes-devtools/binutils/binutils/0020-CVE-2023-22608-2.patch b/meta/recipes-devtools/binutils/binutils/0020-CVE-2023-22608-2.patch new file mode 100644 index 0000000000..a58b8dccdc --- /dev/null +++ b/meta/recipes-devtools/binutils/binutils/0020-CVE-2023-22608-2.patch | |||
| @@ -0,0 +1,210 @@ | |||
| 1 | From 1e716c1b160d56c2ab8711e199cad5b4db47cedf Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Nick Clifton <nickc@redhat.com> | ||
| 3 | Date: Tue, 30 Aug 2022 16:01:20 +0100 | ||
| 4 | Subject: [PATCH] BFD library: Use entry 0 in directory and filename tables of | ||
| 5 | |||
| 6 | DWARF-5 debug info. | ||
| 7 | |||
| 8 | PR 29529 | ||
| 9 | * dwarf2.c (struct line_info_table): Add new field: | ||
| 10 | use_dir_and_file_0. | ||
| 11 | (concat_filename): Use new field to help select the correct table | ||
| 12 | slot. | ||
| 13 | (read_formatted_entries): Do not skip entry 0. | ||
| 14 | (decode_line_info): Set new field depending upon the version of | ||
| 15 | DWARF being parsed. Initialise filename based upon the setting of | ||
| 16 | the new field. | ||
| 17 | |||
| 18 | Upstream-Status: Backport [https://sourceware.org/git/?p=binutils-gdb.git;a=commitdiff;h=37833b966576c5d25e797ea3b6c33d0459a71892] | ||
| 19 | CVE: CVE-2023-22608 | ||
| 20 | |||
| 21 | Signed-off-by: Yash Shinde <Yash.Shinde@windriver.com> | ||
| 22 | |||
| 23 | --- | ||
| 24 | bfd/dwarf2.c | 86 ++++++++++++++++++++---------- | ||
| 25 | ld/testsuite/ld-x86-64/pr27587.err | 2 +- | ||
| 26 | 2 files changed, 59 insertions(+), 29 deletions(-) | ||
| 27 | |||
| 28 | diff --git a/bfd/dwarf2.c b/bfd/dwarf2.c | ||
| 29 | index 0ae50a37..b7839ad6 100644 | ||
| 30 | --- a/bfd/dwarf2.c | ||
| 31 | +++ b/bfd/dwarf2.c | ||
| 32 | @@ -1571,6 +1571,7 @@ struct line_info_table | ||
| 33 | unsigned int num_files; | ||
| 34 | unsigned int num_dirs; | ||
| 35 | unsigned int num_sequences; | ||
| 36 | + bool use_dir_and_file_0; | ||
| 37 | char * comp_dir; | ||
| 38 | char ** dirs; | ||
| 39 | struct fileinfo* files; | ||
| 40 | @@ -1791,16 +1792,30 @@ concat_filename (struct line_info_table *table, unsigned int file) | ||
| 41 | { | ||
| 42 | char *filename; | ||
| 43 | |||
| 44 | - if (table == NULL || file - 1 >= table->num_files) | ||
| 45 | + /* Pre DWARF-5 entry 0 in the directory and filename tables was not used. | ||
| 46 | + So in order to save space in the tables used here the info for, eg | ||
| 47 | + directory 1 is stored in slot 0 of the directory table, directory 2 | ||
| 48 | + in slot 1 and so on. | ||
| 49 | + | ||
| 50 | + Starting with DWARF-5 the 0'th entry is used so there is a one to one | ||
| 51 | + mapping between DWARF slots and internal table entries. */ | ||
| 52 | + if (! table->use_dir_and_file_0) | ||
| 53 | { | ||
| 54 | - /* FILE == 0 means unknown. */ | ||
| 55 | - if (file) | ||
| 56 | - _bfd_error_handler | ||
| 57 | - (_("DWARF error: mangled line number section (bad file number)")); | ||
| 58 | + /* Pre DWARF-5, FILE == 0 means unknown. */ | ||
| 59 | + if (file == 0) | ||
| 60 | + return strdup ("<unknown>"); | ||
| 61 | + -- file; | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | + if (table == NULL || file >= table->num_files) | ||
| 65 | + { | ||
| 66 | + _bfd_error_handler | ||
| 67 | + (_("DWARF error: mangled line number section (bad file number)")); | ||
| 68 | return strdup ("<unknown>"); | ||
| 69 | } | ||
| 70 | |||
| 71 | - filename = table->files[file - 1].name; | ||
| 72 | + filename = table->files[file].name; | ||
| 73 | + | ||
| 74 | if (filename == NULL) | ||
| 75 | return strdup ("<unknown>"); | ||
| 76 | |||
| 77 | @@ -1811,12 +1826,17 @@ concat_filename (struct line_info_table *table, unsigned int file) | ||
| 78 | char *name; | ||
| 79 | size_t len; | ||
| 80 | |||
| 81 | - if (table->files[file - 1].dir | ||
| 82 | + if (table->files[file].dir | ||
| 83 | /* PR 17512: file: 0317e960. */ | ||
| 84 | - && table->files[file - 1].dir <= table->num_dirs | ||
| 85 | + && table->files[file].dir <= table->num_dirs | ||
| 86 | /* PR 17512: file: 7f3d2e4b. */ | ||
| 87 | && table->dirs != NULL) | ||
| 88 | - subdir_name = table->dirs[table->files[file - 1].dir - 1]; | ||
| 89 | + { | ||
| 90 | + if (table->use_dir_and_file_0) | ||
| 91 | + subdir_name = table->dirs[table->files[file].dir]; | ||
| 92 | + else | ||
| 93 | + subdir_name = table->dirs[table->files[file].dir - 1]; | ||
| 94 | + } | ||
| 95 | |||
| 96 | if (!subdir_name || !IS_ABSOLUTE_PATH (subdir_name)) | ||
| 97 | dir_name = table->comp_dir; | ||
| 98 | @@ -1857,10 +1877,12 @@ concat_filename (struct line_info_table *table, unsigned int file) | ||
| 99 | |||
| 100 | /* Check whether [low1, high1) can be combined with [low2, high2), | ||
| 101 | i.e., they touch or overlap. */ | ||
| 102 | -static bool ranges_overlap (bfd_vma low1, | ||
| 103 | - bfd_vma high1, | ||
| 104 | - bfd_vma low2, | ||
| 105 | - bfd_vma high2) | ||
| 106 | + | ||
| 107 | +static bool | ||
| 108 | +ranges_overlap (bfd_vma low1, | ||
| 109 | + bfd_vma high1, | ||
| 110 | + bfd_vma low2, | ||
| 111 | + bfd_vma high2) | ||
| 112 | { | ||
| 113 | if (low1 == low2 || high1 == high2) | ||
| 114 | return true; | ||
| 115 | @@ -1887,15 +1909,16 @@ static bool ranges_overlap (bfd_vma low1, | ||
| 116 | /* Insert an address range in the trie mapping addresses to compilation units. | ||
| 117 | Will return the new trie node (usually the same as is being sent in, but | ||
| 118 | in case of a leaf-to-interior conversion, or expansion of a leaf, it may be | ||
| 119 | - different), or NULL on failure. | ||
| 120 | - */ | ||
| 121 | -static struct trie_node *insert_arange_in_trie(bfd *abfd, | ||
| 122 | - struct trie_node *trie, | ||
| 123 | - bfd_vma trie_pc, | ||
| 124 | - unsigned int trie_pc_bits, | ||
| 125 | - struct comp_unit *unit, | ||
| 126 | - bfd_vma low_pc, | ||
| 127 | - bfd_vma high_pc) | ||
| 128 | + different), or NULL on failure. */ | ||
| 129 | + | ||
| 130 | +static struct trie_node * | ||
| 131 | +insert_arange_in_trie (bfd *abfd, | ||
| 132 | + struct trie_node *trie, | ||
| 133 | + bfd_vma trie_pc, | ||
| 134 | + unsigned int trie_pc_bits, | ||
| 135 | + struct comp_unit *unit, | ||
| 136 | + bfd_vma low_pc, | ||
| 137 | + bfd_vma high_pc) | ||
| 138 | { | ||
| 139 | bfd_vma clamped_low_pc, clamped_high_pc; | ||
| 140 | int ch, from_ch, to_ch; | ||
| 141 | @@ -2031,7 +2054,6 @@ static struct trie_node *insert_arange_in_trie(bfd *abfd, | ||
| 142 | return trie; | ||
| 143 | } | ||
| 144 | |||
| 145 | - | ||
| 146 | static bool | ||
| 147 | arange_add (struct comp_unit *unit, struct arange *first_arange, | ||
| 148 | struct trie_node **trie_root, bfd_vma low_pc, bfd_vma high_pc) | ||
| 149 | @@ -2412,10 +2434,8 @@ read_formatted_entries (struct comp_unit *unit, bfd_byte **bufp, | ||
| 150 | } | ||
| 151 | } | ||
| 152 | |||
| 153 | - /* Skip the first "zero entry", which is the compilation dir/file. */ | ||
| 154 | - if (datai != 0) | ||
| 155 | - if (!callback (table, fe.name, fe.dir, fe.time, fe.size)) | ||
| 156 | - return false; | ||
| 157 | + if (!callback (table, fe.name, fe.dir, fe.time, fe.size)) | ||
| 158 | + return false; | ||
| 159 | } | ||
| 160 | |||
| 161 | *bufp = buf; | ||
| 162 | @@ -2592,6 +2612,7 @@ decode_line_info (struct comp_unit *unit) | ||
| 163 | if (!read_formatted_entries (unit, &line_ptr, line_end, table, | ||
| 164 | line_info_add_file_name)) | ||
| 165 | goto fail; | ||
| 166 | + table->use_dir_and_file_0 = true; | ||
| 167 | } | ||
| 168 | else | ||
| 169 | { | ||
| 170 | @@ -2614,6 +2635,7 @@ decode_line_info (struct comp_unit *unit) | ||
| 171 | if (!line_info_add_file_name (table, cur_file, dir, xtime, size)) | ||
| 172 | goto fail; | ||
| 173 | } | ||
| 174 | + table->use_dir_and_file_0 = false; | ||
| 175 | } | ||
| 176 | |||
| 177 | /* Read the statement sequences until there's nothing left. */ | ||
| 178 | @@ -2622,7 +2644,7 @@ decode_line_info (struct comp_unit *unit) | ||
| 179 | /* State machine registers. */ | ||
| 180 | bfd_vma address = 0; | ||
| 181 | unsigned char op_index = 0; | ||
| 182 | - char * filename = table->num_files ? concat_filename (table, 1) : NULL; | ||
| 183 | + char * filename = NULL; | ||
| 184 | unsigned int line = 1; | ||
| 185 | unsigned int column = 0; | ||
| 186 | unsigned int discriminator = 0; | ||
| 187 | @@ -2637,6 +2659,14 @@ decode_line_info (struct comp_unit *unit) | ||
| 188 | bfd_vma low_pc = (bfd_vma) -1; | ||
| 189 | bfd_vma high_pc = 0; | ||
| 190 | |||
| 191 | + if (table->num_files) | ||
| 192 | + { | ||
| 193 | + if (table->use_dir_and_file_0) | ||
| 194 | + filename = concat_filename (table, 0); | ||
| 195 | + else | ||
| 196 | + filename = concat_filename (table, 1); | ||
| 197 | + } | ||
| 198 | + | ||
| 199 | /* Decode the table. */ | ||
| 200 | while (!end_sequence && line_ptr < line_end) | ||
| 201 | { | ||
| 202 | diff --git a/ld/testsuite/ld-x86-64/pr27587.err b/ld/testsuite/ld-x86-64/pr27587.err | ||
| 203 | index fa870790..807750ca 100644 | ||
| 204 | --- a/ld/testsuite/ld-x86-64/pr27587.err | ||
| 205 | +++ b/ld/testsuite/ld-x86-64/pr27587.err | ||
| 206 | @@ -1,3 +1,3 @@ | ||
| 207 | #... | ||
| 208 | -.*pr27587.i:4: undefined reference to `stack_size' | ||
| 209 | +.*pr27587/<artificial>:4: undefined reference to `stack_size' | ||
| 210 | #... | ||
diff --git a/meta/recipes-devtools/binutils/binutils/0020-CVE-2023-22608-3.patch b/meta/recipes-devtools/binutils/binutils/0020-CVE-2023-22608-3.patch new file mode 100644 index 0000000000..a1b74248ce --- /dev/null +++ b/meta/recipes-devtools/binutils/binutils/0020-CVE-2023-22608-3.patch | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | From 4b8386a90802ed8e43eac2266f6e03c92b4462ed Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Nick Clifton <nickc@redhat.com> | ||
| 3 | Date: Fri, 23 Dec 2022 13:02:04 +0000 | ||
| 4 | Subject: [PATCH] Fix illegal memory access parsing corrupt DWARF information. | ||
| 5 | |||
| 6 | PR 29936 | ||
| 7 | * dwarf2.c (concat_filename): Fix check for a directory index off | ||
| 8 | the end of the directory table. | ||
| 9 | |||
| 10 | Upstream-Status: Backport [https://sourceware.org/git/?p=binutils-gdb.git;a=commitdiff;h=8af23b30edbaedf009bc9b243cd4dfa10ae1ac09] | ||
| 11 | CVE: CVE-2023-22608 | ||
| 12 | |||
| 13 | Signed-off-by: Yash Shinde <Yash.Shinde@windriver.com> | ||
| 14 | |||
| 15 | --- | ||
| 16 | bfd/dwarf2.c | 3 ++- | ||
| 17 | 1 file changed, 2 insertions(+), 1 deletion(-) | ||
| 18 | |||
| 19 | diff --git a/bfd/dwarf2.c b/bfd/dwarf2.c | ||
| 20 | index b7839ad6..8b07a24c 100644 | ||
| 21 | --- a/bfd/dwarf2.c | ||
| 22 | +++ b/bfd/dwarf2.c | ||
| 23 | @@ -1828,7 +1828,8 @@ concat_filename (struct line_info_table *table, unsigned int file) | ||
| 24 | |||
| 25 | if (table->files[file].dir | ||
| 26 | /* PR 17512: file: 0317e960. */ | ||
| 27 | - && table->files[file].dir <= table->num_dirs | ||
| 28 | + && table->files[file].dir | ||
| 29 | + <= (table->use_dir_and_file_0 ? table->num_dirs - 1 : table->num_dirs) | ||
| 30 | /* PR 17512: file: 7f3d2e4b. */ | ||
| 31 | && table->dirs != NULL) | ||
| 32 | { | ||
