mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-22 19:09:31 +08:00
PR28691, validate dwarf attribute form
PR28691 is a fuzzing PR that triggers a non-problem of "output changes per run" with PIEs and/or different compilers. I've closed similar PRs before as wontfix, but I guess there will be no end of this type of PR. The trigger is an attribute that usually takes one of the offset/constant reference DW_FORMs being given an indexed string DW_FORM. The bfd reader doesn't support indexed strings and returns an error string instead. The address of the string varies with PIE runs and/or compiler, and we allow that address to appear in output. Fix this by validating integer attribute forms, as we do for string form attributes. PR 28691 * dwarf2.c (is_str_attr): Rename to.. (is_str_form): ..this. Change param type. Update calls. (is_int_form): New function. (read_attribute_value): Handle DW_FORM_addrx2. (find_abstract_instance): Validate form when using attr.u.val. (scan_unit_for_symbols, parse_comp_unit): Likewise.
This commit is contained in:
184
bfd/dwarf2.c
184
bfd/dwarf2.c
@ -1158,18 +1158,63 @@ read_abbrevs (bfd *abfd, bfd_uint64_t offset, struct dwarf2_debug *stash,
|
|||||||
|
|
||||||
/* Returns true if the form is one which has a string value. */
|
/* Returns true if the form is one which has a string value. */
|
||||||
|
|
||||||
static inline bool
|
static bool
|
||||||
is_str_attr (enum dwarf_form form)
|
is_str_form (const struct attribute *attr)
|
||||||
{
|
{
|
||||||
return (form == DW_FORM_string
|
switch (attr->form)
|
||||||
|| form == DW_FORM_strp
|
{
|
||||||
|| form == DW_FORM_strx
|
case DW_FORM_string:
|
||||||
|| form == DW_FORM_strx1
|
case DW_FORM_strp:
|
||||||
|| form == DW_FORM_strx2
|
case DW_FORM_strx:
|
||||||
|| form == DW_FORM_strx3
|
case DW_FORM_strx1:
|
||||||
|| form == DW_FORM_strx4
|
case DW_FORM_strx2:
|
||||||
|| form == DW_FORM_line_strp
|
case DW_FORM_strx3:
|
||||||
|| form == DW_FORM_GNU_strp_alt);
|
case DW_FORM_strx4:
|
||||||
|
case DW_FORM_line_strp:
|
||||||
|
case DW_FORM_GNU_strp_alt:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns true if the form is one which has an integer value. */
|
||||||
|
|
||||||
|
static bool
|
||||||
|
is_int_form (const struct attribute *attr)
|
||||||
|
{
|
||||||
|
switch (attr->form)
|
||||||
|
{
|
||||||
|
case DW_FORM_addr:
|
||||||
|
case DW_FORM_data2:
|
||||||
|
case DW_FORM_data4:
|
||||||
|
case DW_FORM_data8:
|
||||||
|
case DW_FORM_data1:
|
||||||
|
case DW_FORM_flag:
|
||||||
|
case DW_FORM_sdata:
|
||||||
|
case DW_FORM_udata:
|
||||||
|
case DW_FORM_ref_addr:
|
||||||
|
case DW_FORM_ref1:
|
||||||
|
case DW_FORM_ref2:
|
||||||
|
case DW_FORM_ref4:
|
||||||
|
case DW_FORM_ref8:
|
||||||
|
case DW_FORM_ref_udata:
|
||||||
|
case DW_FORM_sec_offset:
|
||||||
|
case DW_FORM_flag_present:
|
||||||
|
case DW_FORM_ref_sig8:
|
||||||
|
case DW_FORM_addrx:
|
||||||
|
case DW_FORM_implicit_const:
|
||||||
|
case DW_FORM_addrx1:
|
||||||
|
case DW_FORM_addrx2:
|
||||||
|
case DW_FORM_addrx3:
|
||||||
|
case DW_FORM_addrx4:
|
||||||
|
case DW_FORM_GNU_ref_alt:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *
|
static const char *
|
||||||
@ -1250,6 +1295,7 @@ read_attribute_value (struct attribute * attr,
|
|||||||
attr->u.val = read_1_byte (abfd, &info_ptr, info_ptr_end);
|
attr->u.val = read_1_byte (abfd, &info_ptr, info_ptr_end);
|
||||||
break;
|
break;
|
||||||
case DW_FORM_data2:
|
case DW_FORM_data2:
|
||||||
|
case DW_FORM_addrx2:
|
||||||
case DW_FORM_ref2:
|
case DW_FORM_ref2:
|
||||||
attr->u.val = read_2_bytes (abfd, &info_ptr, info_ptr_end);
|
attr->u.val = read_2_bytes (abfd, &info_ptr, info_ptr_end);
|
||||||
break;
|
break;
|
||||||
@ -3037,7 +3083,7 @@ find_abstract_instance (struct comp_unit *unit,
|
|||||||
case DW_AT_name:
|
case DW_AT_name:
|
||||||
/* Prefer DW_AT_MIPS_linkage_name or DW_AT_linkage_name
|
/* Prefer DW_AT_MIPS_linkage_name or DW_AT_linkage_name
|
||||||
over DW_AT_name. */
|
over DW_AT_name. */
|
||||||
if (name == NULL && is_str_attr (attr.form))
|
if (name == NULL && is_str_form (&attr))
|
||||||
{
|
{
|
||||||
name = attr.u.str;
|
name = attr.u.str;
|
||||||
if (non_mangled (unit->lang))
|
if (non_mangled (unit->lang))
|
||||||
@ -3045,16 +3091,17 @@ find_abstract_instance (struct comp_unit *unit,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case DW_AT_specification:
|
case DW_AT_specification:
|
||||||
if (!find_abstract_instance (unit, &attr, recur_count + 1,
|
if (is_int_form (&attr)
|
||||||
&name, is_linkage,
|
&& !find_abstract_instance (unit, &attr, recur_count + 1,
|
||||||
filename_ptr, linenumber_ptr))
|
&name, is_linkage,
|
||||||
|
filename_ptr, linenumber_ptr))
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
case DW_AT_linkage_name:
|
case DW_AT_linkage_name:
|
||||||
case DW_AT_MIPS_linkage_name:
|
case DW_AT_MIPS_linkage_name:
|
||||||
/* PR 16949: Corrupt debug info can place
|
/* PR 16949: Corrupt debug info can place
|
||||||
non-string forms into these attributes. */
|
non-string forms into these attributes. */
|
||||||
if (is_str_attr (attr.form))
|
if (is_str_form (&attr))
|
||||||
{
|
{
|
||||||
name = attr.u.str;
|
name = attr.u.str;
|
||||||
*is_linkage = true;
|
*is_linkage = true;
|
||||||
@ -3063,11 +3110,13 @@ find_abstract_instance (struct comp_unit *unit,
|
|||||||
case DW_AT_decl_file:
|
case DW_AT_decl_file:
|
||||||
if (!comp_unit_maybe_decode_line_info (unit))
|
if (!comp_unit_maybe_decode_line_info (unit))
|
||||||
return false;
|
return false;
|
||||||
*filename_ptr = concat_filename (unit->line_table,
|
if (is_int_form (&attr))
|
||||||
attr.u.val);
|
*filename_ptr = concat_filename (unit->line_table,
|
||||||
|
attr.u.val);
|
||||||
break;
|
break;
|
||||||
case DW_AT_decl_line:
|
case DW_AT_decl_line:
|
||||||
*linenumber_ptr = attr.u.val;
|
if (is_int_form (&attr))
|
||||||
|
*linenumber_ptr = attr.u.val;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -3452,28 +3501,31 @@ scan_unit_for_symbols (struct comp_unit *unit)
|
|||||||
switch (attr.name)
|
switch (attr.name)
|
||||||
{
|
{
|
||||||
case DW_AT_call_file:
|
case DW_AT_call_file:
|
||||||
func->caller_file = concat_filename (unit->line_table,
|
if (is_int_form (&attr))
|
||||||
attr.u.val);
|
func->caller_file = concat_filename (unit->line_table,
|
||||||
|
attr.u.val);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DW_AT_call_line:
|
case DW_AT_call_line:
|
||||||
func->caller_line = attr.u.val;
|
if (is_int_form (&attr))
|
||||||
|
func->caller_line = attr.u.val;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DW_AT_abstract_origin:
|
case DW_AT_abstract_origin:
|
||||||
case DW_AT_specification:
|
case DW_AT_specification:
|
||||||
if (!find_abstract_instance (unit, &attr, 0,
|
if (is_int_form (&attr)
|
||||||
&func->name,
|
&& !find_abstract_instance (unit, &attr, 0,
|
||||||
&func->is_linkage,
|
&func->name,
|
||||||
&func->file,
|
&func->is_linkage,
|
||||||
&func->line))
|
&func->file,
|
||||||
|
&func->line))
|
||||||
goto fail;
|
goto fail;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DW_AT_name:
|
case DW_AT_name:
|
||||||
/* Prefer DW_AT_MIPS_linkage_name or DW_AT_linkage_name
|
/* Prefer DW_AT_MIPS_linkage_name or DW_AT_linkage_name
|
||||||
over DW_AT_name. */
|
over DW_AT_name. */
|
||||||
if (func->name == NULL && is_str_attr (attr.form))
|
if (func->name == NULL && is_str_form (&attr))
|
||||||
{
|
{
|
||||||
func->name = attr.u.str;
|
func->name = attr.u.str;
|
||||||
if (non_mangled (unit->lang))
|
if (non_mangled (unit->lang))
|
||||||
@ -3485,7 +3537,7 @@ scan_unit_for_symbols (struct comp_unit *unit)
|
|||||||
case DW_AT_MIPS_linkage_name:
|
case DW_AT_MIPS_linkage_name:
|
||||||
/* PR 16949: Corrupt debug info can place
|
/* PR 16949: Corrupt debug info can place
|
||||||
non-string forms into these attributes. */
|
non-string forms into these attributes. */
|
||||||
if (is_str_attr (attr.form))
|
if (is_str_form (&attr))
|
||||||
{
|
{
|
||||||
func->name = attr.u.str;
|
func->name = attr.u.str;
|
||||||
func->is_linkage = true;
|
func->is_linkage = true;
|
||||||
@ -3493,26 +3545,33 @@ scan_unit_for_symbols (struct comp_unit *unit)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case DW_AT_low_pc:
|
case DW_AT_low_pc:
|
||||||
low_pc = attr.u.val;
|
if (is_int_form (&attr))
|
||||||
|
low_pc = attr.u.val;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DW_AT_high_pc:
|
case DW_AT_high_pc:
|
||||||
high_pc = attr.u.val;
|
if (is_int_form (&attr))
|
||||||
high_pc_relative = attr.form != DW_FORM_addr;
|
{
|
||||||
|
high_pc = attr.u.val;
|
||||||
|
high_pc_relative = attr.form != DW_FORM_addr;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DW_AT_ranges:
|
case DW_AT_ranges:
|
||||||
if (!read_rangelist (unit, &func->arange, attr.u.val))
|
if (is_int_form (&attr)
|
||||||
|
&& !read_rangelist (unit, &func->arange, attr.u.val))
|
||||||
goto fail;
|
goto fail;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DW_AT_decl_file:
|
case DW_AT_decl_file:
|
||||||
func->file = concat_filename (unit->line_table,
|
if (is_int_form (&attr))
|
||||||
attr.u.val);
|
func->file = concat_filename (unit->line_table,
|
||||||
|
attr.u.val);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DW_AT_decl_line:
|
case DW_AT_decl_line:
|
||||||
func->line = attr.u.val;
|
if (is_int_form (&attr))
|
||||||
|
func->line = attr.u.val;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -3524,7 +3583,7 @@ scan_unit_for_symbols (struct comp_unit *unit)
|
|||||||
switch (attr.name)
|
switch (attr.name)
|
||||||
{
|
{
|
||||||
case DW_AT_specification:
|
case DW_AT_specification:
|
||||||
if (attr.u.val)
|
if (is_int_form (&attr) && attr.u.val)
|
||||||
{
|
{
|
||||||
struct varinfo * spec_var;
|
struct varinfo * spec_var;
|
||||||
|
|
||||||
@ -3551,21 +3610,23 @@ scan_unit_for_symbols (struct comp_unit *unit)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case DW_AT_name:
|
case DW_AT_name:
|
||||||
if (is_str_attr (attr.form))
|
if (is_str_form (&attr))
|
||||||
var->name = attr.u.str;
|
var->name = attr.u.str;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DW_AT_decl_file:
|
case DW_AT_decl_file:
|
||||||
var->file = concat_filename (unit->line_table,
|
if (is_int_form (&attr))
|
||||||
attr.u.val);
|
var->file = concat_filename (unit->line_table,
|
||||||
|
attr.u.val);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DW_AT_decl_line:
|
case DW_AT_decl_line:
|
||||||
var->line = attr.u.val;
|
if (is_int_form (&attr))
|
||||||
|
var->line = attr.u.val;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DW_AT_external:
|
case DW_AT_external:
|
||||||
if (attr.u.val != 0)
|
if (is_int_form (&attr) && attr.u.val != 0)
|
||||||
var->stack = false;
|
var->stack = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -3775,31 +3836,41 @@ parse_comp_unit (struct dwarf2_debug *stash,
|
|||||||
switch (attr.name)
|
switch (attr.name)
|
||||||
{
|
{
|
||||||
case DW_AT_stmt_list:
|
case DW_AT_stmt_list:
|
||||||
unit->stmtlist = 1;
|
if (is_int_form (&attr))
|
||||||
unit->line_offset = attr.u.val;
|
{
|
||||||
|
unit->stmtlist = 1;
|
||||||
|
unit->line_offset = attr.u.val;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DW_AT_name:
|
case DW_AT_name:
|
||||||
if (is_str_attr (attr.form))
|
if (is_str_form (&attr))
|
||||||
unit->name = attr.u.str;
|
unit->name = attr.u.str;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DW_AT_low_pc:
|
case DW_AT_low_pc:
|
||||||
low_pc = attr.u.val;
|
if (is_int_form (&attr))
|
||||||
/* If the compilation unit DIE has a DW_AT_low_pc attribute,
|
{
|
||||||
this is the base address to use when reading location
|
low_pc = attr.u.val;
|
||||||
lists or range lists. */
|
/* If the compilation unit DIE has a DW_AT_low_pc attribute,
|
||||||
if (abbrev->tag == DW_TAG_compile_unit)
|
this is the base address to use when reading location
|
||||||
unit->base_address = low_pc;
|
lists or range lists. */
|
||||||
|
if (abbrev->tag == DW_TAG_compile_unit)
|
||||||
|
unit->base_address = low_pc;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DW_AT_high_pc:
|
case DW_AT_high_pc:
|
||||||
high_pc = attr.u.val;
|
if (is_int_form (&attr))
|
||||||
high_pc_relative = attr.form != DW_FORM_addr;
|
{
|
||||||
|
high_pc = attr.u.val;
|
||||||
|
high_pc_relative = attr.form != DW_FORM_addr;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DW_AT_ranges:
|
case DW_AT_ranges:
|
||||||
if (!read_rangelist (unit, &unit->arange, attr.u.val))
|
if (is_int_form (&attr)
|
||||||
|
&& !read_rangelist (unit, &unit->arange, attr.u.val))
|
||||||
return NULL;
|
return NULL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -3808,7 +3879,7 @@ parse_comp_unit (struct dwarf2_debug *stash,
|
|||||||
char *comp_dir = attr.u.str;
|
char *comp_dir = attr.u.str;
|
||||||
|
|
||||||
/* PR 17512: file: 1fe726be. */
|
/* PR 17512: file: 1fe726be. */
|
||||||
if (! is_str_attr (attr.form))
|
if (!is_str_form (&attr))
|
||||||
{
|
{
|
||||||
_bfd_error_handler
|
_bfd_error_handler
|
||||||
(_("DWARF error: DW_AT_comp_dir attribute encountered with a non-string form"));
|
(_("DWARF error: DW_AT_comp_dir attribute encountered with a non-string form"));
|
||||||
@ -3829,7 +3900,8 @@ parse_comp_unit (struct dwarf2_debug *stash,
|
|||||||
}
|
}
|
||||||
|
|
||||||
case DW_AT_language:
|
case DW_AT_language:
|
||||||
unit->lang = attr.u.val;
|
if (is_int_form (&attr))
|
||||||
|
unit->lang = attr.u.val;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
Reference in New Issue
Block a user