More fixes for processing corrupt files.
PR binutils/17512 * coffcode.h (coff_set_alignment_hook): Warn if the file lies about the number of relocations it contains. (coff_sort_func_alent): Return 0 if the pointers are NULL. (coff_slurp_line_table): Add more range checks. Do not free new tables created when sorting line numbers. * peXXigen.c (pe_print_idata): Add range checks. (pe_print_edata): Likewise. (rsrc_print_resource_entries): Likewise. Avoid printing control characters. Terminate priniting if corruption is detected. (rsrc_print_resource_directory): Terminate printing if an unknown directory type is encountered. (pe_print_debugdata): Fix off-by-one error. (rsrc_count_entries): Add range checking. (rsrc_parse_entry): Likewise.
This commit is contained in:
parent
1ae1b8cc65
commit
20ad5e2842
3 changed files with 129 additions and 39 deletions
|
@ -1,3 +1,21 @@
|
||||||
|
2014-11-05 Nick Clifton <nickc@redhat.com>
|
||||||
|
|
||||||
|
PR binutils/17512
|
||||||
|
* coffcode.h (coff_set_alignment_hook): Warn if the file lies
|
||||||
|
about the number of relocations it contains.
|
||||||
|
(coff_sort_func_alent): Return 0 if the pointers are NULL.
|
||||||
|
(coff_slurp_line_table): Add more range checks. Do not free new
|
||||||
|
tables created when sorting line numbers.
|
||||||
|
* peXXigen.c (pe_print_idata): Add range checks.
|
||||||
|
(pe_print_edata): Likewise.
|
||||||
|
(rsrc_print_resource_entries): Likewise. Avoid printing control
|
||||||
|
characters. Terminate priniting if corruption is detected.
|
||||||
|
(rsrc_print_resource_directory): Terminate printing if an unknown
|
||||||
|
directory type is encountered.
|
||||||
|
(pe_print_debugdata): Fix off-by-one error.
|
||||||
|
(rsrc_count_entries): Add range checking.
|
||||||
|
(rsrc_parse_entry): Likewise.
|
||||||
|
|
||||||
2014-11-04 Nick Clifton <nickc@redhat.com>
|
2014-11-04 Nick Clifton <nickc@redhat.com>
|
||||||
|
|
||||||
PR binutils/17512
|
PR binutils/17512
|
||||||
|
|
|
@ -1920,6 +1920,15 @@ coff_set_alignment_hook (bfd * abfd ATTRIBUTE_UNUSED,
|
||||||
if (bfd_seek (abfd, oldpos, 0) != 0)
|
if (bfd_seek (abfd, oldpos, 0) != 0)
|
||||||
return;
|
return;
|
||||||
section->reloc_count = hdr->s_nreloc = n.r_vaddr - 1;
|
section->reloc_count = hdr->s_nreloc = n.r_vaddr - 1;
|
||||||
|
/* PR binutils/17512: Stop corrupt files from causing
|
||||||
|
memory problems if they claim to have too many relocs. */
|
||||||
|
if (section->reloc_count * relsz > (bfd_size_type) bfd_get_size (abfd))
|
||||||
|
{
|
||||||
|
(*_bfd_error_handler)
|
||||||
|
("%s: warning: claims to have %#x relocs, but the file is not that big",
|
||||||
|
bfd_get_filename (abfd), section->reloc_count);
|
||||||
|
section->reloc_count = 0;
|
||||||
|
}
|
||||||
section->rel_filepos += relsz;
|
section->rel_filepos += relsz;
|
||||||
}
|
}
|
||||||
else if (hdr->s_nreloc == 0xffff)
|
else if (hdr->s_nreloc == 0xffff)
|
||||||
|
@ -4494,6 +4503,8 @@ coff_sort_func_alent (const void * arg1, const void * arg2)
|
||||||
const coff_symbol_type *s1 = (const coff_symbol_type *) (al1->u.sym);
|
const coff_symbol_type *s1 = (const coff_symbol_type *) (al1->u.sym);
|
||||||
const coff_symbol_type *s2 = (const coff_symbol_type *) (al2->u.sym);
|
const coff_symbol_type *s2 = (const coff_symbol_type *) (al2->u.sym);
|
||||||
|
|
||||||
|
if (s1 == NULL || s2 == NULL)
|
||||||
|
return 0;
|
||||||
if (s1->symbol.value < s2->symbol.value)
|
if (s1->symbol.value < s2->symbol.value)
|
||||||
return -1;
|
return -1;
|
||||||
else if (s1->symbol.value > s2->symbol.value)
|
else if (s1->symbol.value > s2->symbol.value)
|
||||||
|
@ -4518,7 +4529,9 @@ coff_slurp_line_table (bfd *abfd, asection *asect)
|
||||||
BFD_ASSERT (asect->lineno == NULL);
|
BFD_ASSERT (asect->lineno == NULL);
|
||||||
|
|
||||||
amt = ((bfd_size_type) asect->lineno_count + 1) * sizeof (alent);
|
amt = ((bfd_size_type) asect->lineno_count + 1) * sizeof (alent);
|
||||||
lineno_cache = (alent *) bfd_alloc (abfd, amt);
|
if (amt > (bfd_size_type) bfd_get_size (abfd))
|
||||||
|
return FALSE;
|
||||||
|
lineno_cache = (alent *) bfd_zalloc (abfd, amt);
|
||||||
if (lineno_cache == NULL)
|
if (lineno_cache == NULL)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
@ -4566,6 +4579,9 @@ coff_slurp_line_table (bfd *abfd, asection *asect)
|
||||||
((symndx + obj_raw_syments (abfd))
|
((symndx + obj_raw_syments (abfd))
|
||||||
->u.syment._n._n_n._n_zeroes));
|
->u.syment._n._n_n._n_zeroes));
|
||||||
cache_ptr->u.sym = (asymbol *) sym;
|
cache_ptr->u.sym = (asymbol *) sym;
|
||||||
|
if (sym == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (sym->lineno != NULL)
|
if (sym->lineno != NULL)
|
||||||
(*_bfd_error_handler)
|
(*_bfd_error_handler)
|
||||||
(_("%B: warning: duplicate line number information for `%s'"),
|
(_("%B: warning: duplicate line number information for `%s'"),
|
||||||
|
@ -4609,7 +4625,7 @@ coff_slurp_line_table (bfd *abfd, asection *asect)
|
||||||
|
|
||||||
/* Create the new sorted table. */
|
/* Create the new sorted table. */
|
||||||
amt = ((bfd_size_type) asect->lineno_count + 1) * sizeof (alent);
|
amt = ((bfd_size_type) asect->lineno_count + 1) * sizeof (alent);
|
||||||
n_lineno_cache = (alent *) bfd_alloc (abfd, amt);
|
n_lineno_cache = (alent *) bfd_zalloc (abfd, amt);
|
||||||
if (n_lineno_cache != NULL)
|
if (n_lineno_cache != NULL)
|
||||||
{
|
{
|
||||||
alent *n_cache_ptr = n_lineno_cache;
|
alent *n_cache_ptr = n_lineno_cache;
|
||||||
|
@ -4621,8 +4637,9 @@ coff_slurp_line_table (bfd *abfd, asection *asect)
|
||||||
|
|
||||||
/* Copy the function entry and update it. */
|
/* Copy the function entry and update it. */
|
||||||
*n_cache_ptr = *old_ptr;
|
*n_cache_ptr = *old_ptr;
|
||||||
sym = (coff_symbol_type *)n_cache_ptr->u.sym;
|
sym = (coff_symbol_type *) n_cache_ptr->u.sym;
|
||||||
sym->lineno = n_cache_ptr;
|
if (sym != NULL)
|
||||||
|
sym->lineno = n_cache_ptr;
|
||||||
n_cache_ptr++;
|
n_cache_ptr++;
|
||||||
old_ptr++;
|
old_ptr++;
|
||||||
|
|
||||||
|
@ -4633,7 +4650,8 @@ coff_slurp_line_table (bfd *abfd, asection *asect)
|
||||||
n_cache_ptr->line_number = 0;
|
n_cache_ptr->line_number = 0;
|
||||||
memcpy (lineno_cache, n_lineno_cache, amt);
|
memcpy (lineno_cache, n_lineno_cache, amt);
|
||||||
}
|
}
|
||||||
bfd_release (abfd, func_table);
|
/* PR binutils/17512: Do *not* free the func table
|
||||||
|
and new lineno cache - they are now being used. */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
122
bfd/peXXigen.c
122
bfd/peXXigen.c
|
@ -1466,6 +1466,9 @@ pe_print_idata (bfd * abfd, void * vfile)
|
||||||
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. */
|
||||||
|
else if (member - adj + 2 >= datasize)
|
||||||
|
fprintf (file, _("\t<corrupt: 0x%04lx>"), member);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int ordinal;
|
int ordinal;
|
||||||
|
@ -1498,6 +1501,9 @@ pe_print_idata (bfd * abfd, void * vfile)
|
||||||
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. */
|
||||||
|
else if (member - adj + 2 >= datasize)
|
||||||
|
fprintf (file, _("\t<corrupt: 0x%04lx>"), member);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int ordinal;
|
int ordinal;
|
||||||
|
@ -1765,19 +1771,23 @@ pe_print_edata (bfd * abfd, void * vfile)
|
||||||
(long) edt.num_names);
|
(long) edt.num_names);
|
||||||
else for (i = 0; i < edt.num_names; ++i)
|
else for (i = 0; i < edt.num_names; ++i)
|
||||||
{
|
{
|
||||||
bfd_vma name_ptr = bfd_get_32 (abfd,
|
bfd_vma name_ptr;
|
||||||
data +
|
bfd_vma ord;
|
||||||
edt.npt_addr
|
|
||||||
+ (i*4) - adj);
|
|
||||||
|
|
||||||
char *name = (char *) data + name_ptr - adj;
|
ord = bfd_get_16 (abfd, data + edt.ot_addr + (i * 2) - adj);
|
||||||
|
name_ptr = bfd_get_32 (abfd, data + edt.npt_addr + (i * 4) - adj);
|
||||||
|
|
||||||
bfd_vma ord = bfd_get_16 (abfd,
|
if ((name_ptr - adj) >= datasize)
|
||||||
data +
|
{
|
||||||
edt.ot_addr
|
fprintf (file, _("\t[%4ld] <corrupt offset: %lx>\n"),
|
||||||
+ (i*2) - adj);
|
(long) ord, (long) name_ptr);
|
||||||
fprintf (file,
|
}
|
||||||
"\t[%4ld] %s\n", (long) ord, name);
|
else
|
||||||
|
{
|
||||||
|
char * name = (char *) data + name_ptr - adj;
|
||||||
|
|
||||||
|
fprintf (file, "\t[%4ld] %s\n", (long) ord, name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free (data);
|
free (data);
|
||||||
|
@ -2217,6 +2227,12 @@ static bfd_byte *
|
||||||
rsrc_print_resource_directory (FILE * , bfd *, unsigned int, bfd_byte *,
|
rsrc_print_resource_directory (FILE * , bfd *, unsigned int, bfd_byte *,
|
||||||
rsrc_regions *, bfd_vma);
|
rsrc_regions *, bfd_vma);
|
||||||
|
|
||||||
|
/* Print the resource entry at DATA, with the text indented by INDENT.
|
||||||
|
Recusively calls rsrc_print_resource_directory to print the contents
|
||||||
|
of directory entries.
|
||||||
|
Returns the address of the end of the data associated with the entry
|
||||||
|
or section_end + 1 upon failure. */
|
||||||
|
|
||||||
static bfd_byte *
|
static bfd_byte *
|
||||||
rsrc_print_resource_entries (FILE * file,
|
rsrc_print_resource_entries (FILE * file,
|
||||||
bfd * abfd,
|
bfd * abfd,
|
||||||
|
@ -2233,7 +2249,7 @@ rsrc_print_resource_entries (FILE * file,
|
||||||
|
|
||||||
fprintf (file, _("%03x %*.s Entry: "), (int)(data - regions->section_start), indent, " ");
|
fprintf (file, _("%03x %*.s Entry: "), (int)(data - regions->section_start), indent, " ");
|
||||||
|
|
||||||
entry = (long) bfd_get_32 (abfd, data);
|
entry = (unsigned long) bfd_get_32 (abfd, data);
|
||||||
if (is_name)
|
if (is_name)
|
||||||
{
|
{
|
||||||
bfd_byte * name;
|
bfd_byte * name;
|
||||||
|
@ -2246,7 +2262,7 @@ rsrc_print_resource_entries (FILE * file,
|
||||||
else
|
else
|
||||||
name = regions->section_start + entry - rva_bias;
|
name = regions->section_start + entry - rva_bias;
|
||||||
|
|
||||||
if (name + 2 < regions->section_end)
|
if (name + 2 < regions->section_end && name > regions->section_start)
|
||||||
{
|
{
|
||||||
unsigned int len;
|
unsigned int len;
|
||||||
|
|
||||||
|
@ -2256,20 +2272,38 @@ rsrc_print_resource_entries (FILE * file,
|
||||||
len = bfd_get_16 (abfd, name);
|
len = bfd_get_16 (abfd, name);
|
||||||
|
|
||||||
fprintf (file, _("name: [val: %08lx len %d]: "), entry, len);
|
fprintf (file, _("name: [val: %08lx len %d]: "), entry, len);
|
||||||
|
|
||||||
if (name + 2 + len * 2 < regions->section_end)
|
if (name + 2 + len * 2 < regions->section_end)
|
||||||
{
|
{
|
||||||
/* This strange loop is to cope with multibyte characters. */
|
/* This strange loop is to cope with multibyte characters. */
|
||||||
while (len --)
|
while (len --)
|
||||||
{
|
{
|
||||||
|
char c;
|
||||||
|
|
||||||
name += 2;
|
name += 2;
|
||||||
fprintf (file, "%.1s", name);
|
c = * name;
|
||||||
|
/* Avoid printing control characters. */
|
||||||
|
if (c > 0 && c < 32)
|
||||||
|
fprintf (file, "^%c", c + 64);
|
||||||
|
else
|
||||||
|
fprintf (file, "%.1s", name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
fprintf (file, _("<corrupt string length: %#x>"), len);
|
{
|
||||||
|
fprintf (file, _("<corrupt string length: %#x>\n"), len);
|
||||||
|
/* PR binutils/17512: Do not try to continue decoding a
|
||||||
|
corrupted resource section. It is likely to end up with
|
||||||
|
reams of extraneous output. FIXME: We could probably
|
||||||
|
continue if we disable the printing of strings... */
|
||||||
|
return regions->section_end + 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
fprintf (file, _("<corrupt string offset: %#lx>"), entry);
|
{
|
||||||
|
fprintf (file, _("<corrupt string offset: %#lx>\n"), entry);
|
||||||
|
return regions->section_end + 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
fprintf (file, _("ID: %#08lx"), entry);
|
fprintf (file, _("ID: %#08lx"), entry);
|
||||||
|
@ -2278,9 +2312,16 @@ rsrc_print_resource_entries (FILE * file,
|
||||||
fprintf (file, _(", Value: %#08lx\n"), entry);
|
fprintf (file, _(", Value: %#08lx\n"), entry);
|
||||||
|
|
||||||
if (HighBitSet (entry))
|
if (HighBitSet (entry))
|
||||||
return rsrc_print_resource_directory (file, abfd, indent + 1,
|
{
|
||||||
regions->section_start + WithoutHighBit (entry),
|
data = regions->section_start + WithoutHighBit (entry);
|
||||||
regions, rva_bias);
|
if (data <= regions->section_start || data > regions->section_end)
|
||||||
|
return regions->section_end + 1;
|
||||||
|
|
||||||
|
/* FIXME: PR binutils/17512: A corrupt file could contain a loop
|
||||||
|
in the resource table. We need some way to detect this. */
|
||||||
|
return rsrc_print_resource_directory (file, abfd, indent + 1, data,
|
||||||
|
regions, rva_bias);
|
||||||
|
}
|
||||||
|
|
||||||
if (regions->section_start + entry + 16 >= regions->section_end)
|
if (regions->section_start + entry + 16 >= regions->section_end)
|
||||||
return regions->section_end + 1;
|
return regions->section_end + 1;
|
||||||
|
@ -2327,7 +2368,12 @@ rsrc_print_resource_directory (FILE * file,
|
||||||
case 0: fprintf (file, "Type"); break;
|
case 0: fprintf (file, "Type"); break;
|
||||||
case 2: fprintf (file, "Name"); break;
|
case 2: fprintf (file, "Name"); break;
|
||||||
case 4: fprintf (file, "Language"); break;
|
case 4: fprintf (file, "Language"); break;
|
||||||
default: fprintf (file, "<unknown>"); break;
|
default:
|
||||||
|
fprintf (file, _("<unknown directory type: %d>\n"), indent);
|
||||||
|
/* FIXME: For now we end the printing here. If in the
|
||||||
|
future more directory types are added to the RSRC spec
|
||||||
|
then we will need to change this. */
|
||||||
|
return regions->section_end + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf (file, _(" Table: Char: %d, Time: %08lx, Ver: %d/%d, Num Names: %d, IDs: %d\n"),
|
fprintf (file, _(" Table: Char: %d, Time: %08lx, Ver: %d/%d, Num Names: %d, IDs: %d\n"),
|
||||||
|
@ -2449,10 +2495,10 @@ rsrc_print_section (bfd * abfd, void * vfile)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (regions.strings_start != NULL)
|
if (regions.strings_start != NULL)
|
||||||
fprintf (file, " String table starts at %03x\n",
|
fprintf (file, " String table starts at offset: %#03x\n",
|
||||||
(int) (regions.strings_start - regions.section_start));
|
(int) (regions.strings_start - regions.section_start));
|
||||||
if (regions.resource_start != NULL)
|
if (regions.resource_start != NULL)
|
||||||
fprintf (file, " Resources start at %03xx\n",
|
fprintf (file, " Resources start at offset: %#03x\n",
|
||||||
(int) (regions.resource_start - regions.section_start));
|
(int) (regions.resource_start - regions.section_start));
|
||||||
|
|
||||||
free (regions.section_start);
|
free (regions.section_start);
|
||||||
|
@ -2547,7 +2593,7 @@ pe_print_debugdata (bfd * abfd, void * vfile)
|
||||||
|
|
||||||
_bfd_XXi_swap_debugdir_in (abfd, ext, &idd);
|
_bfd_XXi_swap_debugdir_in (abfd, ext, &idd);
|
||||||
|
|
||||||
if ((idd.Type) > IMAGE_NUMBEROF_DEBUG_TYPES)
|
if ((idd.Type) >= IMAGE_NUMBEROF_DEBUG_TYPES)
|
||||||
type_name = debug_type_names[0];
|
type_name = debug_type_names[0];
|
||||||
else
|
else
|
||||||
type_name = debug_type_names[idd.Type];
|
type_name = debug_type_names[idd.Type];
|
||||||
|
@ -2953,7 +2999,7 @@ rsrc_count_entries (bfd * abfd,
|
||||||
else
|
else
|
||||||
name = datastart + entry - rva_bias;
|
name = datastart + entry - rva_bias;
|
||||||
|
|
||||||
if (name + 2 >= dataend)
|
if (name + 2 >= dataend || name < datastart)
|
||||||
return dataend + 1;
|
return dataend + 1;
|
||||||
|
|
||||||
unsigned int len = bfd_get_16 (abfd, name);
|
unsigned int len = bfd_get_16 (abfd, name);
|
||||||
|
@ -2964,10 +3010,14 @@ rsrc_count_entries (bfd * abfd,
|
||||||
entry = (long) bfd_get_32 (abfd, data + 4);
|
entry = (long) bfd_get_32 (abfd, data + 4);
|
||||||
|
|
||||||
if (HighBitSet (entry))
|
if (HighBitSet (entry))
|
||||||
return rsrc_count_directory (abfd,
|
{
|
||||||
datastart,
|
data = datastart + WithoutHighBit (entry);
|
||||||
datastart + WithoutHighBit (entry),
|
|
||||||
dataend, rva_bias);
|
if (data <= datastart || data >= dataend)
|
||||||
|
return dataend + 1;
|
||||||
|
|
||||||
|
return rsrc_count_directory (abfd, datastart, data, dataend, rva_bias);
|
||||||
|
}
|
||||||
|
|
||||||
if (datastart + entry + 16 >= dataend)
|
if (datastart + entry + 16 >= dataend)
|
||||||
return dataend + 1;
|
return dataend + 1;
|
||||||
|
@ -3089,20 +3139,24 @@ rsrc_parse_entry (bfd * abfd,
|
||||||
|
|
||||||
if (is_name)
|
if (is_name)
|
||||||
{
|
{
|
||||||
/* FIXME: Add range checking ? */
|
bfd_byte * address;
|
||||||
|
|
||||||
if (HighBitSet (val))
|
if (HighBitSet (val))
|
||||||
{
|
{
|
||||||
val = WithoutHighBit (val);
|
val = WithoutHighBit (val);
|
||||||
|
|
||||||
entry->name_id.name.len = bfd_get_16 (abfd, datastart + val);
|
address = datastart + val;
|
||||||
entry->name_id.name.string = datastart + val + 2;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
entry->name_id.name.len = bfd_get_16 (abfd, datastart + val
|
address = datastart + val - rva_bias;
|
||||||
- rva_bias);
|
|
||||||
entry->name_id.name.string = datastart + val - rva_bias + 2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (address + 3 > dataend)
|
||||||
|
return dataend;
|
||||||
|
|
||||||
|
entry->name_id.name.len = bfd_get_16 (abfd, address);
|
||||||
|
entry->name_id.name.string = address + 2;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
entry->name_id.id = val;
|
entry->name_id.id = val;
|
||||||
|
|
Loading…
Reference in a new issue