Fix more memory faults uncovered by fuzzing various executables.

PR binutils/17512
	* dwarf.c (read_and_display_attr_value): Check that we do not read
	past end.
	(display_debug_pubnames_worker): Add range checks.
	(process_debug_info): Check for invalid pointer sizes.
	(display_loc_list): Likewise.
	(display_loc_list_dwo): Likewise.
	(display_debug_ranges): Likewise.
	(display_debug_aranges): Check for invalid address size.
	(read_cie): Add range checks.  Replace call strchr with while loop.
	* objdump.c (dump_dwarf): Replace abort with a warning message.
	(print_section_stabs): Improve range checks.
	* rdcoff.c (coff_get_slot): Use long for indx parameter type.
	Add check for an excesively large index.
	* rddbg.c (read_section_stabs_debugging_info): Zero terminate the
	string table.  Avoid walking off the end of the stabs data.
	* stabs.c (parse_stab_string): Add check for a NULL name.

	PR binutils/17512
	* coffcode.h (coff_slurp_line_table): Set the line number of
	corrupt entries to -1.
	(coff_slurp_symbol_table): Alway initialise the value of the
	symbol.
	* coffgen.c (coff_print_symbol): Check that the combined pointer
	is valid.
	(coff_print_symbol): Do not print negative line numbers.
	* peXXigen.c (pe_print_idata): Add range checking displaying
	member names.
This commit is contained in:
Nick Clifton 2014-11-12 22:39:58 +00:00
parent 40e91bc71f
commit f41e4712a7
10 changed files with 244 additions and 82 deletions

View file

@ -1,3 +1,16 @@
2014-11-12 Nick Clifton <nickc@redhat.com>
PR binutils/17512
* coffcode.h (coff_slurp_line_table): Set the line number of
corrupt entries to -1.
(coff_slurp_symbol_table): Alway initialise the value of the
symbol.
* coffgen.c (coff_print_symbol): Check that the combined pointer
is valid.
(coff_print_symbol): Do not print negative line numbers.
* peXXigen.c (pe_print_idata): Add range checking displaying
member names.
2014-11-12 Alan Modra <amodra@gmail.com> 2014-11-12 Alan Modra <amodra@gmail.com>
PR binutils/17512 PR binutils/17512

View file

@ -4510,7 +4510,7 @@ coff_slurp_line_table (bfd *abfd, asection *asect)
unsigned int counter; unsigned int counter;
alent *cache_ptr; alent *cache_ptr;
bfd_vma prev_offset = 0; bfd_vma prev_offset = 0;
int ordered = 1; bfd_boolean ordered = TRUE;
unsigned int nbr_func; unsigned int nbr_func;
LINENO *src; LINENO *src;
bfd_boolean have_func; bfd_boolean have_func;
@ -4561,6 +4561,7 @@ coff_slurp_line_table (bfd *abfd, asection *asect)
(*_bfd_error_handler) (*_bfd_error_handler)
(_("%B: warning: illegal symbol index 0x%lx in line number entry %d"), (_("%B: warning: illegal symbol index 0x%lx in line number entry %d"),
abfd, (long) symndx, counter); abfd, (long) symndx, counter);
cache_ptr->line_number = -1;
continue; continue;
} }
@ -4572,11 +4573,12 @@ coff_slurp_line_table (bfd *abfd, asection *asect)
/* PR 17512 file: 078-10659-0.004 */ /* PR 17512 file: 078-10659-0.004 */
if (sym < obj_symbols (abfd) if (sym < obj_symbols (abfd)
|| sym >= obj_symbols (abfd) + obj_raw_syment_count (abfd)) || sym >= obj_symbols (abfd) + bfd_get_symcount (abfd))
{ {
(*_bfd_error_handler) (*_bfd_error_handler)
(_("%B: warning: illegal symbol in line number entry %d"), (_("%B: warning: illegal symbol in line number entry %d"),
abfd, counter); abfd, counter);
cache_ptr->line_number = -1;
continue; continue;
} }
@ -4590,7 +4592,7 @@ coff_slurp_line_table (bfd *abfd, asection *asect)
sym->lineno = cache_ptr; sym->lineno = cache_ptr;
if (sym->symbol.value < prev_offset) if (sym->symbol.value < prev_offset)
ordered = 0; ordered = FALSE;
prev_offset = sym->symbol.value; prev_offset = sym->symbol.value;
} }
else if (!have_func) else if (!have_func)
@ -4625,6 +4627,8 @@ coff_slurp_line_table (bfd *abfd, asection *asect)
if (lineno_cache[i].line_number == 0) if (lineno_cache[i].line_number == 0)
*p++ = &lineno_cache[i]; *p++ = &lineno_cache[i];
BFD_ASSERT ((p - func_table) == nbr_func);
/* Sort by functions. */ /* Sort by functions. */
qsort (func_table, nbr_func, sizeof (alent *), coff_sort_func_alent); qsort (func_table, nbr_func, sizeof (alent *), coff_sort_func_alent);
@ -4650,6 +4654,8 @@ coff_slurp_line_table (bfd *abfd, asection *asect)
*n_cache_ptr++ = *old_ptr++; *n_cache_ptr++ = *old_ptr++;
while (old_ptr->line_number != 0); while (old_ptr->line_number != 0);
} }
BFD_ASSERT ((bfd_size_type) (n_cache_ptr - n_lineno_cache) == (amt / sizeof (alent)));
memcpy (lineno_cache, n_lineno_cache, amt); memcpy (lineno_cache, n_lineno_cache, amt);
} }
bfd_release (abfd, func_table); bfd_release (abfd, func_table);
@ -4710,6 +4716,8 @@ coff_slurp_symbol_table (bfd * abfd)
dst->symbol.section = coff_section_from_bfd_index (abfd, dst->symbol.section = coff_section_from_bfd_index (abfd,
src->u.syment.n_scnum); src->u.syment.n_scnum);
dst->symbol.flags = 0; dst->symbol.flags = 0;
/* PR 17512: file: 079-7098-0.001:0.1. */
dst->symbol.value = 0;
dst->done_lineno = FALSE; dst->done_lineno = FALSE;
switch (src->u.syment.n_sclass) switch (src->u.syment.n_sclass)

View file

@ -2099,6 +2099,14 @@ coff_print_symbol (bfd *abfd,
fprintf (file, "[%3ld]", (long) (combined - root)); fprintf (file, "[%3ld]", (long) (combined - root));
/* PR 17512: file: 079-33786-0.001:0.1. */
if (combined < obj_raw_syments (abfd)
|| combined >= obj_raw_syments (abfd) + obj_raw_syment_count (abfd))
{
fprintf (file, _("<corrupt info> %s"), symbol->name);
break;
}
if (! combined->fix_value) if (! combined->fix_value)
val = (bfd_vma) combined->u.syment.n_value; val = (bfd_vma) combined->u.syment.n_value;
else else
@ -2192,8 +2200,11 @@ coff_print_symbol (bfd *abfd,
l++; l++;
while (l->line_number) while (l->line_number)
{ {
fprintf (file, "\n%4d : ", l->line_number); if (l->line_number > 0)
bfd_fprintf_vma (abfd, file, l->u.offset + symbol->section->vma); {
fprintf (file, "\n%4d : ", l->line_number);
bfd_fprintf_vma (abfd, file, l->u.offset + symbol->section->vma);
}
l++; l++;
} }
} }

View file

@ -1481,27 +1481,31 @@ pe_print_idata (bfd * abfd, void * vfile)
#ifdef COFF_WITH_pex64 #ifdef COFF_WITH_pex64
for (j = 0; idx + j + 8 <= datasize; j += 8) for (j = 0; idx + j + 8 <= datasize; j += 8)
{ {
bfd_size_type amt;
unsigned long member = bfd_get_32 (abfd, data + idx + j); unsigned long member = bfd_get_32 (abfd, data + idx + j);
unsigned long member_high = bfd_get_32 (abfd, data + idx + j + 4); unsigned long member_high = bfd_get_32 (abfd, data + idx + j + 4);
if (!member && !member_high) if (!member && !member_high)
break; break;
amt = member - adj;
if (HighBitSet (member_high)) if (HighBitSet (member_high))
fprintf (file, "\t%lx%08lx\t %4lx%08lx <none>", fprintf (file, "\t%lx%08lx\t %4lx%08lx <none>",
member_high, member, member_high, member,
WithoutHighBit (member_high), member); WithoutHighBit (member_high), member);
/* PR binutils/17512: Handle corrupt PE data. */ /* PR binutils/17512: Handle corrupt PE data. */
else if ((bfd_vma) member - adj + 2 >= datasize) else if (amt + 2 >= datasize)
fprintf (file, _("\t<corrupt: 0x%04lx>"), member); fprintf (file, _("\t<corrupt: 0x%04lx>"), member);
else else
{ {
int ordinal; int ordinal;
char *member_name; char *member_name;
ordinal = bfd_get_16 (abfd, data + member - adj); ordinal = bfd_get_16 (abfd, data + amt);
member_name = (char *) data + member - adj + 2; member_name = (char *) data + amt + 2;
fprintf (file, "\t%04lx\t %4d %s",member, ordinal, member_name); fprintf (file, "\t%04lx\t %4d %.*s",member, ordinal,
(int) (datasize - (amt + 2)), member_name);
} }
/* If the time stamp is not zero, the import address /* If the time stamp is not zero, the import address
@ -1517,27 +1521,30 @@ pe_print_idata (bfd * abfd, void * vfile)
#else #else
for (j = 0; idx + j + 4 <= datasize; j += 4) for (j = 0; idx + j + 4 <= datasize; j += 4)
{ {
bfd_size_type amt;
unsigned long member = bfd_get_32 (abfd, data + idx + j); unsigned long member = bfd_get_32 (abfd, data + idx + j);
/* Print single IMAGE_IMPORT_BY_NAME vector. */ /* Print single IMAGE_IMPORT_BY_NAME vector. */
if (member == 0) if (member == 0)
break; break;
amt = member - adj;
if (HighBitSet (member)) if (HighBitSet (member))
fprintf (file, "\t%04lx\t %4lu <none>", fprintf (file, "\t%04lx\t %4lu <none>",
member, WithoutHighBit (member)); member, WithoutHighBit (member));
/* PR binutils/17512: Handle corrupt PE data. */ /* PR binutils/17512: Handle corrupt PE data. */
else if ((bfd_vma) member - adj + 2 >= datasize) else if (amt + 2 >= datasize)
fprintf (file, _("\t<corrupt: 0x%04lx>"), member); fprintf (file, _("\t<corrupt: 0x%04lx>"), member);
else else
{ {
int ordinal; int ordinal;
char *member_name; char *member_name;
ordinal = bfd_get_16 (abfd, data + member - adj); ordinal = bfd_get_16 (abfd, data + amt);
member_name = (char *) data + member - adj + 2; member_name = (char *) data + amt + 2;
fprintf (file, "\t%04lx\t %4d %s", fprintf (file, "\t%04lx\t %4d %.*s",
member, ordinal, member_name); member, ordinal,
(int) (datasize - (amt + 2)), member_name);
} }
/* If the time stamp is not zero, the import address /* If the time stamp is not zero, the import address

View file

@ -1,3 +1,23 @@
2014-11-12 Nick Clifton <nickc@redhat.com>
PR binutils/17512
* dwarf.c (read_and_display_attr_value): Check that we do not read
past end.
(display_debug_pubnames_worker): Add range checks.
(process_debug_info): Check for invalid pointer sizes.
(display_loc_list): Likewise.
(display_loc_list_dwo): Likewise.
(display_debug_ranges): Likewise.
(display_debug_aranges): Check for invalid address size.
(read_cie): Add range checks. Replace call strchr with while loop.
* objdump.c (dump_dwarf): Replace abort with a warning message.
(print_section_stabs): Improve range checks.
* rdcoff.c (coff_get_slot): Use long for indx parameter type.
Add check for an excesively large index.
* rddbg.c (read_section_stabs_debugging_info): Zero terminate the
string table. Avoid walking off the end of the stabs data.
* stabs.c (parse_stab_string): Add check for a NULL name.
2014-11-11 Nick Clifton <nickc@redhat.com> 2014-11-11 Nick Clifton <nickc@redhat.com>
PR binutils/17531 PR binutils/17531

View file

@ -399,7 +399,7 @@ process_extended_line_op (unsigned char * data,
if (len == 0 || data == end) if (len == 0 || data == end)
{ {
warn (_("badly formed extended line op encountered!\n")); warn (_("Badly formed extended line op encountered!\n"));
return bytes_read; return bytes_read;
} }
@ -1464,9 +1464,9 @@ read_and_display_attr_value (unsigned long attribute,
unsigned char * orig_data = data; unsigned char * orig_data = data;
unsigned int bytes_read; unsigned int bytes_read;
if (data == end && form != DW_FORM_flag_present) if (data > end || (data == end && form != DW_FORM_flag_present))
{ {
warn (_("corrupt attribute\n")); warn (_("Corrupt attribute\n"));
return data; return data;
} }
@ -1623,6 +1623,12 @@ read_and_display_attr_value (unsigned long attribute,
case DW_FORM_exprloc: case DW_FORM_exprloc:
uvalue = read_uleb128 (data, & bytes_read, end); uvalue = read_uleb128 (data, & bytes_read, end);
block_start = data + bytes_read; block_start = data + bytes_read;
/* PR 17512: file: 008-103549-0.001:0.1. */
if (block_start + uvalue > end)
{
warn (_("Corrupt attribute block length: %lx\n"), (long) uvalue);
uvalue = end - block_start;
}
if (do_loc) if (do_loc)
data = block_start + uvalue; data = block_start + uvalue;
else else
@ -1632,6 +1638,11 @@ read_and_display_attr_value (unsigned long attribute,
case DW_FORM_block1: case DW_FORM_block1:
SAFE_BYTE_GET (uvalue, data, 1, end); SAFE_BYTE_GET (uvalue, data, 1, end);
block_start = data + 1; block_start = data + 1;
if (block_start + uvalue > end)
{
warn (_("Corrupt attribute block length: %lx\n"), (long) uvalue);
uvalue = end - block_start;
}
if (do_loc) if (do_loc)
data = block_start + uvalue; data = block_start + uvalue;
else else
@ -1641,6 +1652,11 @@ read_and_display_attr_value (unsigned long attribute,
case DW_FORM_block2: case DW_FORM_block2:
SAFE_BYTE_GET (uvalue, data, 2, end); SAFE_BYTE_GET (uvalue, data, 2, end);
block_start = data + 2; block_start = data + 2;
if (block_start + uvalue > end)
{
warn (_("Corrupt attribute block length: %lx\n"), (long) uvalue);
uvalue = end - block_start;
}
if (do_loc) if (do_loc)
data = block_start + uvalue; data = block_start + uvalue;
else else
@ -1650,6 +1666,11 @@ read_and_display_attr_value (unsigned long attribute,
case DW_FORM_block4: case DW_FORM_block4:
SAFE_BYTE_GET (uvalue, data, 4, end); SAFE_BYTE_GET (uvalue, data, 4, end);
block_start = data + 4; block_start = data + 4;
if (block_start + uvalue > end)
{
warn (_("Corrupt attribute block length: %lx\n"), (long) uvalue);
uvalue = end - block_start;
}
if (do_loc) if (do_loc)
data = block_start + uvalue; data = block_start + uvalue;
else else
@ -2184,7 +2205,7 @@ process_debug_info (struct dwarf_section *section,
if (num_units == 0) if (num_units == 0)
{ {
error (_("No comp units in %s section ?"), section->name); error (_("No comp units in %s section ?\n"), section->name);
return 0; return 0;
} }
@ -2193,7 +2214,7 @@ process_debug_info (struct dwarf_section *section,
sizeof (* debug_information)); sizeof (* debug_information));
if (debug_information == NULL) if (debug_information == NULL)
{ {
error (_("Not enough memory for a debug info array of %u entries"), error (_("Not enough memory for a debug info array of %u entries\n"),
num_units); num_units);
return 0; return 0;
} }
@ -2271,6 +2292,13 @@ process_debug_info (struct dwarf_section *section,
} }
SAFE_BYTE_GET_AND_INC (compunit.cu_pointer_size, hdrptr, 1, end); SAFE_BYTE_GET_AND_INC (compunit.cu_pointer_size, hdrptr, 1, end);
/* PR 17512: file: 001-108546-0.001:0.1. */
if (compunit.cu_pointer_size < 2 || compunit.cu_pointer_size > 8)
{
warn (_("Invalid pointer size (%d) in compunit header, using %d instead\n"),
compunit.cu_pointer_size, offset_size);
compunit.cu_pointer_size = offset_size;
}
if (do_types) if (do_types)
{ {
@ -2602,20 +2630,20 @@ read_debug_line_header (struct dwarf_section * section,
SAFE_BYTE_GET_AND_INC (linfo->li_length, hdrptr, 4, end); SAFE_BYTE_GET_AND_INC (linfo->li_length, hdrptr, 4, end);
if (linfo->li_length == 0xffffffff) if (linfo->li_length == 0xffffffff)
{ {
/* This section is 64-bit DWARF 3. */ /* This section is 64-bit DWARF 3. */
SAFE_BYTE_GET_AND_INC (linfo->li_length, hdrptr, 8, end); SAFE_BYTE_GET_AND_INC (linfo->li_length, hdrptr, 8, end);
offset_size = 8; offset_size = 8;
initial_length_size = 12; initial_length_size = 12;
} }
else else
{ {
offset_size = 4; offset_size = 4;
initial_length_size = 4; initial_length_size = 4;
} }
if (linfo->li_length + initial_length_size > section->size) if (linfo->li_length + initial_length_size > section->size)
{ {
/* If the length is just a bias against the initial_length_size then /* If the length is just a bias against the initial_length_size then
this means that the field has a relocation against it which has not this means that the field has a relocation against it which has not
been applied. (Ie we are dealing with an object file, not a linked been applied. (Ie we are dealing with an object file, not a linked
@ -2627,11 +2655,10 @@ read_debug_line_header (struct dwarf_section * section,
} }
else else
{ {
warn (_("The line info appears to be corrupt - " warn (_("The line info appears to be corrupt - the section is too small\n"));
"the section is too small\n"));
return NULL; return NULL;
} }
} }
/* Get and check the version number. */ /* Get and check the version number. */
SAFE_BYTE_GET_AND_INC (linfo->li_version, hdrptr, 2, end); SAFE_BYTE_GET_AND_INC (linfo->li_version, hdrptr, 2, end);
@ -2639,25 +2666,25 @@ read_debug_line_header (struct dwarf_section * section,
if (linfo->li_version != 2 if (linfo->li_version != 2
&& linfo->li_version != 3 && linfo->li_version != 3
&& linfo->li_version != 4) && linfo->li_version != 4)
{ {
warn (_("Only DWARF version 2, 3 and 4 line info is currently supported.\n")); warn (_("Only DWARF version 2, 3 and 4 line info is currently supported.\n"));
return NULL; return NULL;
} }
SAFE_BYTE_GET_AND_INC (linfo->li_prologue_length, hdrptr, offset_size, end); SAFE_BYTE_GET_AND_INC (linfo->li_prologue_length, hdrptr, offset_size, end);
SAFE_BYTE_GET_AND_INC (linfo->li_min_insn_length, hdrptr, 1, end); SAFE_BYTE_GET_AND_INC (linfo->li_min_insn_length, hdrptr, 1, end);
if (linfo->li_version >= 4) if (linfo->li_version >= 4)
{ {
SAFE_BYTE_GET_AND_INC (linfo->li_max_ops_per_insn, hdrptr, 1, end); SAFE_BYTE_GET_AND_INC (linfo->li_max_ops_per_insn, hdrptr, 1, end);
if (linfo->li_max_ops_per_insn == 0) if (linfo->li_max_ops_per_insn == 0)
{ {
warn (_("Invalid maximum operations per insn.\n")); warn (_("Invalid maximum operations per insn.\n"));
return NULL; return NULL;
}
} }
else }
else
linfo->li_max_ops_per_insn = 1; linfo->li_max_ops_per_insn = 1;
SAFE_BYTE_GET_AND_INC (linfo->li_default_is_stmt, hdrptr, 1, end); SAFE_BYTE_GET_AND_INC (linfo->li_default_is_stmt, hdrptr, 1, end);
@ -3204,7 +3231,7 @@ display_debug_lines_decoded (struct dwarf_section *section,
if (ext_op_code_len == 0) if (ext_op_code_len == 0)
{ {
warn (_("badly formed extended line op encountered!\n")); warn (_("Badly formed extended line op encountered!\n"));
break; break;
} }
ext_op_code_len += bytes_read; ext_op_code_len += bytes_read;
@ -3598,11 +3625,17 @@ display_debug_pubnames_worker (struct dwarf_section *section,
do do
{ {
bfd_size_type maxprint;
SAFE_BYTE_GET (offset, data, offset_size, end); SAFE_BYTE_GET (offset, data, offset_size, end);
if (offset != 0) if (offset != 0)
{ {
data += offset_size; data += offset_size;
if (data >= end)
break;
maxprint = (end - data) - 1;
if (is_gnu) if (is_gnu)
{ {
unsigned int kind_data; unsigned int kind_data;
@ -3612,6 +3645,7 @@ display_debug_pubnames_worker (struct dwarf_section *section,
SAFE_BYTE_GET (kind_data, data, 1, end); SAFE_BYTE_GET (kind_data, data, 1, end);
data++; data++;
maxprint --;
/* GCC computes the kind as the upper byte in the CU index /* GCC computes the kind as the upper byte in the CU index
word, and then right shifts it by the CU index size. word, and then right shifts it by the CU index size.
Left shift KIND to where the gdb-index.h accessor macros Left shift KIND to where the gdb-index.h accessor macros
@ -3620,13 +3654,16 @@ display_debug_pubnames_worker (struct dwarf_section *section,
kind = GDB_INDEX_SYMBOL_KIND_VALUE (kind_data); kind = GDB_INDEX_SYMBOL_KIND_VALUE (kind_data);
kind_name = get_gdb_index_symbol_kind_name (kind); kind_name = get_gdb_index_symbol_kind_name (kind);
is_static = GDB_INDEX_SYMBOL_STATIC_VALUE (kind_data); is_static = GDB_INDEX_SYMBOL_STATIC_VALUE (kind_data);
printf (" %-6lx %s,%-10s %s\n", printf (" %-6lx %s,%-10s %.*s\n",
offset, is_static ? _("s") : _("g"), offset, is_static ? _("s") : _("g"),
kind_name, data); kind_name, (int) maxprint, data);
} }
else else
printf (" %-6lx\t%s\n", offset, data); printf (" %-6lx\t%.*s\n", offset, (int) maxprint, data);
data += strnlen ((char *) data, end - data) + 1;
data += strnlen ((char *) data, maxprint) + 1;
if (data >= end)
break;
} }
} }
while (offset != 0); while (offset != 0);
@ -4135,6 +4172,13 @@ display_loc_list (struct dwarf_section *section,
unsigned short length; unsigned short length;
int need_frame_base; int need_frame_base;
if (pointer_size < 2 || pointer_size > 8)
{
warn (_("Invalid pointer size (%d) in debug info for entry %d\n"),
pointer_size, debug_info_entry);
return;
}
while (1) while (1)
{ {
if (start + 2 * pointer_size > section_end) if (start + 2 * pointer_size > section_end)
@ -4247,6 +4291,13 @@ display_loc_list_dwo (struct dwarf_section *section,
unsigned int idx; unsigned int idx;
unsigned int bytes_read; unsigned int bytes_read;
if (pointer_size < 2 || pointer_size > 8)
{
warn (_("Invalid pointer size (%d) in debug info for entry %d\n"),
pointer_size, debug_info_entry);
return;
}
while (1) while (1)
{ {
printf (" %8.8lx ", offset + (start - *start_ptr)); printf (" %8.8lx ", offset + (start - *start_ptr));
@ -4647,7 +4698,8 @@ display_debug_aranges (struct dwarf_section *section,
address_size = arange.ar_pointer_size + arange.ar_segment_size; address_size = arange.ar_pointer_size + arange.ar_segment_size;
if (address_size == 0) /* PR 17512: file: 001-108546-0.001:0.1. */
if (address_size == 0 || address_size > 8)
{ {
error (_("Invalid address size in %s section!\n"), error (_("Invalid address size in %s section!\n"),
section->name); section->name);
@ -4886,11 +4938,18 @@ display_debug_ranges (struct dwarf_section *section,
unsigned long base_address; unsigned long base_address;
pointer_size = debug_info_p->pointer_size; pointer_size = debug_info_p->pointer_size;
offset = range_entry->ranges_offset; offset = range_entry->ranges_offset;
next = section_begin + offset; next = section_begin + offset;
base_address = debug_info_p->base_address; base_address = debug_info_p->base_address;
/* PR 17512: file: 001-101485-0.001:0.1. */
if (pointer_size < 2 || pointer_size > 8)
{
warn (_("Corrupt pointer size (%d) in debug entry at offset %8.8lx\n"),
pointer_size, offset);
continue;
}
if (dwarf_check != 0 && i > 0) if (dwarf_check != 0 && i > 0)
{ {
if (start < next) if (start < next)
@ -5243,6 +5302,10 @@ read_cie (unsigned char *start, unsigned char *end,
unsigned char *augmentation_data = NULL; unsigned char *augmentation_data = NULL;
unsigned long augmentation_data_len = 0; unsigned long augmentation_data_len = 0;
/* PR 17512: file: 001-228113-0.004. */
if (start >= end)
return end;
fc = (Frame_Chunk *) xmalloc (sizeof (Frame_Chunk)); fc = (Frame_Chunk *) xmalloc (sizeof (Frame_Chunk));
memset (fc, 0, sizeof (Frame_Chunk)); memset (fc, 0, sizeof (Frame_Chunk));
@ -5252,7 +5315,16 @@ read_cie (unsigned char *start, unsigned char *end,
version = *start++; version = *start++;
fc->augmentation = (char *) start; fc->augmentation = (char *) start;
start = (unsigned char *) strchr ((char *) start, '\0') + 1; /* PR 17512: file: 001-228113-0.004.
Skip past augmentation name, but avoid running off the end of the data. */
while (start < end)
if (* start ++ == '\0')
break;
if (start == end)
{
warn (_("No terminator for augmentation name\n"));
return start;
}
if (strcmp (fc->augmentation, "eh") == 0) if (strcmp (fc->augmentation, "eh") == 0)
start += eh_addr_size; start += eh_addr_size;
@ -6140,7 +6212,7 @@ display_debug_frames (struct dwarf_section *section,
if (op >= DW_CFA_lo_user && op <= DW_CFA_hi_user) if (op >= DW_CFA_lo_user && op <= DW_CFA_hi_user)
printf (_(" DW_CFA_??? (User defined call frame op: %#x)\n"), op); printf (_(" DW_CFA_??? (User defined call frame op: %#x)\n"), op);
else else
warn (_("unsupported or unknown Dwarf Call Frame Instruction number: %#x\n"), op); warn (_("Unsupported or unknown Dwarf Call Frame Instruction number: %#x\n"), op);
start = block_end; start = block_end;
} }
} }

View file

@ -2388,7 +2388,12 @@ dump_dwarf (bfd *abfd)
else if (bfd_little_endian (abfd)) else if (bfd_little_endian (abfd))
byte_get = byte_get_little_endian; byte_get = byte_get_little_endian;
else else
abort (); /* PR 17512: file: objdump-s-endless-loop.tekhex. */
{
warn (_("File %s does not contain any dwarf debug information\n"),
bfd_get_filename (abfd));
return;
}
switch (bfd_get_arch (abfd)) switch (bfd_get_arch (abfd))
{ {
@ -2496,7 +2501,7 @@ print_section_stabs (bfd *abfd,
We start the index at -1 because there is a dummy symbol on We start the index at -1 because there is a dummy symbol on
the front of stabs-in-{coff,elf} sections that supplies sizes. */ the front of stabs-in-{coff,elf} sections that supplies sizes. */
for (i = -1; stabp < stabs_end; stabp += STABSIZE, i++) for (i = -1; stabp <= stabs_end - STABSIZE; stabp += STABSIZE, i++)
{ {
const char *name; const char *name;
unsigned long strx; unsigned long strx;
@ -2534,10 +2539,13 @@ print_section_stabs (bfd *abfd,
} }
else else
{ {
bfd_size_type amt = strx + file_string_table_offset;
/* Using the (possibly updated) string table offset, print the /* Using the (possibly updated) string table offset, print the
string (if any) associated with this symbol. */ string (if any) associated with this symbol. */
if ((strx + file_string_table_offset) < stabstr_size) if (amt < stabstr_size)
printf (" %s", &strtab[strx + file_string_table_offset]); /* PR 17512: file: 079-79389-0.001:0.1. */
printf (" %.*s", (int)(stabstr_size - amt), strtab + amt);
else else
printf (" *"); printf (" *");
} }

View file

@ -83,7 +83,7 @@ struct coff_types
debug_type basic[T_MAX + 1]; debug_type basic[T_MAX + 1];
}; };
static debug_type *coff_get_slot (struct coff_types *, int); static debug_type *coff_get_slot (struct coff_types *, long);
static debug_type parse_coff_type static debug_type parse_coff_type
(bfd *, struct coff_symbols *, struct coff_types *, long, int, (bfd *, struct coff_symbols *, struct coff_types *, long, int,
union internal_auxent *, bfd_boolean, void *); union internal_auxent *, bfd_boolean, void *);
@ -104,12 +104,17 @@ static bfd_boolean external_coff_symbol_p (int sym_class);
/* Return the slot for a type. */ /* Return the slot for a type. */
static debug_type * static debug_type *
coff_get_slot (struct coff_types *types, int indx) coff_get_slot (struct coff_types *types, long indx)
{ {
struct coff_slots **pps; struct coff_slots **pps;
pps = &types->slots; pps = &types->slots;
/* PR 17512: file: 078-18333-0.001:0.1.
FIXME: The value of 1000 is a guess. Maybe a better heuristic is needed. */
if (indx / COFF_SLOTS > 1000)
fatal (_("Excessively large slot index: %lx"), indx);
while (indx >= COFF_SLOTS) while (indx >= COFF_SLOTS)
{ {
if (*pps == NULL) if (*pps == NULL)

View file

@ -139,7 +139,7 @@ read_section_stabs_debugging_info (bfd *abfd, asymbol **syms, long symcount,
} }
strsize = bfd_section_size (abfd, strsec); strsize = bfd_section_size (abfd, strsec);
strings = (bfd_byte *) xmalloc (strsize); strings = (bfd_byte *) xmalloc (strsize + 1);
if (! bfd_get_section_contents (abfd, strsec, strings, 0, strsize)) if (! bfd_get_section_contents (abfd, strsec, strings, 0, strsize))
{ {
fprintf (stderr, "%s: %s: %s\n", fprintf (stderr, "%s: %s: %s\n",
@ -147,7 +147,8 @@ read_section_stabs_debugging_info (bfd *abfd, asymbol **syms, long symcount,
bfd_errmsg (bfd_get_error ())); bfd_errmsg (bfd_get_error ()));
return FALSE; return FALSE;
} }
/* Zero terminate the strings table, just in case. */
strings [strsize] = 0;
if (shandle == NULL) if (shandle == NULL)
{ {
shandle = start_stab (dhandle, abfd, TRUE, syms, symcount); shandle = start_stab (dhandle, abfd, TRUE, syms, symcount);
@ -159,7 +160,8 @@ read_section_stabs_debugging_info (bfd *abfd, asymbol **syms, long symcount,
stroff = 0; stroff = 0;
next_stroff = 0; next_stroff = 0;
for (stab = stabs; stab < stabs + stabsize; stab += 12) /* PR 17512: file: 078-60391-0.001:0.1. */
for (stab = stabs; stab <= (stabs + stabsize) - 12; stab += 12)
{ {
unsigned int strx; unsigned int strx;
int type; int type;
@ -184,33 +186,43 @@ read_section_stabs_debugging_info (bfd *abfd, asymbol **syms, long symcount,
} }
else else
{ {
size_t len;
char *f, *s; char *f, *s;
f = NULL; if (stroff + strx >= strsize)
if (stroff + strx > strsize)
{ {
fprintf (stderr, "%s: %s: stab entry %ld is corrupt, strx = 0x%x, type = %d\n", fprintf (stderr, _("%s: %s: stab entry %ld is corrupt, strx = 0x%x, type = %d\n"),
bfd_get_filename (abfd), names[i].secname, bfd_get_filename (abfd), names[i].secname,
(long) (stab - stabs) / 12, strx, type); (long) (stab - stabs) / 12, strx, type);
continue; continue;
} }
s = (char *) strings + stroff + strx; s = (char *) strings + stroff + strx;
f = NULL;
while (s[strlen (s) - 1] == '\\' /* PR 17512: file: 002-87578-0.001:0.1.
It is possible to craft a file where, without the 'strlen (s) > 0',
an attempt to read the byte before 'strings' would occur. */
while ((len = strlen (s)) > 0
&& s[len - 1] == '\\'
&& stab + 12 < stabs + stabsize) && stab + 12 < stabs + stabsize)
{ {
char *p; char *p;
stab += 12; stab += 12;
p = s + strlen (s) - 1; p = s + len - 1;
*p = '\0'; *p = '\0';
s = concat (s, strx = stroff + bfd_get_32 (abfd, stab);
((char *) strings if (strx >= strsize)
+ stroff {
+ bfd_get_32 (abfd, stab)), fprintf (stderr, _("%s: %s: stab entry %ld is corrupt\n"),
(const char *) NULL); bfd_get_filename (abfd), names[i].secname,
(long) (stab - stabs) / 12);
break;
}
else
s = concat (s, (char *) strings + strx,
(const char *) NULL);
/* We have to restore the backslash, because, if /* We have to restore the backslash, because, if
the linker is hashing stabs strings, we may the linker is hashing stabs strings, we may

View file

@ -836,8 +836,6 @@ parse_stab_string (void *dhandle, struct stab_handle *info, int stabtype,
case 'G': case 'G':
{ {
char leading;
long c;
asymbol **ps; asymbol **ps;
/* A global symbol. The value must be extracted from the /* A global symbol. The value must be extracted from the
@ -846,19 +844,27 @@ parse_stab_string (void *dhandle, struct stab_handle *info, int stabtype,
(debug_type **) NULL); (debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL) if (dtype == DEBUG_TYPE_NULL)
return FALSE; return FALSE;
leading = bfd_get_symbol_leading_char (info->abfd); if (name != NULL)
for (c = info->symcount, ps = info->syms; c > 0; --c, ++ps)
{ {
const char *n; char leading;
long c;
n = bfd_asymbol_name (*ps); leading = bfd_get_symbol_leading_char (info->abfd);
if (leading != '\0' && *n == leading) for (c = info->symcount, ps = info->syms; c > 0; --c, ++ps)
++n; {
if (*n == *name && strcmp (n, name) == 0) const char *n;
break;
n = bfd_asymbol_name (*ps);
if (leading != '\0' && *n == leading)
++n;
if (*n == *name && strcmp (n, name) == 0)
break;
}
if (c > 0)
value = bfd_asymbol_value (*ps);
} }
if (c > 0)
value = bfd_asymbol_value (*ps);
if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_GLOBAL, if (! stab_record_variable (dhandle, info, name, dtype, DEBUG_GLOBAL,
value)) value))
return FALSE; return FALSE;