aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNick Clifton <nickc@redhat.com>2014-11-04 11:58:16 +0000
committerNick Clifton <nickc@redhat.com>2014-11-04 11:58:16 +0000
commit049b0c3a2467c785f9068915d81fdba4985470bf (patch)
tree65d2a6eeaf2ddeb0125c9cac82a819a6015a8d64
parente0f52461c2467b6610391681fa27cd9b3c5def57 (diff)
downloadgdb-049b0c3a2467c785f9068915d81fdba4985470bf.zip
gdb-049b0c3a2467c785f9068915d81fdba4985470bf.tar.gz
gdb-049b0c3a2467c785f9068915d81fdba4985470bf.tar.bz2
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.
-rw-r--r--binutils/ChangeLog13
-rw-r--r--binutils/readelf.c116
2 files changed, 96 insertions, 33 deletions
diff --git a/binutils/ChangeLog b/binutils/ChangeLog
index 1f551dd..0815bb8 100644
--- a/binutils/ChangeLog
+++ b/binutils/ChangeLog
@@ -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>
PR binutils/17512
diff --git a/binutils/readelf.c b/binutils/readelf.c
index 8560555..a283345 100644
--- a/binutils/readelf.c
+++ b/binutils/readelf.c
@@ -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))
{
- error (_("Unable to seek to 0x%lx for %s\n"),
- (unsigned long) archive_file_offset + offset, reason);
+ if (reason)
+ error (_("Unable to seek to 0x%lx for %s\n"),
+ (unsigned long) archive_file_offset + offset, reason);
return NULL;
}
@@ -331,8 +332,9 @@ get_data (void * var, FILE * file, long offset, size_t size, size_t nmemb,
if (mvar == NULL)
{
- error (_("Out of memory allocating 0x%lx bytes for %s\n"),
- (unsigned long)(size * nmemb), reason);
+ if (reason)
+ error (_("Out of memory allocating 0x%lx bytes for %s\n"),
+ (unsigned long)(size * nmemb), reason);
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)
{
- error (_("Unable to read in 0x%lx bytes of %s\n"),
- (unsigned long)(size * nmemb), reason);
+ if (reason)
+ error (_("Unable to read in 0x%lx bytes of %s\n"),
+ (unsigned long)(size * nmemb), reason);
if (mvar != var)
free (mvar);
return NULL;
@@ -4482,26 +4485,46 @@ offset_from_vma (FILE * file, bfd_vma vma, bfd_size_type size)
}
-static int
-get_32bit_section_headers (FILE * file, unsigned int num)
+/* Allocate memory and load the sections headers into the global pointer
+ 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;
Elf_Internal_Shdr * internal;
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,
- elf_header.e_shentsize, num,
- _("section headers"));
- if (!shdrs)
- return 0;
+ size, num,
+ probe ? NULL : _("section headers"));
+ if (shdrs == NULL)
+ return FALSE;
+ if (section_headers != NULL)
+ free (section_headers);
section_headers = (Elf_Internal_Shdr *) cmalloc (num,
sizeof (Elf_Internal_Shdr));
-
if (section_headers == NULL)
{
- error (_("Out of memory\n"));
- return 0;
+ if (!probe)
+ error (_("Out of memory\n"));
+ return FALSE;
}
for (i = 0, internal = section_headers;
@@ -4521,30 +4544,45 @@ get_32bit_section_headers (FILE * file, unsigned int num)
}
free (shdrs);
-
- return 1;
+ return TRUE;
}
-static int
-get_64bit_section_headers (FILE * file, unsigned int num)
+static bfd_boolean
+get_64bit_section_headers (FILE * file, bfd_boolean probe)
{
Elf64_External_Shdr * shdrs;
Elf_Internal_Shdr * internal;
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,
- elf_header.e_shentsize, num,
- _("section headers"));
- if (!shdrs)
- return 0;
+ size, num,
+ probe ? NULL : _("section headers"));
+ if (shdrs == NULL)
+ return FALSE;
+ if (section_headers != NULL)
+ free (section_headers);
section_headers = (Elf_Internal_Shdr *) cmalloc (num,
sizeof (Elf_Internal_Shdr));
-
if (section_headers == NULL)
{
- error (_("Out of memory\n"));
- return 0;
+ if (! probe)
+ error (_("Out of memory\n"));
+ return FALSE;
}
for (i = 0, internal = section_headers;
@@ -4564,8 +4602,7 @@ get_64bit_section_headers (FILE * file, unsigned int num)
}
free (shdrs);
-
- return 1;
+ return TRUE;
}
static Elf_Internal_Sym *
@@ -4998,10 +5035,10 @@ process_section_headers (FILE * file)
if (is_32bit_elf)
{
- if (! get_32bit_section_headers (file, elf_header.e_shnum))
+ if (! get_32bit_section_headers (file, FALSE))
return 0;
}
- else if (! get_64bit_section_headers (file, elf_header.e_shnum))
+ else if (! get_64bit_section_headers (file, FALSE))
return 0;
/* 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
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)
syminsz = entry->d_un.d_val;
@@ -10133,6 +10174,15 @@ process_symbol_table (FILE * file)
++nsyms;
if (maxlength < ++lengths[hn])
++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
bomb if we can't read it. */
if (is_32bit_elf)
- get_32bit_section_headers (file, 1);
+ get_32bit_section_headers (file, TRUE);
else
- get_64bit_section_headers (file, 1);
+ get_64bit_section_headers (file, TRUE);
}
return 1;