+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>
PR binutils/17512
unsigned int counter;
alent *cache_ptr;
bfd_vma prev_offset = 0;
- int ordered = 1;
+ bfd_boolean ordered = TRUE;
unsigned int nbr_func;
LINENO *src;
bfd_boolean have_func;
(*_bfd_error_handler)
(_("%B: warning: illegal symbol index 0x%lx in line number entry %d"),
abfd, (long) symndx, counter);
+ cache_ptr->line_number = -1;
continue;
}
/* PR 17512 file: 078-10659-0.004 */
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)
(_("%B: warning: illegal symbol in line number entry %d"),
abfd, counter);
+ cache_ptr->line_number = -1;
continue;
}
sym->lineno = cache_ptr;
if (sym->symbol.value < prev_offset)
- ordered = 0;
+ ordered = FALSE;
prev_offset = sym->symbol.value;
}
else if (!have_func)
if (lineno_cache[i].line_number == 0)
*p++ = &lineno_cache[i];
+ BFD_ASSERT ((p - func_table) == nbr_func);
+
/* Sort by functions. */
qsort (func_table, nbr_func, sizeof (alent *), coff_sort_func_alent);
*n_cache_ptr++ = *old_ptr++;
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);
}
bfd_release (abfd, func_table);
dst->symbol.section = coff_section_from_bfd_index (abfd,
src->u.syment.n_scnum);
dst->symbol.flags = 0;
+ /* PR 17512: file: 079-7098-0.001:0.1. */
+ dst->symbol.value = 0;
dst->done_lineno = FALSE;
switch (src->u.syment.n_sclass)
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)
val = (bfd_vma) combined->u.syment.n_value;
else
l++;
while (l->line_number)
{
- fprintf (file, "\n%4d : ", l->line_number);
- bfd_fprintf_vma (abfd, file, l->u.offset + symbol->section->vma);
+ if (l->line_number > 0)
+ {
+ fprintf (file, "\n%4d : ", l->line_number);
+ bfd_fprintf_vma (abfd, file, l->u.offset + symbol->section->vma);
+ }
l++;
}
}
#ifdef COFF_WITH_pex64
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_high = bfd_get_32 (abfd, data + idx + j + 4);
if (!member && !member_high)
break;
+ amt = member - adj;
+
if (HighBitSet (member_high))
fprintf (file, "\t%lx%08lx\t %4lx%08lx <none>",
member_high, member,
WithoutHighBit (member_high), member);
/* 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);
else
{
int ordinal;
char *member_name;
- ordinal = bfd_get_16 (abfd, data + member - adj);
- member_name = (char *) data + member - adj + 2;
- fprintf (file, "\t%04lx\t %4d %s",member, ordinal, member_name);
+ ordinal = bfd_get_16 (abfd, data + amt);
+ member_name = (char *) data + amt + 2;
+ 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
#else
for (j = 0; idx + j + 4 <= datasize; j += 4)
{
+ bfd_size_type amt;
unsigned long member = bfd_get_32 (abfd, data + idx + j);
/* Print single IMAGE_IMPORT_BY_NAME vector. */
if (member == 0)
break;
+ amt = member - adj;
if (HighBitSet (member))
fprintf (file, "\t%04lx\t %4lu <none>",
member, WithoutHighBit (member));
/* 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);
else
{
int ordinal;
char *member_name;
- ordinal = bfd_get_16 (abfd, data + member - adj);
- member_name = (char *) data + member - adj + 2;
- fprintf (file, "\t%04lx\t %4d %s",
- member, ordinal, member_name);
+ ordinal = bfd_get_16 (abfd, data + amt);
+ member_name = (char *) data + amt + 2;
+ 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
+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>
PR binutils/17531
if (len == 0 || data == end)
{
- warn (_("badly formed extended line op encountered!\n"));
+ warn (_("Badly formed extended line op encountered!\n"));
return bytes_read;
}
unsigned char * orig_data = data;
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;
}
case DW_FORM_exprloc:
uvalue = read_uleb128 (data, & bytes_read, end);
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)
data = block_start + uvalue;
else
case DW_FORM_block1:
SAFE_BYTE_GET (uvalue, data, 1, end);
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)
data = block_start + uvalue;
else
case DW_FORM_block2:
SAFE_BYTE_GET (uvalue, data, 2, end);
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)
data = block_start + uvalue;
else
case DW_FORM_block4:
SAFE_BYTE_GET (uvalue, data, 4, end);
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)
data = block_start + uvalue;
else
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;
}
sizeof (* debug_information));
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);
return 0;
}
}
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)
{
SAFE_BYTE_GET_AND_INC (linfo->li_length, hdrptr, 4, end);
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);
- offset_size = 8;
- initial_length_size = 12;
- }
- else
- {
- offset_size = 4;
- initial_length_size = 4;
- }
+ offset_size = 8;
+ initial_length_size = 12;
+ }
+ else
+ {
+ offset_size = 4;
+ initial_length_size = 4;
+ }
if (linfo->li_length + initial_length_size > section->size)
- {
+ {
/* 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
been applied. (Ie we are dealing with an object file, not a linked
}
else
{
- warn (_("The line info appears to be corrupt - "
- "the section is too small\n"));
+ warn (_("The line info appears to be corrupt - the section is too small\n"));
return NULL;
}
- }
+ }
/* Get and check the version number. */
SAFE_BYTE_GET_AND_INC (linfo->li_version, hdrptr, 2, end);
if (linfo->li_version != 2
&& linfo->li_version != 3
&& 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;
- }
+ }
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);
if (linfo->li_version >= 4)
- {
+ {
SAFE_BYTE_GET_AND_INC (linfo->li_max_ops_per_insn, hdrptr, 1, end);
if (linfo->li_max_ops_per_insn == 0)
- {
- warn (_("Invalid maximum operations per insn.\n"));
+ {
+ warn (_("Invalid maximum operations per insn.\n"));
return NULL;
- }
}
- else
+ }
+ else
linfo->li_max_ops_per_insn = 1;
SAFE_BYTE_GET_AND_INC (linfo->li_default_is_stmt, hdrptr, 1, end);
if (ext_op_code_len == 0)
{
- warn (_("badly formed extended line op encountered!\n"));
+ warn (_("Badly formed extended line op encountered!\n"));
break;
}
ext_op_code_len += bytes_read;
do
{
+ bfd_size_type maxprint;
+
SAFE_BYTE_GET (offset, data, offset_size, end);
if (offset != 0)
{
data += offset_size;
+ if (data >= end)
+ break;
+ maxprint = (end - data) - 1;
+
if (is_gnu)
{
unsigned int kind_data;
SAFE_BYTE_GET (kind_data, data, 1, end);
data++;
+ maxprint --;
/* GCC computes the kind as the upper byte in the CU index
word, and then right shifts it by the CU index size.
Left shift KIND to where the gdb-index.h accessor macros
kind = GDB_INDEX_SYMBOL_KIND_VALUE (kind_data);
kind_name = get_gdb_index_symbol_kind_name (kind);
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"),
- kind_name, data);
+ kind_name, (int) maxprint, data);
}
else
- printf (" %-6lx\t%s\n", offset, data);
- data += strnlen ((char *) data, end - data) + 1;
+ printf (" %-6lx\t%.*s\n", offset, (int) maxprint, data);
+
+ data += strnlen ((char *) data, maxprint) + 1;
+ if (data >= end)
+ break;
}
}
while (offset != 0);
unsigned short length;
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)
{
if (start + 2 * pointer_size > section_end)
unsigned int idx;
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)
{
printf (" %8.8lx ", offset + (start - *start_ptr));
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"),
section->name);
unsigned long base_address;
pointer_size = debug_info_p->pointer_size;
-
offset = range_entry->ranges_offset;
next = section_begin + offset;
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 (start < next)
unsigned char *augmentation_data = NULL;
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));
memset (fc, 0, sizeof (Frame_Chunk));
version = *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)
start += eh_addr_size;
if (op >= DW_CFA_lo_user && op <= DW_CFA_hi_user)
printf (_(" DW_CFA_??? (User defined call frame op: %#x)\n"), op);
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;
}
}
else if (bfd_little_endian (abfd))
byte_get = byte_get_little_endian;
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))
{
We start the index at -1 because there is a dummy symbol on
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;
unsigned long strx;
}
else
{
+ bfd_size_type amt = strx + file_string_table_offset;
+
/* Using the (possibly updated) string table offset, print the
string (if any) associated with this symbol. */
- if ((strx + file_string_table_offset) < stabstr_size)
- printf (" %s", &strtab[strx + file_string_table_offset]);
+ if (amt < stabstr_size)
+ /* PR 17512: file: 079-79389-0.001:0.1. */
+ printf (" %.*s", (int)(stabstr_size - amt), strtab + amt);
else
printf (" *");
}
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
(bfd *, struct coff_symbols *, struct coff_types *, long, int,
union internal_auxent *, bfd_boolean, void *);
/* Return the slot for a 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;
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)
{
if (*pps == NULL)
}
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))
{
fprintf (stderr, "%s: %s: %s\n",
bfd_errmsg (bfd_get_error ()));
return FALSE;
}
-
+ /* Zero terminate the strings table, just in case. */
+ strings [strsize] = 0;
if (shandle == NULL)
{
shandle = start_stab (dhandle, abfd, TRUE, syms, symcount);
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;
int type;
}
else
{
+ size_t len;
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,
(long) (stab - stabs) / 12, strx, type);
continue;
}
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)
{
char *p;
stab += 12;
- p = s + strlen (s) - 1;
+ p = s + len - 1;
*p = '\0';
- s = concat (s,
- ((char *) strings
- + stroff
- + bfd_get_32 (abfd, stab)),
- (const char *) NULL);
+ strx = stroff + bfd_get_32 (abfd, stab);
+ if (strx >= strsize)
+ {
+ fprintf (stderr, _("%s: %s: stab entry %ld is corrupt\n"),
+ 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
the linker is hashing stabs strings, we may
case 'G':
{
- char leading;
- long c;
asymbol **ps;
/* A global symbol. The value must be extracted from the
(debug_type **) NULL);
if (dtype == DEBUG_TYPE_NULL)
return FALSE;
- leading = bfd_get_symbol_leading_char (info->abfd);
- for (c = info->symcount, ps = info->syms; c > 0; --c, ++ps)
+ if (name != NULL)
{
- const char *n;
+ char leading;
+ long c;
- n = bfd_asymbol_name (*ps);
- if (leading != '\0' && *n == leading)
- ++n;
- if (*n == *name && strcmp (n, name) == 0)
- break;
+ leading = bfd_get_symbol_leading_char (info->abfd);
+ for (c = info->symcount, ps = info->syms; c > 0; --c, ++ps)
+ {
+ const char *n;
+
+ 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,
value))
return FALSE;