Avoid allocating over-large buffers when parsing corrupt binaries.
authorNick Clifton <nickc@redhat.com>
Fri, 31 Oct 2014 16:36:31 +0000 (16:36 +0000)
committerNick Clifton <nickc@redhat.com>
Fri, 31 Oct 2014 16:36:31 +0000 (16:36 +0000)
PR binutils/17512
* coffgen.c (_bfd_coff_get_external_symbols): Do not try to load a
symbol table bigger than the file.
* elf.c (bfd_elf_get_str_section): Do not try to load a string
table bigger than the file.

* readelf.c (process_program_headers): Avoid memory exhaustion due
to corrupt values in a dynamis segment header.
(get_32bit_elf_symbols): Do not attempt to read an over-large
section.
(get_64bit_elf_symbols): Likewise.

bfd/ChangeLog
bfd/coffgen.c
bfd/elf.c
binutils/ChangeLog
binutils/readelf.c

index c15e8cb703dbe3fc0f7a5a1e275b8e5e1820dd03..accbcc953ebbf2b2a4c7d4b52de2eba26d144b9e 100644 (file)
@@ -1,3 +1,11 @@
+2014-10-31  Nick Clifton  <nickc@redhat.com>
+
+       PR binutils/17512
+       * coffgen.c (_bfd_coff_get_external_symbols): Do not try to load a
+       symbol table bigger than the file.
+       * elf.c (bfd_elf_get_str_section): Do not try to load a string
+       table bigger than the file.
+
 2014-10-30  Nick Clifton  <nickc@redhat.com>
 
        PR binutils/17512
index a1a032543e44e218dc4c69d5088dfe920c41326a..f18ddab346d7c53d2124f21aa4e4ab1e9e48f2df 100644 (file)
@@ -1616,6 +1616,11 @@ _bfd_coff_get_external_symbols (bfd *abfd)
   if (size == 0)
     return TRUE;
 
+  /* PR binutils/17512: Do not even try to load
+     a symbol table bigger than the entire file...  */
+  if (size >= (bfd_size_type) bfd_get_size (abfd))
+    return FALSE;
+
   syms = bfd_malloc (size);
   if (syms == NULL)
     return FALSE;
index 9c4dcdf452d1ab43c89d38b082214d0f694d3894..7cc0ce1fa6b8030d7b386da341270b3ecd5bceef 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -294,6 +294,11 @@ bfd_elf_get_str_section (bfd *abfd, unsigned int shindex)
       offset = i_shdrp[shindex]->sh_offset;
       shstrtabsize = i_shdrp[shindex]->sh_size;
 
+      /* PR binutils/17512: Do not even try to load
+        a string table bigger than the entire file...  */
+      if (shstrtabsize >= (bfd_size_type) bfd_get_size (abfd))
+       return NULL;
+
       /* Allocate and clear an extra byte at the end, to prevent crashes
         in case the string table is not terminated.  */
       if (shstrtabsize + 1 <= 1
index ec8a9e8be26ff6fcbde934272c6772b3b1a63e9a..993f15caaa22c156156077d1163776b83ee69d4d 100644 (file)
@@ -1,3 +1,12 @@
+2014-10-31  Nick Clifton  <nickc@redhat.com>
+
+       PR binutils/17512
+       * readelf.c (process_program_headers): Avoid memory exhaustion due
+       to corrupt values in a dynamis segment header.
+       (get_32bit_elf_symbols): Do not attempt to read an over-large
+       section.
+       (get_64bit_elf_symbols): Likewise.
+
 2014-10-31  Nick Clifton  <nickc@redhat.com>
 
        * strings.c: Add new command line option --data to only scan the
index aea02623c222236f97e6f91ec4adb20fddc9771f..6ddc078629bd86d3768719fe2f50acc2985d6b58 100644 (file)
 char * program_name = "readelf";
 static long archive_file_offset;
 static unsigned long archive_file_size;
+static bfd_size_type current_file_size;
 static unsigned long dynamic_addr;
 static bfd_size_type dynamic_size;
 static unsigned int dynamic_nent;
@@ -4341,6 +4342,9 @@ process_program_headers (FILE * file)
            }
        }
 
+      if (do_segments)
+       putc ('\n', stdout);
+
       switch (segment->p_type)
        {
        case PT_DYNAMIC:
@@ -4351,6 +4355,12 @@ process_program_headers (FILE * file)
             section in the DYNAMIC segment.  */
          dynamic_addr = segment->p_offset;
          dynamic_size = segment->p_filesz;
+         /* PR binutils/17512: Avoid corrupt dynamic section info in the segment.  */
+         if (dynamic_addr + dynamic_size >= current_file_size)
+           {
+             error (_("the dynamic segment offset + size exceeds the size of the file\n"));
+             dynamic_addr = dynamic_size = 0;
+           }
 
          /* Try to locate the .dynamic section. If there is
             a section header table, we can easily locate it.  */
@@ -4404,14 +4414,11 @@ process_program_headers (FILE * file)
                error (_("Unable to read program interpreter name\n"));
 
              if (do_segments)
-               printf (_("\n      [Requesting program interpreter: %s]"),
+               printf (_("      [Requesting program interpreter: %s]\n"),
                    program_interpreter);
            }
          break;
        }
-
-      if (do_segments)
-       putc ('\n', stdout);
     }
 
   if (do_segments && section_headers != NULL && string_table != NULL)
@@ -4580,6 +4587,13 @@ get_32bit_elf_symbols (FILE * file,
       goto exit_point;
     }
 
+  if (section->sh_size > current_file_size)
+    {
+      error (_("Section %s has an invalid sh_size of 0x%lx\n"),
+            SECTION_NAME (section), section->sh_size);
+      goto exit_point;
+    }
+
   number = section->sh_size / section->sh_entsize;
 
   if (number * sizeof (Elf32_External_Sym) > section->sh_size + 1)
@@ -4660,6 +4674,13 @@ get_64bit_elf_symbols (FILE * file,
       goto exit_point;
     }
 
+  if (section->sh_size > current_file_size)
+    {
+      error (_("Section %s has an invalid sh_size of 0x%lx\n"),
+            SECTION_NAME (section), section->sh_size);
+      goto exit_point;
+    }
+
   number = section->sh_size / section->sh_entsize;
 
   if (number * sizeof (Elf64_External_Sym) > section->sh_size + 1)
@@ -14886,6 +14907,8 @@ process_file (char * file_name)
       return 1;
     }
 
+  current_file_size = (bfd_size_type) statbuf.st_size;
+
   if (memcmp (armag, ARMAG, SARMAG) == 0)
     ret = process_archive (file_name, file, FALSE);
   else if (memcmp (armag, ARMAGT, SARMAG) == 0)
@@ -14903,6 +14926,7 @@ process_file (char * file_name)
 
   fclose (file);
 
+  current_file_size = 0;
   return ret;
 }