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
@ -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>
|
||||
|
||||
PR binutils/17512
|
||||
|
@ -1920,6 +1920,15 @@ coff_set_alignment_hook (bfd * abfd ATTRIBUTE_UNUSED,
|
||||
if (bfd_seek (abfd, oldpos, 0) != 0)
|
||||
return;
|
||||
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;
|
||||
}
|
||||
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 *s2 = (const coff_symbol_type *) (al2->u.sym);
|
||||
|
||||
if (s1 == NULL || s2 == NULL)
|
||||
return 0;
|
||||
if (s1->symbol.value < s2->symbol.value)
|
||||
return -1;
|
||||
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);
|
||||
|
||||
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)
|
||||
return FALSE;
|
||||
|
||||
@ -4566,6 +4579,9 @@ coff_slurp_line_table (bfd *abfd, asection *asect)
|
||||
((symndx + obj_raw_syments (abfd))
|
||||
->u.syment._n._n_n._n_zeroes));
|
||||
cache_ptr->u.sym = (asymbol *) sym;
|
||||
if (sym == NULL)
|
||||
continue;
|
||||
|
||||
if (sym->lineno != NULL)
|
||||
(*_bfd_error_handler)
|
||||
(_("%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. */
|
||||
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)
|
||||
{
|
||||
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. */
|
||||
*n_cache_ptr = *old_ptr;
|
||||
sym = (coff_symbol_type *)n_cache_ptr->u.sym;
|
||||
sym->lineno = n_cache_ptr;
|
||||
sym = (coff_symbol_type *) n_cache_ptr->u.sym;
|
||||
if (sym != NULL)
|
||||
sym->lineno = n_cache_ptr;
|
||||
n_cache_ptr++;
|
||||
old_ptr++;
|
||||
|
||||
@ -4633,7 +4650,8 @@ coff_slurp_line_table (bfd *abfd, asection *asect)
|
||||
n_cache_ptr->line_number = 0;
|
||||
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>",
|
||||
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
|
||||
{
|
||||
int ordinal;
|
||||
@ -1498,6 +1501,9 @@ pe_print_idata (bfd * abfd, void * vfile)
|
||||
if (HighBitSet (member))
|
||||
fprintf (file, "\t%04lx\t %4lu <none>",
|
||||
member, WithoutHighBit (member));
|
||||
/* PR binutils/17512: Handle corrupt PE data. */
|
||||
else if (member - adj + 2 >= datasize)
|
||||
fprintf (file, _("\t<corrupt: 0x%04lx>"), member);
|
||||
else
|
||||
{
|
||||
int ordinal;
|
||||
@ -1765,19 +1771,23 @@ pe_print_edata (bfd * abfd, void * vfile)
|
||||
(long) edt.num_names);
|
||||
else for (i = 0; i < edt.num_names; ++i)
|
||||
{
|
||||
bfd_vma name_ptr = bfd_get_32 (abfd,
|
||||
data +
|
||||
edt.npt_addr
|
||||
+ (i*4) - adj);
|
||||
bfd_vma name_ptr;
|
||||
bfd_vma ord;
|
||||
|
||||
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,
|
||||
data +
|
||||
edt.ot_addr
|
||||
+ (i*2) - adj);
|
||||
fprintf (file,
|
||||
"\t[%4ld] %s\n", (long) ord, name);
|
||||
if ((name_ptr - adj) >= datasize)
|
||||
{
|
||||
fprintf (file, _("\t[%4ld] <corrupt offset: %lx>\n"),
|
||||
(long) ord, (long) name_ptr);
|
||||
}
|
||||
else
|
||||
{
|
||||
char * name = (char *) data + name_ptr - adj;
|
||||
|
||||
fprintf (file, "\t[%4ld] %s\n", (long) ord, name);
|
||||
}
|
||||
}
|
||||
|
||||
free (data);
|
||||
@ -2217,6 +2227,12 @@ static bfd_byte *
|
||||
rsrc_print_resource_directory (FILE * , bfd *, unsigned int, bfd_byte *,
|
||||
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 *
|
||||
rsrc_print_resource_entries (FILE * file,
|
||||
bfd * abfd,
|
||||
@ -2233,7 +2249,7 @@ rsrc_print_resource_entries (FILE * file,
|
||||
|
||||
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)
|
||||
{
|
||||
bfd_byte * name;
|
||||
@ -2246,7 +2262,7 @@ rsrc_print_resource_entries (FILE * file,
|
||||
else
|
||||
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;
|
||||
|
||||
@ -2256,20 +2272,38 @@ rsrc_print_resource_entries (FILE * file,
|
||||
len = bfd_get_16 (abfd, name);
|
||||
|
||||
fprintf (file, _("name: [val: %08lx len %d]: "), entry, len);
|
||||
|
||||
if (name + 2 + len * 2 < regions->section_end)
|
||||
{
|
||||
/* This strange loop is to cope with multibyte characters. */
|
||||
while (len --)
|
||||
{
|
||||
char c;
|
||||
|
||||
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
|
||||
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
|
||||
fprintf (file, _("<corrupt string offset: %#lx>"), entry);
|
||||
{
|
||||
fprintf (file, _("<corrupt string offset: %#lx>\n"), entry);
|
||||
return regions->section_end + 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
fprintf (file, _("ID: %#08lx"), entry);
|
||||
@ -2278,9 +2312,16 @@ rsrc_print_resource_entries (FILE * file,
|
||||
fprintf (file, _(", Value: %#08lx\n"), entry);
|
||||
|
||||
if (HighBitSet (entry))
|
||||
return rsrc_print_resource_directory (file, abfd, indent + 1,
|
||||
regions->section_start + WithoutHighBit (entry),
|
||||
regions, rva_bias);
|
||||
{
|
||||
data = regions->section_start + WithoutHighBit (entry);
|
||||
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)
|
||||
return regions->section_end + 1;
|
||||
@ -2327,7 +2368,12 @@ rsrc_print_resource_directory (FILE * file,
|
||||
case 0: fprintf (file, "Type"); break;
|
||||
case 2: fprintf (file, "Name"); 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"),
|
||||
@ -2449,10 +2495,10 @@ rsrc_print_section (bfd * abfd, void * vfile)
|
||||
}
|
||||
|
||||
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));
|
||||
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));
|
||||
|
||||
free (regions.section_start);
|
||||
@ -2547,7 +2593,7 @@ pe_print_debugdata (bfd * abfd, void * vfile)
|
||||
|
||||
_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];
|
||||
else
|
||||
type_name = debug_type_names[idd.Type];
|
||||
@ -2953,7 +2999,7 @@ rsrc_count_entries (bfd * abfd,
|
||||
else
|
||||
name = datastart + entry - rva_bias;
|
||||
|
||||
if (name + 2 >= dataend)
|
||||
if (name + 2 >= dataend || name < datastart)
|
||||
return dataend + 1;
|
||||
|
||||
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);
|
||||
|
||||
if (HighBitSet (entry))
|
||||
return rsrc_count_directory (abfd,
|
||||
datastart,
|
||||
datastart + WithoutHighBit (entry),
|
||||
dataend, rva_bias);
|
||||
{
|
||||
data = datastart + WithoutHighBit (entry);
|
||||
|
||||
if (data <= datastart || data >= dataend)
|
||||
return dataend + 1;
|
||||
|
||||
return rsrc_count_directory (abfd, datastart, data, dataend, rva_bias);
|
||||
}
|
||||
|
||||
if (datastart + entry + 16 >= dataend)
|
||||
return dataend + 1;
|
||||
@ -3089,20 +3139,24 @@ rsrc_parse_entry (bfd * abfd,
|
||||
|
||||
if (is_name)
|
||||
{
|
||||
/* FIXME: Add range checking ? */
|
||||
bfd_byte * address;
|
||||
|
||||
if (HighBitSet (val))
|
||||
{
|
||||
val = WithoutHighBit (val);
|
||||
|
||||
entry->name_id.name.len = bfd_get_16 (abfd, datastart + val);
|
||||
entry->name_id.name.string = datastart + val + 2;
|
||||
address = datastart + val;
|
||||
}
|
||||
else
|
||||
{
|
||||
entry->name_id.name.len = bfd_get_16 (abfd, datastart + val
|
||||
- rva_bias);
|
||||
entry->name_id.name.string = datastart + val - rva_bias + 2;
|
||||
address = datastart + val - rva_bias;
|
||||
}
|
||||
|
||||
if (address + 3 > dataend)
|
||||
return dataend;
|
||||
|
||||
entry->name_id.name.len = bfd_get_16 (abfd, address);
|
||||
entry->name_id.name.string = address + 2;
|
||||
}
|
||||
else
|
||||
entry->name_id.id = val;
|
||||
|
Loading…
Reference in New Issue
Block a user