diff options
Diffstat (limited to 'meta/recipes-devtools/binutils/binutils/0021-CVE-2023-1579-1.patch')
-rw-r--r-- | meta/recipes-devtools/binutils/binutils/0021-CVE-2023-1579-1.patch | 459 |
1 files changed, 459 insertions, 0 deletions
diff --git a/meta/recipes-devtools/binutils/binutils/0021-CVE-2023-1579-1.patch b/meta/recipes-devtools/binutils/binutils/0021-CVE-2023-1579-1.patch new file mode 100644 index 0000000000..1e9c03e70e --- /dev/null +++ b/meta/recipes-devtools/binutils/binutils/0021-CVE-2023-1579-1.patch @@ -0,0 +1,459 @@ +From f67741e172bf342291fe3abd2b395899ce6433a0 Mon Sep 17 00:00:00 2001 +From: "Potharla, Rupesh" <Rupesh.Potharla@amd.com> +Date: Tue, 24 May 2022 00:01:49 +0000 +Subject: [PATCH] bfd: Add Support for DW_FORM_strx* and DW_FORM_addrx* + +Upstream-Status: Backport [https://sourceware.org/git/?p=binutils-gdb.git;a=commitdiff;h=f67741e172bf342291fe3abd2b395899ce6433a0] + +CVE: CVE-2023-1579 + +Signed-off-by: Yash Shinde <Yash.Shinde@windriver.com> + +--- + bfd/dwarf2.c | 282 ++++++++++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 268 insertions(+), 14 deletions(-) + +diff --git a/bfd/dwarf2.c b/bfd/dwarf2.c +index f6b0183720b..45e286754e4 100644 +--- a/bfd/dwarf2.c ++++ b/bfd/dwarf2.c +@@ -189,6 +189,18 @@ struct dwarf2_debug_file + /* Length of the loaded .debug_str section. */ + bfd_size_type dwarf_str_size; + ++ /* Pointer to the .debug_str_offsets section loaded into memory. */ ++ bfd_byte *dwarf_str_offsets_buffer; ++ ++ /* Length of the loaded .debug_str_offsets section. */ ++ bfd_size_type dwarf_str_offsets_size; ++ ++ /* Pointer to the .debug_addr section loaded into memory. */ ++ bfd_byte *dwarf_addr_buffer; ++ ++ /* Length of the loaded .debug_addr section. */ ++ bfd_size_type dwarf_addr_size; ++ + /* Pointer to the .debug_line_str section loaded into memory. */ + bfd_byte *dwarf_line_str_buffer; + +@@ -382,6 +394,12 @@ struct comp_unit + /* Used when iterating over trie leaves to know which units we have + already seen in this iteration. */ + bool mark; ++ ++ /* Base address of debug_addr section. */ ++ size_t dwarf_addr_offset; ++ ++ /* Base address of string offset table. */ ++ size_t dwarf_str_offset; + }; + + /* This data structure holds the information of an abbrev. */ +@@ -424,6 +442,8 @@ const struct dwarf_debug_section dwarf_debug_sections[] = + { ".debug_static_vars", ".zdebug_static_vars" }, + { ".debug_str", ".zdebug_str", }, + { ".debug_str", ".zdebug_str", }, ++ { ".debug_str_offsets", ".zdebug_str_offsets", }, ++ { ".debug_addr", ".zdebug_addr", }, + { ".debug_line_str", ".zdebug_line_str", }, + { ".debug_types", ".zdebug_types" }, + /* GNU DWARF 1 extensions */ +@@ -458,6 +478,8 @@ enum dwarf_debug_section_enum + debug_static_vars, + debug_str, + debug_str_alt, ++ debug_str_offsets, ++ debug_addr, + debug_line_str, + debug_types, + debug_sfnames, +@@ -1307,12 +1329,92 @@ is_int_form (const struct attribute *attr) + } + } + ++/* Returns true if the form is strx[1-4]. */ ++ ++static inline bool ++is_strx_form (enum dwarf_form form) ++{ ++ return (form == DW_FORM_strx ++ || form == DW_FORM_strx1 ++ || form == DW_FORM_strx2 ++ || form == DW_FORM_strx3 ++ || form == DW_FORM_strx4); ++} ++ ++/* Return true if the form is addrx[1-4]. */ ++ ++static inline bool ++is_addrx_form (enum dwarf_form form) ++{ ++ return (form == DW_FORM_addrx ++ || form == DW_FORM_addrx1 ++ || form == DW_FORM_addrx2 ++ || form == DW_FORM_addrx3 ++ || form == DW_FORM_addrx4); ++} ++ ++/* Returns the address in .debug_addr section using DW_AT_addr_base. ++ Used to implement DW_FORM_addrx*. */ ++static bfd_vma ++read_indexed_address (bfd_uint64_t idx, ++ struct comp_unit *unit) ++{ ++ struct dwarf2_debug *stash = unit->stash; ++ struct dwarf2_debug_file *file = unit->file; ++ size_t addr_base = unit->dwarf_addr_offset; ++ bfd_byte *info_ptr; ++ ++ if (stash == NULL) ++ return 0; ++ ++ if (!read_section (unit->abfd, &stash->debug_sections[debug_addr], ++ file->syms, 0, ++ &file->dwarf_addr_buffer, &file->dwarf_addr_size)) ++ return 0; ++ ++ info_ptr = file->dwarf_addr_buffer + addr_base + idx * unit->offset_size; ++ ++ if (unit->offset_size == 4) ++ return bfd_get_32 (unit->abfd, info_ptr); ++ else ++ return bfd_get_64 (unit->abfd, info_ptr); ++} ++ ++/* Returns the string using DW_AT_str_offsets_base. ++ Used to implement DW_FORM_strx*. */ + static const char * +-read_indexed_string (bfd_uint64_t idx ATTRIBUTE_UNUSED, +- struct comp_unit * unit ATTRIBUTE_UNUSED) ++read_indexed_string (bfd_uint64_t idx, ++ struct comp_unit *unit) + { +- /* FIXME: Add support for indexed strings. */ +- return "<indexed strings not yet supported>"; ++ struct dwarf2_debug *stash = unit->stash; ++ struct dwarf2_debug_file *file = unit->file; ++ bfd_byte *info_ptr; ++ unsigned long str_offset; ++ ++ if (stash == NULL) ++ return NULL; ++ ++ if (!read_section (unit->abfd, &stash->debug_sections[debug_str], ++ file->syms, 0, ++ &file->dwarf_str_buffer, &file->dwarf_str_size)) ++ return NULL; ++ ++ if (!read_section (unit->abfd, &stash->debug_sections[debug_str_offsets], ++ file->syms, 0, ++ &file->dwarf_str_offsets_buffer, ++ &file->dwarf_str_offsets_size)) ++ return NULL; ++ ++ info_ptr = (file->dwarf_str_offsets_buffer ++ + unit->dwarf_str_offset ++ + idx * unit->offset_size); ++ ++ if (unit->offset_size == 4) ++ str_offset = bfd_get_32 (unit->abfd, info_ptr); ++ else ++ str_offset = bfd_get_64 (unit->abfd, info_ptr); ++ ++ return (const char *) file->dwarf_str_buffer + str_offset; + } + + /* Read and fill in the value of attribute ATTR as described by FORM. +@@ -1381,21 +1483,37 @@ read_attribute_value (struct attribute * attr, + case DW_FORM_ref1: + case DW_FORM_flag: + case DW_FORM_data1: ++ attr->u.val = read_1_byte (abfd, &info_ptr, info_ptr_end); ++ break; + case DW_FORM_addrx1: + attr->u.val = read_1_byte (abfd, &info_ptr, info_ptr_end); ++ /* dwarf_addr_offset value 0 indicates the attribute DW_AT_addr_base ++ is not yet read. */ ++ if (unit->dwarf_addr_offset != 0) ++ attr->u.val = read_indexed_address (attr->u.val, unit); + break; + case DW_FORM_data2: +- case DW_FORM_addrx2: + case DW_FORM_ref2: + attr->u.val = read_2_bytes (abfd, &info_ptr, info_ptr_end); + break; ++ case DW_FORM_addrx2: ++ attr->u.val = read_2_bytes (abfd, &info_ptr, info_ptr_end); ++ if (unit->dwarf_addr_offset != 0) ++ attr->u.val = read_indexed_address (attr->u.val, unit); ++ break; + case DW_FORM_addrx3: + attr->u.val = read_3_bytes (abfd, &info_ptr, info_ptr_end); ++ if (unit->dwarf_addr_offset != 0) ++ attr->u.val = read_indexed_address(attr->u.val, unit); + break; + case DW_FORM_ref4: + case DW_FORM_data4: ++ attr->u.val = read_4_bytes (abfd, &info_ptr, info_ptr_end); ++ break; + case DW_FORM_addrx4: + attr->u.val = read_4_bytes (abfd, &info_ptr, info_ptr_end); ++ if (unit->dwarf_addr_offset != 0) ++ attr->u.val = read_indexed_address (attr->u.val, unit); + break; + case DW_FORM_data8: + case DW_FORM_ref8: +@@ -1416,24 +1534,31 @@ read_attribute_value (struct attribute * attr, + break; + case DW_FORM_strx1: + attr->u.val = read_1_byte (abfd, &info_ptr, info_ptr_end); +- attr->u.str = (char *) read_indexed_string (attr->u.val, unit); ++ /* dwarf_str_offset value 0 indicates the attribute DW_AT_str_offsets_base ++ is not yet read. */ ++ if (unit->dwarf_str_offset != 0) ++ attr->u.str = (char *) read_indexed_string (attr->u.val, unit); + break; + case DW_FORM_strx2: + attr->u.val = read_2_bytes (abfd, &info_ptr, info_ptr_end); +- attr->u.str = (char *) read_indexed_string (attr->u.val, unit); ++ if (unit->dwarf_str_offset != 0) ++ attr->u.str = (char *) read_indexed_string (attr->u.val, unit); + break; + case DW_FORM_strx3: + attr->u.val = read_3_bytes (abfd, &info_ptr, info_ptr_end); +- attr->u.str = (char *) read_indexed_string (attr->u.val, unit); ++ if (unit->dwarf_str_offset != 0) ++ attr->u.str = (char *) read_indexed_string (attr->u.val, unit); + break; + case DW_FORM_strx4: + attr->u.val = read_4_bytes (abfd, &info_ptr, info_ptr_end); +- attr->u.str = (char *) read_indexed_string (attr->u.val, unit); ++ if (unit->dwarf_str_offset != 0) ++ attr->u.str = (char *) read_indexed_string (attr->u.val, unit); + break; + case DW_FORM_strx: + attr->u.val = _bfd_safe_read_leb128 (abfd, &info_ptr, + false, info_ptr_end); +- attr->u.str = (char *) read_indexed_string (attr->u.val, unit); ++ if (unit->dwarf_str_offset != 0) ++ attr->u.str = (char *) read_indexed_string (attr->u.val, unit); + break; + case DW_FORM_exprloc: + case DW_FORM_block: +@@ -1455,9 +1580,14 @@ read_attribute_value (struct attribute * attr, + break; + case DW_FORM_ref_udata: + case DW_FORM_udata: ++ attr->u.val = _bfd_safe_read_leb128 (abfd, &info_ptr, ++ false, info_ptr_end); ++ break; + case DW_FORM_addrx: + attr->u.val = _bfd_safe_read_leb128 (abfd, &info_ptr, + false, info_ptr_end); ++ if (unit->dwarf_addr_offset != 0) ++ attr->u.val = read_indexed_address (attr->u.val, unit); + break; + case DW_FORM_indirect: + form = _bfd_safe_read_leb128 (abfd, &info_ptr, +@@ -2396,6 +2526,11 @@ read_formatted_entries (struct comp_unit *unit, bfd_byte **bufp, + { + case DW_FORM_string: + case DW_FORM_line_strp: ++ case DW_FORM_strx: ++ case DW_FORM_strx1: ++ case DW_FORM_strx2: ++ case DW_FORM_strx3: ++ case DW_FORM_strx4: + *stringp = attr.u.str; + break; + +@@ -4031,6 +4166,80 @@ scan_unit_for_symbols (struct comp_unit *unit) + return false; + } + ++/* Read the attributes of the form strx and addrx. */ ++ ++static void ++reread_attribute (struct comp_unit *unit, ++ struct attribute *attr, ++ bfd_vma *low_pc, ++ bfd_vma *high_pc, ++ bool *high_pc_relative, ++ bool compunit) ++{ ++ if (is_strx_form (attr->form)) ++ attr->u.str = (char *) read_indexed_string (attr->u.val, unit); ++ if (is_addrx_form (attr->form)) ++ attr->u.val = read_indexed_address (attr->u.val, unit); ++ ++ switch (attr->name) ++ { ++ case DW_AT_stmt_list: ++ unit->stmtlist = 1; ++ unit->line_offset = attr->u.val; ++ break; ++ ++ case DW_AT_name: ++ if (is_str_form (attr)) ++ unit->name = attr->u.str; ++ break; ++ ++ case DW_AT_low_pc: ++ *low_pc = attr->u.val; ++ if (compunit) ++ unit->base_address = *low_pc; ++ break; ++ ++ case DW_AT_high_pc: ++ *high_pc = attr->u.val; ++ *high_pc_relative = attr->form != DW_FORM_addr; ++ break; ++ ++ case DW_AT_ranges: ++ if (!read_rangelist (unit, &unit->arange, ++ &unit->file->trie_root, attr->u.val)) ++ return; ++ break; ++ ++ case DW_AT_comp_dir: ++ { ++ char *comp_dir = attr->u.str; ++ ++ if (!is_str_form (attr)) ++ { ++ _bfd_error_handler ++ (_("DWARF error: DW_AT_comp_dir attribute encountered " ++ "with a non-string form")); ++ comp_dir = NULL; ++ } ++ ++ if (comp_dir) ++ { ++ char *cp = strchr (comp_dir, ':'); ++ ++ if (cp && cp != comp_dir && cp[-1] == '.' && cp[1] == '/') ++ comp_dir = cp + 1; ++ } ++ unit->comp_dir = comp_dir; ++ break; ++ } ++ ++ case DW_AT_language: ++ unit->lang = attr->u.val; ++ default: ++ break; ++ } ++} ++ + /* Parse a DWARF2 compilation unit starting at INFO_PTR. UNIT_LENGTH + includes the compilation unit header that proceeds the DIE's, but + does not include the length field that precedes each compilation +@@ -4064,6 +4273,10 @@ parse_comp_unit (struct dwarf2_debug *stash, + bfd *abfd = file->bfd_ptr; + bool high_pc_relative = false; + enum dwarf_unit_type unit_type; ++ struct attribute *str_addrp = NULL; ++ size_t str_count = 0; ++ size_t str_alloc = 0; ++ bool compunit_flag = false; + + version = read_2_bytes (abfd, &info_ptr, end_ptr); + if (version < 2 || version > 5) +@@ -4168,11 +4381,33 @@ parse_comp_unit (struct dwarf2_debug *stash, + unit->file = file; + unit->info_ptr_unit = info_ptr_unit; + ++ if (abbrev->tag == DW_TAG_compile_unit) ++ compunit_flag = true; ++ + for (i = 0; i < abbrev->num_attrs; ++i) + { + info_ptr = read_attribute (&attr, &abbrev->attrs[i], unit, info_ptr, end_ptr); + if (info_ptr == NULL) +- return NULL; ++ goto err_exit; ++ ++ /* Identify attributes of the form strx* and addrx* which come before ++ DW_AT_str_offsets_base and DW_AT_addr_base respectively in the CU. ++ Store the attributes in an array and process them later. */ ++ if ((unit->dwarf_str_offset == 0 && is_strx_form (attr.form)) ++ || (unit->dwarf_addr_offset == 0 && is_addrx_form (attr.form))) ++ { ++ if (str_count <= str_alloc) ++ { ++ str_alloc = 2 * str_alloc + 200; ++ str_addrp = bfd_realloc (str_addrp, ++ str_alloc * sizeof (*str_addrp)); ++ if (str_addrp == NULL) ++ goto err_exit; ++ } ++ str_addrp[str_count] = attr; ++ str_count++; ++ continue; ++ } + + /* Store the data if it is of an attribute we want to keep in a + partial symbol table. */ +@@ -4198,7 +4433,7 @@ parse_comp_unit (struct dwarf2_debug *stash, + /* If the compilation unit DIE has a DW_AT_low_pc attribute, + this is the base address to use when reading location + lists or range lists. */ +- if (abbrev->tag == DW_TAG_compile_unit) ++ if (compunit_flag) + unit->base_address = low_pc; + } + break; +@@ -4215,7 +4450,7 @@ parse_comp_unit (struct dwarf2_debug *stash, + if (is_int_form (&attr) + && !read_rangelist (unit, &unit->arange, + &unit->file->trie_root, attr.u.val)) +- return NULL; ++ goto err_exit; + break; + + case DW_AT_comp_dir: +@@ -4248,21 +4483,40 @@ parse_comp_unit (struct dwarf2_debug *stash, + unit->lang = attr.u.val; + break; + ++ case DW_AT_addr_base: ++ unit->dwarf_addr_offset = attr.u.val; ++ break; ++ ++ case DW_AT_str_offsets_base: ++ unit->dwarf_str_offset = attr.u.val; ++ break; ++ + default: + break; + } + } ++ ++ for (i = 0; i < str_count; ++i) ++ reread_attribute (unit, &str_addrp[i], &low_pc, &high_pc, ++ &high_pc_relative, compunit_flag); ++ + if (high_pc_relative) + high_pc += low_pc; + if (high_pc != 0) + { + if (!arange_add (unit, &unit->arange, &unit->file->trie_root, + low_pc, high_pc)) +- return NULL; ++ goto err_exit; + } + + unit->first_child_die_ptr = info_ptr; ++ ++ free (str_addrp); + return unit; ++ ++ err_exit: ++ free (str_addrp); ++ return NULL; + } + + /* Return TRUE if UNIT may contain the address given by ADDR. When +-- +2.31.1 + |