/* Support for the generic parts of PE/PEI; the common executable parts.
- Copyright (C) 1995-2014 Free Software Foundation, Inc.
+ Copyright (C) 1995-2015 Free Software Foundation, Inc.
Written by Cygnus Solutions.
This file is part of BFD, the Binary File Descriptor library.
name = _bfd_coff_internal_syment_name (abfd, in, namebuf);
if (name == NULL)
- /* FIXME: Return error. */
- abort ();
+ {
+ _bfd_error_handler (_("%B: unable to find name for empty section"),
+ abfd);
+ bfd_set_error (bfd_error_invalid_target);
+ return;
+ }
+
sec = bfd_get_section_by_name (abfd, name);
if (sec != NULL)
in->n_scnum = sec->target_index;
{
name = (const char *) bfd_alloc (abfd, strlen (namebuf) + 1);
if (name == NULL)
- /* FIXME: Return error. */
- abort ();
+ {
+ _bfd_error_handler (_("%B: out of memory creating name for empty section"),
+ abfd);
+ return;
+ }
strcpy ((char *) name, namebuf);
}
+
flags = SEC_HAS_CONTENTS | SEC_ALLOC | SEC_DATA | SEC_LOAD;
sec = bfd_make_section_anyway_with_flags (abfd, name, flags);
if (sec == NULL)
- /* FIXME: Return error. */
- abort ();
+ {
+ _bfd_error_handler (_("%B: unable to create fake empty section"),
+ abfd);
+ return;
+ }
sec->vma = 0;
sec->lma = 0;
AUXENT *ext = (AUXENT *) ext1;
union internal_auxent *in = (union internal_auxent *) in1;
+ /* PR 17521: Make sure that all fields in the aux structure
+ are initialised. */
+ memset (in, 0, sizeof * in);
switch (in_class)
{
case C_FILE:
aouthdr_int->entry = GET_AOUTHDR_ENTRY (abfd, aouthdr_ext->entry);
aouthdr_int->text_start =
GET_AOUTHDR_TEXT_START (abfd, aouthdr_ext->text_start);
+
#if !defined(COFF_WITH_pep) && !defined(COFF_WITH_pex64)
/* PE32+ does not have data_start member! */
aouthdr_int->data_start =
{
int idx;
+ /* PR 17512: Corrupt PE binaries can cause seg-faults. */
+ if (a->NumberOfRvaAndSizes > IMAGE_NUMBEROF_DIRECTORY_ENTRIES)
+ {
+ (*_bfd_error_handler)
+ (_("%B: aout header specifies an invalid number of data-directory entries: %d"),
+ abfd, a->NumberOfRvaAndSizes);
+ /* Paranoia: If the number is corrupt, then assume that the
+ actual entries themselves might be corrupt as well. */
+ a->NumberOfRvaAndSizes = 0;
+ }
+
for (idx = 0; idx < a->NumberOfRvaAndSizes; idx++)
{
/* If data directory is empty, rva also should be 0. */
else
a->DataDirectory[idx].VirtualAddress = 0;
}
+
+ while (idx < IMAGE_NUMBEROF_DIRECTORY_ENTRIES)
+ {
+ a->DataDirectory[idx].Size = 0;
+ a->DataDirectory[idx].VirtualAddress = 0;
+ idx ++;
+ }
}
if (aouthdr_int->entry)
{
int idx;
- for (idx = 0; idx < 16; idx++)
+ for (idx = 0; idx < IMAGE_NUMBEROF_DIRECTORY_ENTRIES; idx++)
{
H_PUT_32 (abfd, extra->DataDirectory[idx].VirtualAddress,
aouthdr_out->DataDirectory[idx][0]);
break;
dll = (char *) data + dll_name - adj;
- fprintf (file, _("\n\tDLL Name: %s\n"), dll);
+ /* PR 17512 file: 078-12277-0.004. */
+ bfd_size_type maxlen = (char *)(data + datasize) - dll - 1;
+ fprintf (file, _("\n\tDLL Name: %.*s\n"), (int) maxlen, dll);
if (hint_addr != 0)
{
#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 (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 (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
}
}
+ /* PR 17512: Handle corrupt PE binaries. */
+ if (datasize < 36)
+ {
+ fprintf (file,
+ _("\nThere is an export table in %s, but it is too small (%d)\n"),
+ section->name, (int) datasize);
+ return TRUE;
+ }
+
fprintf (file, _("\nThere is an export table in %s at 0x%lx\n"),
section->name, (unsigned long) addr);
bfd_fprintf_vma (abfd, file, edt.name);
if ((edt.name >= adj) && (edt.name < adj + datasize))
- fprintf (file, " %s\n", data + edt.name - adj);
+ fprintf (file, " %.*s\n",
+ (int) (datasize - (edt.name - adj)),
+ data + edt.name - adj);
else
fprintf (file, "(outside .edata section)\n");
_("\nExport Address Table -- Ordinal Base %ld\n"),
edt.base);
- for (i = 0; i < edt.num_functions; ++i)
+ /* PR 17512: Handle corrupt PE binaries. */
+ if (edt.eat_addr + (edt.num_functions * 4) - adj >= datasize
+ /* PR 17512 file: 140-165018-0.004. */
+ || data + edt.eat_addr - adj < data)
+ fprintf (file, _("\tInvalid Export Address Table rva (0x%lx) or entry count (0x%lx)\n"),
+ (long) edt.eat_addr,
+ (long) edt.num_functions);
+ else for (i = 0; i < edt.num_functions; ++i)
{
bfd_vma eat_member = bfd_get_32 (abfd,
data + edt.eat_addr + (i * 4) - adj);
/* This rva is to a name (forwarding function) in our section. */
/* Should locate a function descriptor. */
fprintf (file,
- "\t[%4ld] +base[%4ld] %04lx %s -- %s\n",
+ "\t[%4ld] +base[%4ld] %04lx %s -- %.*s\n",
(long) i,
(long) (i + edt.base),
(unsigned long) eat_member,
_("Forwarder RVA"),
+ (int)(datasize - (eat_member - adj)),
data + eat_member - adj);
}
else
fprintf (file,
_("\n[Ordinal/Name Pointer] Table\n"));
- for (i = 0; i < edt.num_names; ++i)
+ /* PR 17512: Handle corrupt PE binaries. */
+ if (edt.npt_addr + (edt.num_names * 4) - adj >= datasize
+ || (data + edt.npt_addr - adj) < data)
+ fprintf (file, _("\tInvalid Name Pointer Table rva (0x%lx) or entry count (0x%lx)\n"),
+ (long) edt.npt_addr,
+ (long) edt.num_names);
+ /* PR 17512: file: 140-147171-0.004. */
+ else if (edt.ot_addr + (edt.num_names * 2) - adj >= datasize
+ || data + edt.ot_addr - adj < data)
+ fprintf (file, _("\tInvalid Ordinal Table rva (0x%lx) or entry count (0x%lx)\n"),
+ (long) edt.ot_addr,
+ (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,
+ (int)((char *)(data + datasize) - name), name);
+ }
}
free (data);
if (datasize == 0)
return TRUE;
+ /* PR 17512: file: 002-193900-0.004. */
+ if (datasize < stop)
+ {
+ fprintf (file, _("Virtual size of .pdata section (%ld) larger than real size (%ld)\n"),
+ (long) stop, (long) datasize);
+ return FALSE;
+ }
+
if (! bfd_malloc_and_get_section (abfd, section, &data))
{
if (data != NULL)
FILE *file = (FILE *) vfile;
bfd_byte *data = 0;
asection *section = bfd_get_section_by_name (abfd, ".reloc");
- bfd_size_type i;
- bfd_size_type start, stop;
+ bfd_byte *p, *end;
if (section == NULL || section->size == 0 || !(section->flags & SEC_HAS_CONTENTS))
return TRUE;
return FALSE;
}
- start = 0;
-
- stop = section->size;
-
- for (i = start; i < stop;)
+ p = data;
+ end = data + section->size;
+ while (p + 8 <= end)
{
int j;
bfd_vma virtual_address;
long number, size;
+ bfd_byte *chunk_end;
/* The .reloc section is a sequence of blocks, with a header consisting
of two 32 bit quantities, followed by a number of 16 bit entries. */
- virtual_address = bfd_get_32 (abfd, data+i);
- size = bfd_get_32 (abfd, data+i+4);
+ virtual_address = bfd_get_32 (abfd, p);
+ size = bfd_get_32 (abfd, p + 4);
+ p += 8;
number = (size - 8) / 2;
if (size == 0)
_("\nVirtual Address: %08lx Chunk size %ld (0x%lx) Number of fixups %ld\n"),
(unsigned long) virtual_address, size, (unsigned long) size, number);
- for (j = 0; j < number; ++j)
+ chunk_end = p + size;
+ if (chunk_end > end)
+ chunk_end = end;
+ j = 0;
+ while (p + 2 <= chunk_end)
{
- unsigned short e = bfd_get_16 (abfd, data + i + 8 + j * 2);
+ unsigned short e = bfd_get_16 (abfd, p);
unsigned int t = (e & 0xF000) >> 12;
int off = e & 0x0FFF;
_("\treloc %4d offset %4x [%4lx] %s"),
j, off, (unsigned long) (off + virtual_address), tbl[t]);
+ p += 2;
+ j++;
+
/* HIGHADJ takes an argument, - the next record *is* the
low 16 bits of addend. */
- if (t == IMAGE_REL_BASED_HIGHADJ)
+ if (t == IMAGE_REL_BASED_HIGHADJ && p + 2 <= chunk_end)
{
- fprintf (file, " (%4x)",
- ((unsigned int)
- bfd_get_16 (abfd, data + i + 8 + j * 2 + 2)));
+ fprintf (file, " (%4x)", (unsigned int) bfd_get_16 (abfd, p));
+ p += 2;
j++;
}
fprintf (file, "\n");
}
-
- i += size;
}
free (data);
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,
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;
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;
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);
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;
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"),
if (data == (regions.section_end - 4))
data = regions.section_end;
else if (data < regions.section_end)
- fprintf (file, _("\nWARNING: Extra data in .rsrc section - it will be ignored by Windows:\n"));
+ {
+ /* If the extra data is all zeros then do not complain.
+ This is just padding so that the section meets the
+ page size requirements. */
+ while (++ data < regions.section_end)
+ if (*data != 0)
+ break;
+ if (data < regions.section_end)
+ fprintf (file, _("\nWARNING: Extra data in .rsrc section - it will be ignored by Windows:\n"));
+ }
}
}
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);
section->name);
return TRUE;
}
+ else if (section->size < size)
+ {
+ fprintf (file,
+ _("\nError: section %s contains the debug data starting address but it is too small\n"),
+ section->name);
+ return FALSE;
+ }
fprintf (file, _("\nThere is a debug directory in %s at 0x%lx\n\n"),
section->name, (unsigned long) addr);
dataoff = addr - section->vma;
+ if (size > (section->size - dataoff))
+ {
+ fprintf (file, _("The debug data size field in the data directory is too big for the section"));
+ return FALSE;
+ }
+
fprintf (file,
_("Type Size Rva Offset\n"));
- /* Read the whole section. */
+ /* Read the whole section. */
if (!bfd_malloc_and_get_section (abfd, section, &data))
{
if (data != NULL)
_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];
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);
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;
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;
data = bfd_malloc (size);
if (data == NULL)
return;
+
datastart = data;
if (! bfd_get_section_contents (abfd, sec, data, 0, size))
for (input = pfinfo->info->input_bfds;
input != NULL;
- input = input->link_next)
+ input = input->link.next)
{
asection * rsrc_sec = bfd_get_section_by_name (input, ".rsrc");
starts on an 8-byte boundary. FIXME: Is this correct ? */
sizeof_strings = (sizeof_strings + 7) & ~ 7;
- new_data = bfd_malloc (size);
+ new_data = bfd_zalloc (abfd, size);
if (new_data == NULL)
goto end;
/* Step five: Replace the old contents with the new.
We recompute the size as we may have lost entries due to mergeing. */
size = ((write_data.next_data - new_data) + 3) & ~ 3;
+
+ {
+ int page_size;
+
+ if (coff_data (abfd)->link_info)
+ {
+ page_size = pe_data (abfd)->pe_opthdr.FileAlignment;
+
+ /* If no file alignment has been set, default to one.
+ This repairs 'ld -r' for arm-wince-pe target. */
+ if (page_size == 0)
+ page_size = 1;
+ }
+ else
+ page_size = PE_DEF_FILE_ALIGNMENT;
+ size = (size + page_size - 1) & - page_size;
+ }
+
bfd_set_section_contents (pfinfo->output_bfd, sec, new_data, 0, size);
sec->size = sec->rawsize = size;