Fixes for crashes running readelf.

PR binutils/17531
	* readelf.c (get_data): If the reason parameter is null, do not
	print any error messages.
	(get_32bit_section_headers): Verify section header entry size
	before reading in the section headers.
	(get_64bit_section_headers): Likewise.
	(process_section_headers): Pass FALSE to get_section_headers.
	(get_file_header): Pass TRUE to get_section_headers.
	(process_dynamic_section): Change an assert to an error message.
	(process_symbol_table): Handle corrupt histograms.
This commit is contained in:
Nick Clifton
2014-11-04 11:58:16 +00:00
parent e0f52461c2
commit 049b0c3a24
2 changed files with 96 additions and 33 deletions

View File

@ -1,3 +1,16 @@
2014-11-04 Nick Clifton <nickc@redhat.com>
PR binutils/17531
* readelf.c (get_data): If the reason parameter is null, do not
print any error messages.
(get_32bit_section_headers): Verify section header entry size
before reading in the section headers.
(get_64bit_section_headers): Likewise.
(process_section_headers): Pass FALSE to get_section_headers.
(get_file_header): Pass TRUE to get_section_headers.
(process_dynamic_section): Change an assert to an error message.
(process_symbol_table): Handle corrupt histograms.
2014-11-03 Nick Clifton <nickc@redhat.com> 2014-11-03 Nick Clifton <nickc@redhat.com>
PR binutils/17512 PR binutils/17512

View File

@ -316,8 +316,9 @@ get_data (void * var, FILE * file, long offset, size_t size, size_t nmemb,
if (fseek (file, archive_file_offset + offset, SEEK_SET)) if (fseek (file, archive_file_offset + offset, SEEK_SET))
{ {
error (_("Unable to seek to 0x%lx for %s\n"), if (reason)
(unsigned long) archive_file_offset + offset, reason); error (_("Unable to seek to 0x%lx for %s\n"),
(unsigned long) archive_file_offset + offset, reason);
return NULL; return NULL;
} }
@ -331,8 +332,9 @@ get_data (void * var, FILE * file, long offset, size_t size, size_t nmemb,
if (mvar == NULL) if (mvar == NULL)
{ {
error (_("Out of memory allocating 0x%lx bytes for %s\n"), if (reason)
(unsigned long)(size * nmemb), reason); error (_("Out of memory allocating 0x%lx bytes for %s\n"),
(unsigned long)(size * nmemb), reason);
return NULL; return NULL;
} }
@ -341,8 +343,9 @@ get_data (void * var, FILE * file, long offset, size_t size, size_t nmemb,
if (fread (mvar, size, nmemb, file) != nmemb) if (fread (mvar, size, nmemb, file) != nmemb)
{ {
error (_("Unable to read in 0x%lx bytes of %s\n"), if (reason)
(unsigned long)(size * nmemb), reason); error (_("Unable to read in 0x%lx bytes of %s\n"),
(unsigned long)(size * nmemb), reason);
if (mvar != var) if (mvar != var)
free (mvar); free (mvar);
return NULL; return NULL;
@ -4482,26 +4485,46 @@ offset_from_vma (FILE * file, bfd_vma vma, bfd_size_type size)
} }
static int /* Allocate memory and load the sections headers into the global pointer
get_32bit_section_headers (FILE * file, unsigned int num) SECTION_HEADERS. If PROBE is true, this is just a probe and we do not
generate any error messages if the load fails. */
static bfd_boolean
get_32bit_section_headers (FILE * file, bfd_boolean probe)
{ {
Elf32_External_Shdr * shdrs; Elf32_External_Shdr * shdrs;
Elf_Internal_Shdr * internal; Elf_Internal_Shdr * internal;
unsigned int i; unsigned int i;
unsigned int size = elf_header.e_shentsize;
unsigned int num = probe ? 1 : elf_header.e_shnum;
/* PR binutils/17531: Cope with unexpected section header sizes. */
if (size == 0 || num == 0)
return FALSE;
if (size < sizeof * shdrs)
{
if (! probe)
error (_("The e_shentsize field in the ELF header is less than the size of an ELF section header\n"));
return FALSE;
}
if (!probe && size > sizeof * shdrs)
warn (_("The e_shentsize field in the ELF header is larger than the size of an ELF section header\n"));
shdrs = (Elf32_External_Shdr *) get_data (NULL, file, elf_header.e_shoff, shdrs = (Elf32_External_Shdr *) get_data (NULL, file, elf_header.e_shoff,
elf_header.e_shentsize, num, size, num,
_("section headers")); probe ? NULL : _("section headers"));
if (!shdrs) if (shdrs == NULL)
return 0; return FALSE;
if (section_headers != NULL)
free (section_headers);
section_headers = (Elf_Internal_Shdr *) cmalloc (num, section_headers = (Elf_Internal_Shdr *) cmalloc (num,
sizeof (Elf_Internal_Shdr)); sizeof (Elf_Internal_Shdr));
if (section_headers == NULL) if (section_headers == NULL)
{ {
error (_("Out of memory\n")); if (!probe)
return 0; error (_("Out of memory\n"));
return FALSE;
} }
for (i = 0, internal = section_headers; for (i = 0, internal = section_headers;
@ -4521,30 +4544,45 @@ get_32bit_section_headers (FILE * file, unsigned int num)
} }
free (shdrs); free (shdrs);
return TRUE;
return 1;
} }
static int static bfd_boolean
get_64bit_section_headers (FILE * file, unsigned int num) get_64bit_section_headers (FILE * file, bfd_boolean probe)
{ {
Elf64_External_Shdr * shdrs; Elf64_External_Shdr * shdrs;
Elf_Internal_Shdr * internal; Elf_Internal_Shdr * internal;
unsigned int i; unsigned int i;
unsigned int size = elf_header.e_shentsize;
unsigned int num = probe ? 1 : elf_header.e_shnum;
/* PR binutils/17531: Cope with unexpected section header sizes. */
if (size == 0 || num == 0)
return FALSE;
if (size < sizeof * shdrs)
{
if (! probe)
error (_("The e_shentsize field in the ELF header is less than the size of an ELF section header\n"));
return FALSE;
}
if (! probe && size > sizeof * shdrs)
warn (_("The e_shentsize field in the ELF header is larger than the size of an ELF section header\n"));
shdrs = (Elf64_External_Shdr *) get_data (NULL, file, elf_header.e_shoff, shdrs = (Elf64_External_Shdr *) get_data (NULL, file, elf_header.e_shoff,
elf_header.e_shentsize, num, size, num,
_("section headers")); probe ? NULL : _("section headers"));
if (!shdrs) if (shdrs == NULL)
return 0; return FALSE;
if (section_headers != NULL)
free (section_headers);
section_headers = (Elf_Internal_Shdr *) cmalloc (num, section_headers = (Elf_Internal_Shdr *) cmalloc (num,
sizeof (Elf_Internal_Shdr)); sizeof (Elf_Internal_Shdr));
if (section_headers == NULL) if (section_headers == NULL)
{ {
error (_("Out of memory\n")); if (! probe)
return 0; error (_("Out of memory\n"));
return FALSE;
} }
for (i = 0, internal = section_headers; for (i = 0, internal = section_headers;
@ -4564,8 +4602,7 @@ get_64bit_section_headers (FILE * file, unsigned int num)
} }
free (shdrs); free (shdrs);
return TRUE;
return 1;
} }
static Elf_Internal_Sym * static Elf_Internal_Sym *
@ -4998,10 +5035,10 @@ process_section_headers (FILE * file)
if (is_32bit_elf) if (is_32bit_elf)
{ {
if (! get_32bit_section_headers (file, elf_header.e_shnum)) if (! get_32bit_section_headers (file, FALSE))
return 0; return 0;
} }
else if (! get_64bit_section_headers (file, elf_header.e_shnum)) else if (! get_64bit_section_headers (file, FALSE))
return 0; return 0;
/* Read in the string table, so that we have names to display. */ /* Read in the string table, so that we have names to display. */
@ -8236,7 +8273,11 @@ process_dynamic_section (FILE * file)
{ {
/* Note: these braces are necessary to avoid a syntax /* Note: these braces are necessary to avoid a syntax
error from the SunOS4 C compiler. */ error from the SunOS4 C compiler. */
assert (sizeof (Elf_External_Syminfo) == entry->d_un.d_val); /* PR binutils/17531: A corrupt file can trigger this test.
So do not use an assert, instead generate an error message. */
if (sizeof (Elf_External_Syminfo) != entry->d_un.d_val)
error (_("Bad value (%d) for SYMINENT entry"),
(int) entry->d_un.d_val);
} }
else if (entry->d_tag == DT_SYMINSZ) else if (entry->d_tag == DT_SYMINSZ)
syminsz = entry->d_un.d_val; syminsz = entry->d_un.d_val;
@ -10133,6 +10174,15 @@ process_symbol_table (FILE * file)
++nsyms; ++nsyms;
if (maxlength < ++lengths[hn]) if (maxlength < ++lengths[hn])
++maxlength; ++maxlength;
/* PR binutils/17531: A corrupt binary could contain broken
histogram data. Do not go into an infinite loop trying
to process it. */
if (chains[si] == si)
{
error (_("histogram chain links to itself\n"));
break;
}
} }
} }
@ -14466,9 +14516,9 @@ get_file_header (FILE * file)
/* There may be some extensions in the first section header. Don't /* There may be some extensions in the first section header. Don't
bomb if we can't read it. */ bomb if we can't read it. */
if (is_32bit_elf) if (is_32bit_elf)
get_32bit_section_headers (file, 1); get_32bit_section_headers (file, TRUE);
else else
get_64bit_section_headers (file, 1); get_64bit_section_headers (file, TRUE);
} }
return 1; return 1;