mirror of
https://git.yoctoproject.org/poky
synced 2026-01-29 21:08:42 +01:00
binutils : Fix CVE-2023-1579
Upstream-Status: Backport [https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=3e307d538c351aa9327cbad672c884059ecc20dd] (From OE-Core rev: d478e7ea0bb897e13d86c476966924ef9927f11a) Signed-off-by: Yash Shinde <Yash.Shinde@windriver.com> Signed-off-by: Steve Sakoman <steve@sakoman.com>
This commit is contained in:
committed by
Steve Sakoman
parent
09def309f9
commit
dea0c1e1f5
@@ -46,5 +46,9 @@ SRC_URI = "\
|
||||
file://0020-CVE-2023-22608-1.patch \
|
||||
file://0020-CVE-2023-22608-2.patch \
|
||||
file://0020-CVE-2023-22608-3.patch \
|
||||
file://0021-CVE-2023-1579-1.patch \
|
||||
file://0021-CVE-2023-1579-2.patch \
|
||||
file://0021-CVE-2023-1579-3.patch \
|
||||
file://0021-CVE-2023-1579-4.patch \
|
||||
"
|
||||
S = "${WORKDIR}/git"
|
||||
|
||||
@@ -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
|
||||
|
||||
2127
meta/recipes-devtools/binutils/binutils/0021-CVE-2023-1579-2.patch
Normal file
2127
meta/recipes-devtools/binutils/binutils/0021-CVE-2023-1579-2.patch
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,156 @@
|
||||
From 31d6c13defeba7716ebc9d5c8f81f2f35fe39980 Mon Sep 17 00:00:00 2001
|
||||
From: Alan Modra <amodra@gmail.com>
|
||||
Date: Tue, 14 Jun 2022 12:46:42 +0930
|
||||
Subject: [PATCH] PR29230, segv in lookup_symbol_in_variable_table
|
||||
|
||||
The PR23230 testcase uses indexed strings without specifying
|
||||
SW_AT_str_offsets_base. In this case we left u.str with garbage (from
|
||||
u.val) which then led to a segfault when attempting to access the
|
||||
string. Fix that by clearing u.str. The patch also adds missing
|
||||
sanity checks in the recently committed read_indexed_address and
|
||||
read_indexed_string functions.
|
||||
|
||||
PR 29230
|
||||
* dwarf2.c (read_indexed_address): Return uint64_t. Sanity check idx.
|
||||
(read_indexed_string): Use uint64_t for str_offset. Sanity check idx.
|
||||
(read_attribute_value): Clear u.str for indexed string forms when
|
||||
DW_AT_str_offsets_base is not yet read or missing.
|
||||
|
||||
Upstream-Status: Backport [https://sourceware.org/git/?p=binutils-gdb.git;a=commitdiff;h=31d6c13defeba7716ebc9d5c8f81f2f35fe39980]
|
||||
|
||||
CVE: CVE-2023-1579
|
||||
|
||||
Signed-off-by: Yash Shinde <Yash.Shinde@windriver.com>
|
||||
|
||||
---
|
||||
bfd/dwarf2.c | 51 ++++++++++++++++++++++++++++++++++++++++++---------
|
||||
1 file changed, 42 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/bfd/dwarf2.c b/bfd/dwarf2.c
|
||||
index 51018e1ab45..aaa2d84887f 100644
|
||||
--- a/bfd/dwarf2.c
|
||||
+++ b/bfd/dwarf2.c
|
||||
@@ -1353,13 +1353,13 @@ is_addrx_form (enum dwarf_form form)
|
||||
|
||||
/* Returns the address in .debug_addr section using DW_AT_addr_base.
|
||||
Used to implement DW_FORM_addrx*. */
|
||||
-static bfd_vma
|
||||
+static uint64_t
|
||||
read_indexed_address (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;
|
||||
+ size_t offset;
|
||||
|
||||
if (stash == NULL)
|
||||
return 0;
|
||||
@@ -1369,12 +1369,23 @@ read_indexed_address (uint64_t idx, struct comp_unit *unit)
|
||||
&file->dwarf_addr_buffer, &file->dwarf_addr_size))
|
||||
return 0;
|
||||
|
||||
- info_ptr = file->dwarf_addr_buffer + addr_base + idx * unit->offset_size;
|
||||
+ if (_bfd_mul_overflow (idx, unit->offset_size, &offset))
|
||||
+ return 0;
|
||||
+
|
||||
+ offset += unit->dwarf_addr_offset;
|
||||
+ if (offset < unit->dwarf_addr_offset
|
||||
+ || offset > file->dwarf_addr_size
|
||||
+ || file->dwarf_addr_size - offset < unit->offset_size)
|
||||
+ return 0;
|
||||
+
|
||||
+ info_ptr = file->dwarf_addr_buffer + offset;
|
||||
|
||||
if (unit->offset_size == 4)
|
||||
return bfd_get_32 (unit->abfd, info_ptr);
|
||||
- else
|
||||
+ else if (unit->offset_size == 8)
|
||||
return bfd_get_64 (unit->abfd, info_ptr);
|
||||
+ else
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
/* Returns the string using DW_AT_str_offsets_base.
|
||||
@@ -1385,7 +1396,8 @@ read_indexed_string (uint64_t idx, struct comp_unit *unit)
|
||||
struct dwarf2_debug *stash = unit->stash;
|
||||
struct dwarf2_debug_file *file = unit->file;
|
||||
bfd_byte *info_ptr;
|
||||
- unsigned long str_offset;
|
||||
+ uint64_t str_offset;
|
||||
+ size_t offset;
|
||||
|
||||
if (stash == NULL)
|
||||
return NULL;
|
||||
@@ -1401,15 +1413,26 @@ read_indexed_string (uint64_t idx, struct comp_unit *unit)
|
||||
&file->dwarf_str_offsets_size))
|
||||
return NULL;
|
||||
|
||||
- info_ptr = (file->dwarf_str_offsets_buffer
|
||||
- + unit->dwarf_str_offset
|
||||
- + idx * unit->offset_size);
|
||||
+ if (_bfd_mul_overflow (idx, unit->offset_size, &offset))
|
||||
+ return NULL;
|
||||
+
|
||||
+ offset += unit->dwarf_str_offset;
|
||||
+ if (offset < unit->dwarf_str_offset
|
||||
+ || offset > file->dwarf_str_offsets_size
|
||||
+ || file->dwarf_str_offsets_size - offset < unit->offset_size)
|
||||
+ return NULL;
|
||||
+
|
||||
+ info_ptr = file->dwarf_str_offsets_buffer + offset;
|
||||
|
||||
if (unit->offset_size == 4)
|
||||
str_offset = bfd_get_32 (unit->abfd, info_ptr);
|
||||
- else
|
||||
+ else if (unit->offset_size == 8)
|
||||
str_offset = bfd_get_64 (unit->abfd, info_ptr);
|
||||
+ else
|
||||
+ return NULL;
|
||||
|
||||
+ if (str_offset >= file->dwarf_str_size)
|
||||
+ return NULL;
|
||||
return (const char *) file->dwarf_str_buffer + str_offset;
|
||||
}
|
||||
|
||||
@@ -1534,27 +1557,37 @@ read_attribute_value (struct attribute * attr,
|
||||
is not yet read. */
|
||||
if (unit->dwarf_str_offset != 0)
|
||||
attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
|
||||
+ else
|
||||
+ attr->u.str = NULL;
|
||||
break;
|
||||
case DW_FORM_strx2:
|
||||
attr->u.val = read_2_bytes (abfd, &info_ptr, info_ptr_end);
|
||||
if (unit->dwarf_str_offset != 0)
|
||||
attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
|
||||
+ else
|
||||
+ attr->u.str = NULL;
|
||||
break;
|
||||
case DW_FORM_strx3:
|
||||
attr->u.val = read_3_bytes (abfd, &info_ptr, info_ptr_end);
|
||||
if (unit->dwarf_str_offset != 0)
|
||||
attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
|
||||
+ else
|
||||
+ attr->u.str = NULL;
|
||||
break;
|
||||
case DW_FORM_strx4:
|
||||
attr->u.val = read_4_bytes (abfd, &info_ptr, info_ptr_end);
|
||||
if (unit->dwarf_str_offset != 0)
|
||||
attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
|
||||
+ else
|
||||
+ attr->u.str = NULL;
|
||||
break;
|
||||
case DW_FORM_strx:
|
||||
attr->u.val = _bfd_safe_read_leb128 (abfd, &info_ptr,
|
||||
false, info_ptr_end);
|
||||
if (unit->dwarf_str_offset != 0)
|
||||
attr->u.str = (char *) read_indexed_string (attr->u.val, unit);
|
||||
+ else
|
||||
+ attr->u.str = NULL;
|
||||
break;
|
||||
case DW_FORM_exprloc:
|
||||
case DW_FORM_block:
|
||||
--
|
||||
2.31.1
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
From 3e307d538c351aa9327cbad672c884059ecc20dd Mon Sep 17 00:00:00 2001
|
||||
From: Nick Clifton <nickc@redhat.com>
|
||||
Date: Wed, 11 Jan 2023 12:13:46 +0000
|
||||
Subject: [PATCH] Fix a potential illegal memory access in the BFD library when
|
||||
parsing a corrupt DWARF file.
|
||||
|
||||
PR 29988
|
||||
* dwarf2.c (read_indexed_address): Fix check for an out of range
|
||||
offset.
|
||||
|
||||
Upstream-Status: Backport [https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=3e307d538c351aa9327cbad672c884059ecc20dd]
|
||||
|
||||
CVE: CVE-2023-1579
|
||||
|
||||
Signed-off-by: Yash Shinde <Yash.Shinde@windriver.com>
|
||||
|
||||
---
|
||||
bfd/ChangeLog | 6 ++++++
|
||||
bfd/dwarf2.c | 2 +-
|
||||
2 files changed, 7 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/bfd/dwarf2.c b/bfd/dwarf2.c
|
||||
index 6eb6e04e6e5..4ec0053a111 100644
|
||||
--- a/bfd/dwarf2.c
|
||||
+++ b/bfd/dwarf2.c
|
||||
@@ -1412,7 +1412,7 @@ read_indexed_address (uint64_t idx, struct comp_unit *unit)
|
||||
offset += unit->dwarf_addr_offset;
|
||||
if (offset < unit->dwarf_addr_offset
|
||||
|| offset > file->dwarf_addr_size
|
||||
- || file->dwarf_addr_size - offset < unit->offset_size)
|
||||
+ || file->dwarf_addr_size - offset < unit->addr_size)
|
||||
return 0;
|
||||
|
||||
info_ptr = file->dwarf_addr_buffer + offset;
|
||||
--
|
||||
2.31.1
|
||||
|
||||
Reference in New Issue
Block a user