summaryrefslogtreecommitdiffstats
path: root/meta/recipes-devtools/binutils/binutils/0021-CVE-2023-1579-1.patch
diff options
context:
space:
mode:
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.patch459
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
+