From aec72fda3b320c36eb99fc1c4cf95b10fc026729 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Thu, 16 Apr 2020 17:49:38 +0930 Subject: [PATCH] PR25827, Null pointer dereferencing in scan_unit_for_symbols PR 25827 * dwarf2.c (scan_unit_for_symbols): Wrap overlong lines. Don't strdup(0). Upstream-Status: Backport https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=aec72fda3b320c36eb99fc1c4cf95b10fc026729 CVE: CVE-2020-16593 Signed-off-by: Armin Kuster Index: git/bfd/dwarf2.c =================================================================== --- git.orig/bfd/dwarf2.c +++ git/bfd/dwarf2.c @@ -295,12 +295,12 @@ struct comp_unit /* This data structure holds the information of an abbrev. */ struct abbrev_info { - unsigned int number; /* Number identifying abbrev. */ - enum dwarf_tag tag; /* DWARF tag. */ - int has_children; /* Boolean. */ - unsigned int num_attrs; /* Number of attributes. */ - struct attr_abbrev *attrs; /* An array of attribute descriptions. */ - struct abbrev_info *next; /* Next in chain. */ + unsigned int number; /* Number identifying abbrev. */ + enum dwarf_tag tag; /* DWARF tag. */ + bfd_boolean has_children; /* TRUE if the abbrev has children. */ + unsigned int num_attrs; /* Number of attributes. */ + struct attr_abbrev * attrs; /* An array of attribute descriptions. */ + struct abbrev_info * next; /* Next in chain. */ }; struct attr_abbrev @@ -1487,6 +1487,8 @@ struct varinfo { /* Pointer to previous variable in list of all variables */ struct varinfo *prev_var; + /* The offset of the varinfo from the start of the unit. */ + bfd_uint64_t unit_offset; /* Source location file name */ char *file; /* Source location line number */ @@ -1497,7 +1499,7 @@ struct varinfo /* Where the symbol is defined */ asection *sec; /* Is this a stack variable? */ - unsigned int stack: 1; + bfd_boolean stack; }; /* Return TRUE if NEW_LINE should sort after LINE. */ @@ -2871,7 +2873,7 @@ lookup_symbol_in_variable_table (struct struct varinfo* each; for (each = unit->variable_table; each; each = each->prev_var) - if (each->stack == 0 + if (! each->stack && each->file != NULL && each->name != NULL && each->addr == addr @@ -3166,6 +3168,20 @@ read_rangelist (struct comp_unit *unit, return TRUE; } +static struct varinfo * +lookup_var_by_offset (bfd_uint64_t offset, struct varinfo * table) +{ + while (table) + { + if (table->unit_offset == offset) + return table; + table = table->prev_var; + } + + return NULL; +} + + /* DWARF2 Compilation unit functions. */ /* Scan over each die in a comp. unit looking for functions to add @@ -3202,6 +3218,9 @@ scan_unit_for_symbols (struct comp_unit bfd_vma low_pc = 0; bfd_vma high_pc = 0; bfd_boolean high_pc_relative = FALSE; + bfd_uint64_t current_offset; + + current_offset = info_ptr - unit->info_ptr_unit; /* PR 17512: file: 9f405d9d. */ if (info_ptr >= info_ptr_end) @@ -3234,12 +3253,13 @@ scan_unit_for_symbols (struct comp_unit goto fail; } - var = NULL; if (abbrev->tag == DW_TAG_subprogram || abbrev->tag == DW_TAG_entry_point || abbrev->tag == DW_TAG_inlined_subroutine) { bfd_size_type amt = sizeof (struct funcinfo); + + var = NULL; func = (struct funcinfo *) bfd_zalloc (abfd, amt); if (func == NULL) goto fail; @@ -3268,13 +3288,15 @@ scan_unit_for_symbols (struct comp_unit if (var == NULL) goto fail; var->tag = abbrev->tag; - var->stack = 1; + var->stack = TRUE; var->prev_var = unit->variable_table; unit->variable_table = var; + var->unit_offset = current_offset; /* PR 18205: Missing debug information can cause this var to be attached to an already cached unit. */ } - + else + var = NULL; /* No inline function in scope at this nesting level. */ nested_funcs[nesting_level].func = 0; } @@ -3362,6 +3384,33 @@ scan_unit_for_symbols (struct comp_unit { switch (attr.name) { + case DW_AT_specification: + if (attr.u.val) + { + struct varinfo * spec_var; + + spec_var = lookup_var_by_offset (attr.u.val, + unit->variable_table); + if (spec_var == NULL) + { + _bfd_error_handler (_("DWARF error: could not find " + "variable specification " + "at offset %lx"), + (unsigned long) attr.u.val); + break; + } + + if (var->name == NULL) + var->name = spec_var->name; + if (var->file == NULL && spec_var->file != NULL) + var->file = strdup (spec_var->file); + if (var->line == 0) + var->line = spec_var->line; + if (var->sec == NULL) + var->sec = spec_var->sec; + } + break; + case DW_AT_name: if (is_str_attr (attr.form)) var->name = attr.u.str; @@ -3378,7 +3427,7 @@ scan_unit_for_symbols (struct comp_unit case DW_AT_external: if (attr.u.val != 0) - var->stack = 0; + var->stack = FALSE; break; case DW_AT_location: @@ -3392,7 +3441,7 @@ scan_unit_for_symbols (struct comp_unit if (attr.u.blk->data != NULL && *attr.u.blk->data == DW_OP_addr) { - var->stack = 0; + var->stack = FALSE; /* Verify that DW_OP_addr is the only opcode in the location, in which case the block size will be 1 @@ -3888,7 +3937,7 @@ comp_unit_hash_info (struct dwarf2_debug each_var = each_var->prev_var) { /* Skip stack vars and vars with no files or names. */ - if (each_var->stack == 0 + if (! each_var->stack && each_var->file != NULL && each_var->name != NULL) /* There is no need to copy name string into hash table as Index: git/bfd/ChangeLog =================================================================== --- git.orig/bfd/ChangeLog +++ git/bfd/ChangeLog @@ -1,3 +1,9 @@ +2020-04-16 Alan Modra + + PR 25827 + * dwarf2.c (scan_unit_for_symbols): Wrap overlong lines. Don't + strdup(0). + 2021-05-03 Alan Modra PR 27755