Package: binutils
Version: 2.16.1-2
Severity: important
Tags: patch

readelf -s currently segfaults on some mips libraries, notably
libnewt.so.0.51-so used in debian-installer:

hattusa:~/colo/binutils$ readelf -s libnewt.so.0.51-so

Symbol table '.dynsym' contains 186 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 000000d4     0 SECTION LOCAL  DEFAULT    1
     2: 00002410     0 SECTION LOCAL  DEFAULT    8
     3: 0000cd40     0 SECTION LOCAL  DEFAULT    9
     4: 0000d120     0 SECTION LOCAL  DEFAULT   10
     5: 0000d4d0     0 SECTION LOCAL  DEFAULT   11
     6: 0004d4e4     0 SECTION LOCAL  DEFAULT   12
     7: 0004d50c     0 SECTION LOCAL  DEFAULT   13
     8: 0004d810     0 SECTION LOCAL  DEFAULT   14
     9: 0004db50     0 SECTION LOCAL  DEFAULT   17
    10: 00002d88   132 FUNC    GLOBAL DEFAULT    8 newtRadiobutton
    11: 000063e0   240 FUNC    GLOBAL DEFAULT    8 newtLabel
    12: 0000a9fc    76 FUNC    GLOBAL DEFAULT    8 newtGetScreenSize
Segmentation fault

The appended patch (from upstream, by Jakub Jelinek, adjusted for the
revision in debian) fixes it.


Thiemo


--- binutils/readelf.c.orig     2005-04-20 20:43:36.000000000 +0200
+++ binutils/readelf.c  2005-07-15 00:23:05.000000000 +0200
@@ -206,7 +206,7 @@ unsigned int num_dump_sects = 0;
 #define DISASS_DUMP    (1 << 1)
 #define DEBUG_DUMP     (1 << 2)
 
-/* How to rpint a vma value.  */
+/* How to print a vma value.  */
 typedef enum print_mode
 {
   HEX,
@@ -286,11 +286,42 @@ warn (const char *message, ...)
 }
 
 static void *
-get_data (void *var, FILE *file, long offset, size_t size, const char *reason)
+cmalloc (size_t nmemb, size_t size)
+{
+  /* Check for overflow.  */
+  if (nmemb >= ~(size_t) 0 / size)
+    return NULL;
+  else
+    return malloc (nmemb * size);
+}
+
+static void *
+xcmalloc (size_t nmemb, size_t size)
+{
+  /* Check for overflow.  */
+  if (nmemb >= ~(size_t) 0 / size)
+    return NULL;
+  else
+    return xmalloc (nmemb * size);
+}
+
+static void *
+xcrealloc (void *ptr, size_t nmemb, size_t size)
+{
+  /* Check for overflow.  */
+  if (nmemb >= ~(size_t) 0 / size)
+    return NULL;
+  else
+    return xrealloc (ptr, nmemb * size);
+}
+
+static void *
+get_data (void *var, FILE *file, long offset, size_t size, size_t nmemb,
+         const char *reason)
 {
   void *mvar;
 
-  if (size == 0)
+  if (size == 0 || nmemb == 0)
     return NULL;
 
   if (fseek (file, archive_file_offset + offset, SEEK_SET))
@@ -303,19 +334,24 @@ get_data (void *var, FILE *file, long of
   mvar = var;
   if (mvar == NULL)
     {
-      mvar = malloc (size);
+      /* Check for overflow.  */
+      if (nmemb < (~(size_t) 0 - 1) / size)
+       /* + 1 so that we can '\0' terminate invalid string table sections.  */
+       mvar = malloc (size * nmemb + 1);
 
       if (mvar == NULL)
        {
          error (_("Out of memory allocating 0x%x bytes for %s\n"),
-                size, reason);
+                size * nmemb, reason);
          return NULL;
        }
+
+      ((char *) mvar)[size * nmemb] = '\0';
     }
 
-  if (fread (mvar, size, 1, file) != 1)
+  if (fread (mvar, size, nmemb, file) != nmemb)
     {
-      error (_("Unable to read in 0x%x bytes of %s\n"), size, reason);
+      error (_("Unable to read in 0x%x bytes of %s\n"), size * nmemb, reason);
       if (mvar != var)
        free (mvar);
       return NULL;
@@ -769,16 +805,17 @@ slurp_rela_relocs (FILE *file,
     {
       Elf32_External_Rela *erelas;
 
-      erelas = get_data (NULL, file, rel_offset, rel_size, _("relocs"));
+      erelas = get_data (NULL, file, rel_offset, 1, rel_size, _("relocs"));
       if (!erelas)
        return 0;
 
       nrelas = rel_size / sizeof (Elf32_External_Rela);
 
-      relas = malloc (nrelas * sizeof (Elf_Internal_Rela));
+      relas = cmalloc (nrelas, sizeof (Elf_Internal_Rela));
 
       if (relas == NULL)
        {
+         free (erelas);
          error (_("out of memory parsing relocs"));
          return 0;
        }
@@ -796,16 +833,17 @@ slurp_rela_relocs (FILE *file,
     {
       Elf64_External_Rela *erelas;
 
-      erelas = get_data (NULL, file, rel_offset, rel_size, _("relocs"));
+      erelas = get_data (NULL, file, rel_offset, 1, rel_size, _("relocs"));
       if (!erelas)
        return 0;
 
       nrelas = rel_size / sizeof (Elf64_External_Rela);
 
-      relas = malloc (nrelas * sizeof (Elf_Internal_Rela));
+      relas = cmalloc (nrelas, sizeof (Elf_Internal_Rela));
 
       if (relas == NULL)
        {
+         free (erelas);
          error (_("out of memory parsing relocs"));
          return 0;
        }
@@ -839,16 +877,17 @@ slurp_rel_relocs (FILE *file,
     {
       Elf32_External_Rel *erels;
 
-      erels = get_data (NULL, file, rel_offset, rel_size, _("relocs"));
+      erels = get_data (NULL, file, rel_offset, 1, rel_size, _("relocs"));
       if (!erels)
        return 0;
 
       nrels = rel_size / sizeof (Elf32_External_Rel);
 
-      rels = malloc (nrels * sizeof (Elf_Internal_Rela));
+      rels = cmalloc (nrels, sizeof (Elf_Internal_Rela));
 
       if (rels == NULL)
        {
+         free (erels);
          error (_("out of memory parsing relocs"));
          return 0;
        }
@@ -866,16 +905,17 @@ slurp_rel_relocs (FILE *file,
     {
       Elf64_External_Rel *erels;
 
-      erels = get_data (NULL, file, rel_offset, rel_size, _("relocs"));
+      erels = get_data (NULL, file, rel_offset, 1, rel_size, _("relocs"));
       if (!erels)
        return 0;
 
       nrels = rel_size / sizeof (Elf64_External_Rel);
 
-      rels = malloc (nrels * sizeof (Elf_Internal_Rela));
+      rels = cmalloc (nrels, sizeof (Elf_Internal_Rela));
 
       if (rels == NULL)
        {
+         free (erels);
          error (_("out of memory parsing relocs"));
          return 0;
        }
@@ -1293,7 +1333,7 @@ dump_relocations (FILE *file,
                }
              else if (strtab == NULL)
                printf (_("<string table index: %3ld>"), psym->st_name);
-             else if (psym->st_name > strtablen)
+             else if (psym->st_name >= strtablen)
                printf (_("<corrupt string table index: %3ld>"), psym->st_name);
              else
                print_symbol (22, strtab + psym->st_name);
@@ -3087,7 +3127,7 @@ get_32bit_program_headers (FILE *file, E
   unsigned int i;
 
   phdrs = get_data (NULL, file, elf_header.e_phoff,
-                   elf_header.e_phentsize * elf_header.e_phnum,
+                   elf_header.e_phentsize, elf_header.e_phnum,
                    _("program headers"));
   if (!phdrs)
     return 0;
@@ -3120,7 +3160,7 @@ get_64bit_program_headers (FILE *file, E
   unsigned int i;
 
   phdrs = get_data (NULL, file, elf_header.e_phoff,
-                   elf_header.e_phentsize * elf_header.e_phnum,
+                   elf_header.e_phentsize, elf_header.e_phnum,
                    _("program headers"));
   if (!phdrs)
     return 0;
@@ -3155,7 +3195,7 @@ get_program_headers (FILE *file)
   if (program_headers != NULL)
     return 1;
 
-  phdrs = malloc (elf_header.e_phnum * sizeof (Elf_Internal_Phdr));
+  phdrs = cmalloc (elf_header.e_phnum, sizeof (Elf_Internal_Phdr));
 
   if (phdrs == NULL)
     {
@@ -3368,13 +3408,11 @@ process_program_headers (FILE *file)
        putc ('\n', stdout);
     }
 
-  if (do_segments && section_headers != NULL)
+  if (do_segments && section_headers != NULL && string_table != NULL)
     {
       printf (_("\n Section to Segment mapping:\n"));
       printf (_("  Segment Sections...\n"));
 
-      assert (string_table != NULL);
-
       for (i = 0; i < elf_header.e_phnum; i++)
        {
          unsigned int j;
@@ -3452,11 +3490,11 @@ get_32bit_section_headers (FILE *file, u
   unsigned int i;
 
   shdrs = get_data (NULL, file, elf_header.e_shoff,
-                   elf_header.e_shentsize * num, _("section headers"));
+                   elf_header.e_shentsize, num, _("section headers"));
   if (!shdrs)
     return 0;
 
-  section_headers = malloc (num * sizeof (Elf_Internal_Shdr));
+  section_headers = cmalloc (num, sizeof (Elf_Internal_Shdr));
 
   if (section_headers == NULL)
     {
@@ -3493,11 +3531,11 @@ get_64bit_section_headers (FILE *file, u
   unsigned int i;
 
   shdrs = get_data (NULL, file, elf_header.e_shoff,
-                   elf_header.e_shentsize * num, _("section headers"));
+                   elf_header.e_shentsize, num, _("section headers"));
   if (!shdrs)
     return 0;
 
-  section_headers = malloc (num * sizeof (Elf_Internal_Shdr));
+  section_headers = cmalloc (num, sizeof (Elf_Internal_Shdr));
 
   if (section_headers == NULL)
     {
@@ -3536,7 +3574,7 @@ get_32bit_elf_symbols (FILE *file, Elf_I
   Elf_Internal_Sym *psym;
   unsigned int j;
 
-  esyms = get_data (NULL, file, section->sh_offset, section->sh_size,
+  esyms = get_data (NULL, file, section->sh_offset, 1, section->sh_size,
                    _("symbols"));
   if (!esyms)
     return NULL;
@@ -3547,7 +3585,7 @@ get_32bit_elf_symbols (FILE *file, Elf_I
          == (unsigned long) SECTION_HEADER_NUM (section - section_headers)))
     {
       shndx = get_data (NULL, file, symtab_shndx_hdr->sh_offset,
-                       symtab_shndx_hdr->sh_size, _("symtab shndx"));
+                       1, symtab_shndx_hdr->sh_size, _("symtab shndx"));
       if (!shndx)
        {
          free (esyms);
@@ -3556,7 +3594,7 @@ get_32bit_elf_symbols (FILE *file, Elf_I
     }
 
   number = section->sh_size / section->sh_entsize;
-  isyms = malloc (number * sizeof (Elf_Internal_Sym));
+  isyms = cmalloc (number, sizeof (Elf_Internal_Sym));
 
   if (isyms == NULL)
     {
@@ -3599,7 +3637,7 @@ get_64bit_elf_symbols (FILE *file, Elf_I
   Elf_Internal_Sym *psym;
   unsigned int j;
 
-  esyms = get_data (NULL, file, section->sh_offset, section->sh_size,
+  esyms = get_data (NULL, file, section->sh_offset, 1, section->sh_size,
                    _("symbols"));
   if (!esyms)
     return NULL;
@@ -3610,7 +3648,7 @@ get_64bit_elf_symbols (FILE *file, Elf_I
          == (unsigned long) SECTION_HEADER_NUM (section - section_headers)))
     {
       shndx = get_data (NULL, file, symtab_shndx_hdr->sh_offset,
-                       symtab_shndx_hdr->sh_size, _("symtab shndx"));
+                       1, symtab_shndx_hdr->sh_size, _("symtab shndx"));
       if (!shndx)
        {
          free (esyms);
@@ -3619,7 +3657,7 @@ get_64bit_elf_symbols (FILE *file, Elf_I
     }
 
   number = section->sh_size / section->sh_entsize;
-  isyms = malloc (number * sizeof (Elf_Internal_Sym));
+  isyms = cmalloc (number, sizeof (Elf_Internal_Sym));
 
   if (isyms == NULL)
     {
@@ -3729,17 +3767,17 @@ process_section_headers (FILE *file)
     return 0;
 
   /* Read in the string table, so that we have names to display.  */
-  section = SECTION_HEADER (elf_header.e_shstrndx);
-
-  if (section->sh_size != 0)
+  if (SECTION_HEADER_INDEX (elf_header.e_shstrndx) < elf_header.e_shnum)
     {
-      string_table = get_data (NULL, file, section->sh_offset,
-                              section->sh_size, _("string table"));
+      section = SECTION_HEADER (elf_header.e_shstrndx);
 
-      if (string_table == NULL)
-       return 0;
+      if (section->sh_size != 0)
+       {
+         string_table = get_data (NULL, file, section->sh_offset,
+                                  1, section->sh_size, _("string table"));
 
-      string_table_length = section->sh_size;
+         string_table_length = string_table != NULL ? section->sh_size : 0;
+       }
     }
 
   /* Scan the sections for the dynamic symbol table
@@ -3796,7 +3834,7 @@ process_section_headers (FILE *file)
            }
 
          dynamic_strings = get_data (NULL, file, section->sh_offset,
-                                     section->sh_size, _("dynamic strings"));
+                                     1, section->sh_size, _("dynamic 
strings"));
          dynamic_strings_length = section->sh_size;
        }
       else if (section->sh_type == SHT_SYMTAB_SHNDX)
@@ -3983,6 +4021,7 @@ process_section_groups (FILE *file)
   Elf_Internal_Shdr *symtab_sec, *strtab_sec;
   Elf_Internal_Sym *symtab;
   char *strtab;
+  size_t strtab_size;
 
   /* Don't process section groups unless needed.  */
   if (!do_unwind && !do_section_groups)
@@ -4039,6 +4078,7 @@ process_section_groups (FILE *file)
   strtab_sec = NULL;
   symtab = NULL;
   strtab = NULL;
+  strtab_size = 0;
   for (i = 0, section = section_headers, group = section_groups;
        i < elf_header.e_shnum;
        i++, section++)
@@ -4053,8 +4093,9 @@ process_section_groups (FILE *file)
          Elf_Internal_Sym *sym;
 
          /* Get the symbol table.  */
-         sec = SECTION_HEADER (section->sh_link);
-         if (sec->sh_type != SHT_SYMTAB)
+         if (SECTION_HEADER_INDEX (section->sh_link) >= elf_header.e_shnum
+             || ((sec = SECTION_HEADER (section->sh_link))->sh_type
+                 != SHT_SYMTAB))
            {
              error (_("Bad sh_link in group section `%s'\n"), name);
              continue;
@@ -4080,26 +4121,41 @@ process_section_groups (FILE *file)
                }
 
              group_name = SECTION_NAME (section_headers + sec_index);
+             strtab_sec = NULL;
+             if (strtab)
+               free (strtab);
              strtab = NULL;
+             strtab_size = 0;
            }
          else
            {
              /* Get the string table.  */
-             sec = SECTION_HEADER (symtab_sec->sh_link);
-             if (strtab_sec != sec)
+             if (SECTION_HEADER_INDEX (symtab_sec->sh_link)
+                 >= elf_header.e_shnum)
+               {
+                 strtab_sec = NULL;
+                 if (strtab)
+                   free (strtab);
+                 strtab = NULL;
+                 strtab_size = 0;
+               }
+             else if (strtab_sec
+                      != (sec = SECTION_HEADER (symtab_sec->sh_link)))
                {
                  strtab_sec = sec;
                  if (strtab)
                    free (strtab);
                  strtab = get_data (NULL, file, strtab_sec->sh_offset,
-                                    strtab_sec->sh_size,
+                                    1, strtab_sec->sh_size,
                                     _("string table"));
+                 strtab_size = strtab != NULL ? strtab_sec->sh_size : 0;
                }
-             group_name = strtab + sym->st_name;
+             group_name = sym->st_name < strtab_size
+                          ? strtab + sym->st_name : "<corrupt>";
            }
 
          start = get_data (NULL, file, section->sh_offset,
-                           section->sh_size, _("section data"));
+                           1, section->sh_size, _("section data"));
 
          indices = start;
          size = (section->sh_size / section->sh_entsize) - 1;
@@ -4126,7 +4182,7 @@ process_section_groups (FILE *file)
              if (section_headers_groups [SECTION_HEADER_INDEX (entry)]
                  != NULL)
                {
-                 if (entry)
+                 if (SECTION_HEADER_INDEX (entry))
                    {
                      error (_("section [%5u] already in group section 
[%5u]\n"),
                             entry,
@@ -4154,8 +4210,7 @@ process_section_groups (FILE *file)
              if (do_section_groups)
                {
                  sec = SECTION_HEADER (entry);
-                 printf ("   [%5u]   %s\n",
-                         entry, SECTION_NAME (sec));
+                 printf ("   [%5u]   %s\n", entry, SECTION_NAME (sec));
                }
 
              g = xmalloc (sizeof (struct group_list));
@@ -4286,12 +4341,14 @@ process_relocs (FILE *file)
 
              is_rela = section->sh_type == SHT_RELA;
 
-             if (section->sh_link)
+             if (section->sh_link
+                 && SECTION_HEADER_INDEX (section->sh_link)
+                    < elf_header.e_shnum)
                {
                  Elf_Internal_Shdr *symsec;
                  Elf_Internal_Sym *symtab;
                  unsigned long nsyms;
-                 unsigned long strtablen;
+                 unsigned long strtablen = 0;
                  char *strtab = NULL;
 
                  symsec = SECTION_HEADER (section->sh_link);
@@ -4301,11 +4358,16 @@ process_relocs (FILE *file)
                  if (symtab == NULL)
                    continue;
 
-                 strsec = SECTION_HEADER (symsec->sh_link);
+                 if (SECTION_HEADER_INDEX (symsec->sh_link)
+                     < elf_header.e_shnum)
+                   {
+                     strsec = SECTION_HEADER (symsec->sh_link);
 
-                 strtab = get_data (NULL, file, strsec->sh_offset,
-                                    strsec->sh_size, _("string table"));
-                 strtablen = strtab == NULL ? 0 : strsec->sh_size;
+                     strtab = get_data (NULL, file, strsec->sh_offset,
+                                        1, strsec->sh_size,
+                                        _("string table"));
+                     strtablen = strtab == NULL ? 0 : strsec->sh_size;
+                   }
 
                  dump_relocations (file, rel_offset, rel_size,
                                    symtab, nsyms, strtab, strtablen, is_rela);
@@ -4496,11 +4558,11 @@ slurp_ia64_unwind_table (FILE *file,
 
   /* Second, build the unwind table from the contents of the unwind section:  
*/
   size = sec->sh_size;
-  table = get_data (NULL, file, sec->sh_offset, size, _("unwind table"));
+  table = get_data (NULL, file, sec->sh_offset, 1, size, _("unwind table"));
   if (!table)
     return 0;
 
-  aux->table = xmalloc (size / (3 * eh_addr_size) * sizeof (aux->table[0]));
+  aux->table = xcmalloc (size / (3 * eh_addr_size), sizeof (aux->table[0]));
   tep = aux->table;
   for (tp = table; tp < table + size; tp += 3 * eh_addr_size, ++tep)
     {
@@ -4532,6 +4594,7 @@ slurp_ia64_unwind_table (FILE *file,
        ++relsec)
     {
       if (relsec->sh_type != SHT_RELA
+         || SECTION_HEADER_INDEX (relsec->sh_info) >= elf_header.e_shnum
          || SECTION_HEADER (relsec->sh_info) != sec)
        continue;
 
@@ -4597,15 +4660,16 @@ ia64_process_unwind (FILE *file)
 
   for (i = 0, sec = section_headers; i < elf_header.e_shnum; ++i, ++sec)
     {
-      if (sec->sh_type == SHT_SYMTAB)
+      if (sec->sh_type == SHT_SYMTAB
+         && SECTION_HEADER_INDEX (sec->sh_link) < elf_header.e_shnum)
        {
          aux.nsyms = sec->sh_size / sec->sh_entsize;
          aux.symtab = GET_ELF_SYMBOLS (file, sec);
 
          strsec = SECTION_HEADER (sec->sh_link);
-         aux.strtab_size = strsec->sh_size;
          aux.strtab = get_data (NULL, file, strsec->sh_offset,
-                                aux.strtab_size, _("string table"));
+                                1, strsec->sh_size, _("string table"));
+         aux.strtab_size = aux.strtab != NULL ? strsec->sh_size : 0;
        }
       else if (sec->sh_type == SHT_IA_64_UNWIND)
        unwcount++;
@@ -4686,7 +4750,7 @@ ia64_process_unwind (FILE *file)
        {
          aux.info_size = sec->sh_size;
          aux.info_addr = sec->sh_addr;
-         aux.info = get_data (NULL, file, sec->sh_offset, aux.info_size,
+         aux.info = get_data (NULL, file, sec->sh_offset, 1, aux.info_size,
                               _("unwind info"));
 
          printf (_("\nUnwind section "));
@@ -4876,13 +4940,13 @@ slurp_hppa_unwind_table (FILE *file,
   /* Second, build the unwind table from the contents of the unwind
      section.  */
   size = sec->sh_size;
-  table = get_data (NULL, file, sec->sh_offset, size, _("unwind table"));
+  table = get_data (NULL, file, sec->sh_offset, 1, size, _("unwind table"));
   if (!table)
     return 0;
 
   unw_ent_size = 2 * eh_addr_size + 8;
 
-  tep = aux->table = xmalloc (size / unw_ent_size * sizeof (aux->table[0]));
+  tep = aux->table = xcmalloc (size / unw_ent_size, sizeof (aux->table[0]));
 
   for (tp = table; tp < table + size; tp += (2 * eh_addr_size + 8), ++tep)
     {
@@ -4950,6 +5014,7 @@ slurp_hppa_unwind_table (FILE *file,
        ++relsec)
     {
       if (relsec->sh_type != SHT_RELA
+         || SECTION_HEADER_INDEX (relsec->sh_info) >= elf_header.e_shnum
          || SECTION_HEADER (relsec->sh_info) != sec)
        continue;
 
@@ -5013,19 +5078,21 @@ hppa_process_unwind (FILE *file)
 
   memset (& aux, 0, sizeof (aux));
 
-  assert (string_table != NULL);
+  if (string_table == NULL)
+    return 1;
 
   for (i = 0, sec = section_headers; i < elf_header.e_shnum; ++i, ++sec)
     {
-      if (sec->sh_type == SHT_SYMTAB)
+      if (sec->sh_type == SHT_SYMTAB
+         && SECTION_HEADER_INDEX (sec->sh_link) < elf_header.e_shnum)
        {
          aux.nsyms = sec->sh_size / sec->sh_entsize;
          aux.symtab = GET_ELF_SYMBOLS (file, sec);
 
          strsec = SECTION_HEADER (sec->sh_link);
-         aux.strtab_size = strsec->sh_size;
          aux.strtab = get_data (NULL, file, strsec->sh_offset,
-                                aux.strtab_size, _("string table"));
+                                1, strsec->sh_size, _("string table"));
+         aux.strtab_size = aux.strtab != NULL ? strsec->sh_size : 0;
        }
       else if (streq (SECTION_NAME (sec), ".PARISC.unwind"))
        unwsec = sec;
@@ -5241,7 +5308,7 @@ get_32bit_dynamic_section (FILE *file)
   Elf32_External_Dyn *edyn, *ext;
   Elf_Internal_Dyn *entry;
 
-  edyn = get_data (NULL, file, dynamic_addr, dynamic_size,
+  edyn = get_data (NULL, file, dynamic_addr, 1, dynamic_size,
                   _("dynamic section"));
   if (!edyn)
     return 0;
@@ -5258,7 +5325,7 @@ get_32bit_dynamic_section (FILE *file)
        break;
     }
 
-  dynamic_section = malloc (dynamic_nent * sizeof (*entry));
+  dynamic_section = cmalloc (dynamic_nent, sizeof (*entry));
   if (dynamic_section == NULL)
     {
       error (_("Out of memory\n"));
@@ -5285,7 +5352,7 @@ get_64bit_dynamic_section (FILE *file)
   Elf64_External_Dyn *edyn, *ext;
   Elf_Internal_Dyn *entry;
 
-  edyn = get_data (NULL, file, dynamic_addr, dynamic_size,
+  edyn = get_data (NULL, file, dynamic_addr, 1, dynamic_size,
                   _("dynamic section"));
   if (!edyn)
     return 0;
@@ -5302,7 +5369,7 @@ get_64bit_dynamic_section (FILE *file)
        break;
     }
 
-  dynamic_section = malloc (dynamic_nent * sizeof (*entry));
+  dynamic_section = cmalloc (dynamic_nent, sizeof (*entry));
   if (dynamic_section == NULL)
     {
       error (_("Out of memory\n"));
@@ -5460,7 +5527,7 @@ process_dynamic_section (FILE *file)
              continue;
            }
 
-         dynamic_strings = get_data (NULL, file, offset, str_tab_len,
+         dynamic_strings = get_data (NULL, file, offset, 1, str_tab_len,
                                      _("dynamic string table"));
          dynamic_strings_length = str_tab_len;
          break;
@@ -5495,8 +5562,8 @@ process_dynamic_section (FILE *file)
          Elf_Internal_Syminfo *syminfo;
 
          /* There is a syminfo section.  Read the data.  */
-         extsyminfo = get_data (NULL, file, dynamic_syminfo_offset, syminsz,
-                                _("symbol information"));
+         extsyminfo = get_data (NULL, file, dynamic_syminfo_offset, 1,
+                                syminsz, _("symbol information"));
          if (!extsyminfo)
            return 0;
 
@@ -5972,9 +6039,13 @@ process_version_sections (FILE *file)
            printf_vma (section->sh_addr);
            printf (_("  Offset: %#08lx  Link: %lx (%s)\n"),
                    (unsigned long) section->sh_offset, section->sh_link,
-                   SECTION_NAME (SECTION_HEADER (section->sh_link)));
+                   SECTION_HEADER_INDEX (section->sh_link)
+                   < elf_header.e_shnum
+                   ? SECTION_NAME (SECTION_HEADER (section->sh_link))
+                   : "<corrupt>");
 
-           edefs = get_data (NULL, file, section->sh_offset, section->sh_size,
+           edefs = get_data (NULL, file, section->sh_offset, 1,
+                             section->sh_size,
                              _("version definition section"));
            if (!edefs)
              break;
@@ -6061,9 +6132,13 @@ process_version_sections (FILE *file)
            printf_vma (section->sh_addr);
            printf (_("  Offset: %#08lx  Link to section: %ld (%s)\n"),
                    (unsigned long) section->sh_offset, section->sh_link,
-                   SECTION_NAME (SECTION_HEADER (section->sh_link)));
+                   SECTION_HEADER_INDEX (section->sh_link)
+                   < elf_header.e_shnum
+                   ? SECTION_NAME (SECTION_HEADER (section->sh_link))
+                   : "<corrupt>");
 
-           eneed = get_data (NULL, file, section->sh_offset, section->sh_size,
+           eneed = get_data (NULL, file, section->sh_offset, 1,
+                             section->sh_size,
                              _("version need section"));
            if (!eneed)
              break;
@@ -6143,16 +6218,23 @@ process_version_sections (FILE *file)
            Elf_Internal_Shdr *string_sec;
            long off;
 
+           if (SECTION_HEADER_INDEX (section->sh_link) >= elf_header.e_shnum)
+             break;
+
            link_section = SECTION_HEADER (section->sh_link);
            total = section->sh_size / section->sh_entsize;
 
+           if (SECTION_HEADER_INDEX (link_section->sh_link)
+               >= elf_header.e_shnum)
+             break;
+
            found = 1;
 
            symbols = GET_ELF_SYMBOLS (file, link_section);
 
            string_sec = SECTION_HEADER (link_section->sh_link);
 
-           strtab = get_data (NULL, file, string_sec->sh_offset,
+           strtab = get_data (NULL, file, string_sec->sh_offset, 1,
                               string_sec->sh_size, _("version string table"));
            if (!strtab)
              break;
@@ -6169,7 +6251,7 @@ process_version_sections (FILE *file)
            off = offset_from_vma (file,
                                   version_info[DT_VERSIONTAGIDX (DT_VERSYM)],
                                   total * sizeof (short));
-           edata = get_data (NULL, file, off, total * sizeof (short),
+           edata = get_data (NULL, file, off, total, sizeof (short),
                              _("version symbol data"));
            if (!edata)
              {
@@ -6177,7 +6259,7 @@ process_version_sections (FILE *file)
                break;
              }
 
-           data = malloc (total * sizeof (short));
+           data = cmalloc (total, sizeof (short));
 
            for (cnt = total; cnt --;)
              data[cnt] = byte_get (edata + cnt * sizeof (short),
@@ -6210,8 +6292,10 @@ process_version_sections (FILE *file)
 
                      check_def = 1;
                      check_need = 1;
-                     if (SECTION_HEADER (symbols[cnt + j].st_shndx)->sh_type
-                         != SHT_NOBITS)
+                     if (SECTION_HEADER_INDEX (symbols[cnt + j].st_shndx)
+                         >= elf_header.e_shnum
+                         || SECTION_HEADER (symbols[cnt + j].st_shndx)->sh_type
+                            != SHT_NOBITS)
                        {
                          if (symbols[cnt + j].st_shndx == SHN_UNDEF)
                            check_def = 0;
@@ -6236,7 +6320,7 @@ process_version_sections (FILE *file)
                              Elf_External_Vernaux evna;
                              unsigned long a_off;
 
-                             get_data (&evn, file, offset, sizeof (evn),
+                             get_data (&evn, file, offset, sizeof (evn), 1,
                                        _("version need"));
 
                              ivn.vn_aux  = BYTE_GET (evn.vn_aux);
@@ -6247,7 +6331,7 @@ process_version_sections (FILE *file)
                              do
                                {
                                  get_data (&evna, file, a_off, sizeof (evna),
-                                           _("version need aux (2)"));
+                                           1, _("version need aux (2)"));
 
                                  ivna.vna_next  = BYTE_GET (evna.vna_next);
                                  ivna.vna_other = BYTE_GET (evna.vna_other);
@@ -6288,7 +6372,7 @@ process_version_sections (FILE *file)
 
                          do
                            {
-                             get_data (&evd, file, offset, sizeof (evd),
+                             get_data (&evd, file, offset, sizeof (evd), 1,
                                        _("version def"));
 
                              ivd.vd_next = BYTE_GET (evd.vd_next);
@@ -6308,7 +6392,8 @@ process_version_sections (FILE *file)
 
                              get_data (&evda, file,
                                        offset - ivd.vd_next + ivd.vd_aux,
-                                       sizeof (evda), _("version def aux"));
+                                       sizeof (evda), 1,
+                                       _("version def aux"));
 
                              ivda.vda_name = BYTE_GET (evda.vda_name);
 
@@ -6460,7 +6545,7 @@ get_dynamic_data (FILE *file, unsigned i
   unsigned char *e_data;
   bfd_vma *i_data;
 
-  e_data = malloc (number * ent_size);
+  e_data = cmalloc (number, ent_size);
 
   if (e_data == NULL)
     {
@@ -6474,7 +6559,7 @@ get_dynamic_data (FILE *file, unsigned i
       return NULL;
     }
 
-  i_data = malloc (number * sizeof (*i_data));
+  i_data = cmalloc (number, sizeof (*i_data));
 
   if (i_data == NULL)
     {
@@ -6602,7 +6687,8 @@ process_symbol_table (FILE *file)
           i++, section++)
        {
          unsigned int si;
-         char *strtab;
+         char *strtab = NULL;
+         unsigned long int strtab_size = 0;
          Elf_Internal_Sym *symtab;
          Elf_Internal_Sym *psym;
 
@@ -6624,15 +6710,19 @@ process_symbol_table (FILE *file)
            continue;
 
          if (section->sh_link == elf_header.e_shstrndx)
-           strtab = string_table;
-         else
+           {
+             strtab = string_table;
+             strtab_size = string_table_length;
+           }
+         else if (SECTION_HEADER_INDEX (section->sh_link) < elf_header.e_shnum)
            {
              Elf_Internal_Shdr *string_sec;
 
              string_sec = SECTION_HEADER (section->sh_link);
 
              strtab = get_data (NULL, file, string_sec->sh_offset,
-                                string_sec->sh_size, _("string table"));
+                                1, string_sec->sh_size, _("string table"));
+             strtab_size = strtab != NULL ? string_sec->sh_size : 0;
            }
 
          for (si = 0, psym = symtab;
@@ -6647,7 +6737,8 @@ process_symbol_table (FILE *file)
              printf (" %-6s", get_symbol_binding (ELF_ST_BIND 
(psym->st_info)));
              printf (" %-3s", get_symbol_visibility (ELF_ST_VISIBILITY 
(psym->st_other)));
              printf (" %4s ", get_symbol_index_type (psym->st_shndx));
-             print_symbol (25, strtab + psym->st_name);
+             print_symbol (25, psym->st_name < strtab_size
+                           ? strtab + psym->st_name : "<corrupt>");
 
              if (section->sh_type == SHT_DYNSYM &&
                  version_info[DT_VERSIONTAGIDX (DT_VERSYM)] != 0)
@@ -6663,12 +6754,14 @@ process_symbol_table (FILE *file)
                     sizeof data + si * sizeof (vers_data));
 
                  get_data (&data, file, offset + si * sizeof (vers_data),
-                           sizeof (data), _("version data"));
+                           sizeof (data), 1, _("version data"));
 
                  vers_data = byte_get (data, 2);
 
-                 is_nobits = (SECTION_HEADER (psym->st_shndx)->sh_type
-                              == SHT_NOBITS);
+                 is_nobits = (SECTION_HEADER_INDEX (psym->st_shndx)
+                              < elf_header.e_shnum
+                              && SECTION_HEADER (psym->st_shndx)->sh_type
+                                 == SHT_NOBITS);
 
                  check_def = (psym->st_shndx != SHN_UNDEF);
 
@@ -6690,7 +6783,7 @@ process_symbol_table (FILE *file)
                            {
                              unsigned long vna_off;
 
-                             get_data (&evn, file, offset, sizeof (evn),
+                             get_data (&evn, file, offset, sizeof (evn), 1,
                                        _("version need"));
 
                              ivn.vn_aux  = BYTE_GET (evn.vn_aux);
@@ -6703,7 +6796,7 @@ process_symbol_table (FILE *file)
                                  Elf_External_Vernaux evna;
 
                                  get_data (&evna, file, vna_off,
-                                           sizeof (evna),
+                                           sizeof (evna), 1,
                                            _("version need aux (3)"));
 
                                  ivna.vna_other = BYTE_GET (evna.vna_other);
@@ -6725,7 +6818,9 @@ process_symbol_table (FILE *file)
                          if (ivna.vna_other == vers_data)
                            {
                              printf ("@%s (%d)",
-                                     strtab + ivna.vna_name, ivna.vna_other);
+                                     ivna.vna_name < strtab_size
+                                     ? strtab + ivna.vna_name : "<corrupt>",
+                                     ivna.vna_other);
                              check_def = 0;
                            }
                          else if (! is_nobits)
@@ -6754,7 +6849,7 @@ process_symbol_table (FILE *file)
                                  Elf_External_Verdef evd;
 
                                  get_data (&evd, file, offset, sizeof (evd),
-                                           _("version def"));
+                                           1, _("version def"));
 
                                  ivd.vd_ndx = BYTE_GET (evd.vd_ndx);
                                  ivd.vd_aux = BYTE_GET (evd.vd_aux);
@@ -6769,14 +6864,15 @@ process_symbol_table (FILE *file)
                              offset += ivd.vd_aux;
 
                              get_data (&evda, file, offset, sizeof (evda),
-                                       _("version def aux"));
+                                       1, _("version def aux"));
 
                              ivda.vda_name = BYTE_GET (evda.vda_name);
 
                              if (psym->st_name != ivda.vda_name)
                                printf ((vers_data & 0x8000)
                                        ? "@%s" : "@@%s",
-                                       strtab + ivda.vda_name);
+                                       ivda.vda_name < strtab_size
+                                       ? strtab + ivda.vda_name : "<corrupt>");
                            }
                        }
                    }
@@ -6961,7 +7057,8 @@ dump_section (Elf_Internal_Shdr *section
 
   addr = section->sh_addr;
 
-  start = get_data (NULL, file, section->sh_offset, bytes, _("section data"));
+  start = get_data (NULL, file, section->sh_offset, 1, bytes,
+                   _("section data"));
   if (!start)
     return 0;
 
@@ -7168,7 +7265,7 @@ load_debug_str (FILE *file)
 
   debug_str_size = sec->sh_size;
 
-  debug_str_contents = get_data (NULL, file, sec->sh_offset, sec->sh_size,
+  debug_str_contents = get_data (NULL, file, sec->sh_offset, 1, sec->sh_size,
                                 _("debug_str section data"));
 }
 
@@ -7214,7 +7311,7 @@ load_debug_loc (FILE *file)
 
   debug_loc_size = sec->sh_size;
 
-  debug_loc_contents = get_data (NULL, file, sec->sh_offset, sec->sh_size,
+  debug_loc_contents = get_data (NULL, file, sec->sh_offset, 1, sec->sh_size,
                                 _("debug_loc section data"));
 }
 
@@ -7248,7 +7345,7 @@ load_debug_range (FILE *file)
 
   debug_range_size = sec->sh_size;
 
-  debug_range_contents = get_data (NULL, file, sec->sh_offset, sec->sh_size,
+  debug_range_contents = get_data (NULL, file, sec->sh_offset, 1, sec->sh_size,
                                   _("debug_range section data"));
 }
 
@@ -7289,8 +7386,10 @@ debug_apply_rela_addends (FILE *file,
       Elf_Internal_Sym *sym;
 
       if (relsec->sh_type != SHT_RELA
+         || SECTION_HEADER_INDEX (relsec->sh_info) >= elf_header.e_shnum
          || SECTION_HEADER (relsec->sh_info) != section
-         || relsec->sh_size == 0)
+         || relsec->sh_size == 0
+         || SECTION_HEADER_INDEX (relsec->sh_link) >= elf_header.e_shnum)
        continue;
 
       if (!slurp_rela_relocs (file, relsec->sh_offset, relsec->sh_size,
@@ -8228,11 +8327,11 @@ read_and_display_attr_value (unsigned lo
                {
                  max += 1024;
                  debug_info_p->loc_offsets
-                   = xrealloc (debug_info_p->loc_offsets,
-                               max * sizeof (*debug_info_p->loc_offsets));
+                   = xcrealloc (debug_info_p->loc_offsets,
+                                max, sizeof (*debug_info_p->loc_offsets));
                  debug_info_p->have_frame_base
-                   = xrealloc (debug_info_p->have_frame_base,
-                               max * sizeof (*debug_info_p->have_frame_base));
+                   = xcrealloc (debug_info_p->have_frame_base,
+                                max, sizeof (*debug_info_p->have_frame_base));
                  debug_info_p->max_loc_offsets = max;
                }
              debug_info_p->loc_offsets [num] = uvalue;
@@ -8257,8 +8356,8 @@ read_and_display_attr_value (unsigned lo
                {
                  max += 1024;
                  debug_info_p->range_lists
-                   = xrealloc (debug_info_p->range_lists,
-                               max * sizeof (*debug_info_p->range_lists));
+                   = xcrealloc (debug_info_p->range_lists,
+                                max, sizeof (*debug_info_p->range_lists));
                  debug_info_p->max_range_lists = max;
                }
              debug_info_p->range_lists [num] = uvalue;
@@ -8633,8 +8732,8 @@ process_debug_info (Elf_Internal_Shdr *s
        }
 
       /* Then allocate an array to hold the information.  */
-      debug_information = malloc (num_units *
-                                 sizeof (* debug_information));
+      debug_information = cmalloc (num_units,
+                                  sizeof (* debug_information));
       if (debug_information == NULL)
        {
          error (_("Not enough memory for a debug info array of %u entries"),
@@ -8747,7 +8846,7 @@ process_debug_info (Elf_Internal_Shdr *s
            return 0;
          }
 
-       begin = get_data (NULL, file, sec->sh_offset, sec->sh_size,
+       begin = get_data (NULL, file, sec->sh_offset, 1, sec->sh_size,
                          _("debug_abbrev section data"));
        if (!begin)
          return 0;
@@ -8916,7 +9015,7 @@ get_debug_info (FILE * file)
   if (section == NULL)
     return 0;
 
-  start = get_data (NULL, file, section->sh_offset, section->sh_size,
+  start = get_data (NULL, file, section->sh_offset, 1, section->sh_size,
                    _("extracting information from .debug_info section"));
   if (start == NULL)
     return 0;
@@ -9529,8 +9628,22 @@ display_debug_loc (Elf_Internal_Shdr *se
            }
          start = next;
 
+         if (offset >= bytes)
+           {
+             warn (_("Offset 0x%lx is bigger than .debug_loc section size.\n"),
+                   offset);
+             continue;
+           }
+
          while (1)
            {
+             if (start + 2 * pointer_size > section_end)
+               {
+                 warn (_("Location list starting at offset 0x%lx is not 
terminated.\n"),
+                       offset);
+                 break;
+               }
+
              begin = byte_get (start, pointer_size);
              start += pointer_size;
              end = byte_get (start, pointer_size);
@@ -9546,14 +9659,28 @@ display_debug_loc (Elf_Internal_Shdr *se
              if (begin == -1UL && end != -1UL)
                {
                  base_address = end;
-                 printf ("    %8.8lx %8.8lx %8.8lx (base address)\n",
+                 printf (_("    %8.8lx %8.8lx %8.8lx (base address)\n"),
                          offset, begin, end);
                  continue;
                }
 
+             if (start + 2 > section_end)
+               {
+                 warn (_("Location list starting at offset 0x%lx is not 
terminated.\n"),
+                       offset);
+                 break;
+               }
+
              length = byte_get (start, 2);
              start += 2;
 
+             if (start + length > section_end)
+               {
+                 warn (_("Location list starting at offset 0x%lx is not 
terminated.\n"),
+                       offset);
+                 break;
+               }
+
              printf ("    %8.8lx %8.8lx %8.8lx (",
                      offset, begin + base_address, end + base_address);
              need_frame_base = decode_location_expression (start,
@@ -9926,8 +10053,8 @@ frame_need_space (Frame_Chunk *fc, int r
     return;
 
   fc->ncols = reg + 1;
-  fc->col_type = xrealloc (fc->col_type, fc->ncols * sizeof (short int));
-  fc->col_offset = xrealloc (fc->col_offset, fc->ncols * sizeof (int));
+  fc->col_type = xcrealloc (fc->col_type, fc->ncols, sizeof (short int));
+  fc->col_offset = xcrealloc (fc->col_offset, fc->ncols, sizeof (int));
 
   while (prev < fc->ncols)
     {
@@ -10237,8 +10364,8 @@ display_debug_frames (Elf_Internal_Shdr 
          else
            {
              fc->ncols = cie->ncols;
-             fc->col_type = xmalloc (fc->ncols * sizeof (short int));
-             fc->col_offset = xmalloc (fc->ncols * sizeof (int));
+             fc->col_type = xcmalloc (fc->ncols, sizeof (short int));
+             fc->col_offset = xcmalloc (fc->ncols, sizeof (int));
              memcpy (fc->col_type, cie->col_type, fc->ncols * sizeof (short 
int));
              memcpy (fc->col_offset, cie->col_offset, fc->ncols * sizeof 
(int));
              fc->augmentation = cie->augmentation;
@@ -10550,8 +10677,8 @@ display_debug_frames (Elf_Internal_Shdr 
                printf ("  DW_CFA_remember_state\n");
              rs = xmalloc (sizeof (Frame_Chunk));
              rs->ncols = fc->ncols;
-             rs->col_type = xmalloc (rs->ncols * sizeof (short int));
-             rs->col_offset = xmalloc (rs->ncols * sizeof (int));
+             rs->col_type = xcmalloc (rs->ncols, sizeof (short int));
+             rs->col_offset = xcmalloc (rs->ncols, sizeof (int));
              memcpy (rs->col_type, fc->col_type, rs->ncols);
              memcpy (rs->col_offset, fc->col_offset, rs->ncols * sizeof (int));
              rs->next = remembered_state;
@@ -10773,7 +10900,7 @@ display_debug_section (Elf_Internal_Shdr
       {
        unsigned char *start;
 
-       start = get_data (NULL, file, section->sh_offset, length,
+       start = get_data (NULL, file, section->sh_offset, 1, length,
                          _("debug section data"));
        if (start == NULL)
          {
@@ -10899,7 +11026,7 @@ process_mips_specific (FILE *file)
       size_t cnt;
 
       elib = get_data (NULL, file, liblist_offset,
-                      liblistno * sizeof (Elf32_External_Lib),
+                      liblistno, sizeof (Elf32_External_Lib),
                       _("liblist"));
       if (elib)
        {
@@ -10988,11 +11115,11 @@ process_mips_specific (FILE *file)
       while (sect->sh_type != SHT_MIPS_OPTIONS)
        ++sect;
 
-      eopt = get_data (NULL, file, options_offset, sect->sh_size,
+      eopt = get_data (NULL, file, options_offset, 1, sect->sh_size,
                       _("options"));
       if (eopt)
        {
-         iopt = malloc ((sect->sh_size / sizeof (eopt)) * sizeof (*iopt));
+         iopt = cmalloc ((sect->sh_size / sizeof (eopt)), sizeof (*iopt));
          if (iopt == NULL)
            {
              error (_("Out of memory"));
@@ -11184,7 +11311,7 @@ process_mips_specific (FILE *file)
          return 0;
        }
 
-      iconf = malloc (conflictsno * sizeof (*iconf));
+      iconf = cmalloc (conflictsno, sizeof (*iconf));
       if (iconf == NULL)
        {
          error (_("Out of memory"));
@@ -11196,7 +11323,7 @@ process_mips_specific (FILE *file)
          Elf32_External_Conflict *econf32;
 
          econf32 = get_data (NULL, file, conflicts_offset,
-                             conflictsno * sizeof (*econf32), _("conflict"));
+                             conflictsno, sizeof (*econf32), _("conflict"));
          if (!econf32)
            return 0;
 
@@ -11210,7 +11337,7 @@ process_mips_specific (FILE *file)
          Elf64_External_Conflict *econf64;
 
          econf64 = get_data (NULL, file, conflicts_offset,
-                             conflictsno * sizeof (*econf64), _("conflict"));
+                             conflictsno, sizeof (*econf64), _("conflict"));
          if (!econf64)
            return 0;
 
@@ -11250,6 +11377,7 @@ process_gnu_liblist (FILE *file)
   Elf_Internal_Shdr *section, *string_sec;
   Elf32_External_Lib *elib;
   char *strtab;
+  size_t strtab_size;
   size_t cnt;
   unsigned i;
 
@@ -11263,15 +11391,19 @@ process_gnu_liblist (FILE *file)
       switch (section->sh_type)
        {
        case SHT_GNU_LIBLIST:
-         elib = get_data (NULL, file, section->sh_offset, section->sh_size,
+         if (SECTION_HEADER_INDEX (section->sh_link) >= elf_header.e_shnum)
+           break;
+
+         elib = get_data (NULL, file, section->sh_offset, 1, section->sh_size,
                           _("liblist"));
 
          if (elib == NULL)
            break;
          string_sec = SECTION_HEADER (section->sh_link);
 
-         strtab = get_data (NULL, file, string_sec->sh_offset,
+         strtab = get_data (NULL, file, string_sec->sh_offset, 1,
                             string_sec->sh_size, _("liblist string table"));
+         strtab_size = string_sec->sh_size;
 
          if (strtab == NULL
              || section->sh_entsize != sizeof (Elf32_External_Lib))
@@ -11308,9 +11440,11 @@ process_gnu_liblist (FILE *file)
 
              printf ("%3lu: ", (unsigned long) cnt);
              if (do_wide)
-               printf ("%-20s", strtab + liblist.l_name);
+               printf ("%-20s", liblist.l_name < strtab_size
+                                ? strtab + liblist.l_name : "<corrupt>");
              else
-               printf ("%-20.20s", strtab + liblist.l_name);
+               printf ("%-20.20s", liblist.l_name < strtab_size
+                                   ? strtab + liblist.l_name : "<corrupt>");
              printf (" %s %#010lx %-7ld %-7ld\n", timebuf, liblist.l_checksum,
                      liblist.l_version, liblist.l_flags);
            }
@@ -11475,7 +11609,7 @@ process_corefile_note_segment (FILE *fil
   if (length <= 0)
     return 0;
 
-  pnotes = get_data (NULL, file, offset, length, _("notes"));
+  pnotes = get_data (NULL, file, offset, 1, length, _("notes"));
   if (!pnotes)
     return 0;
 


-- 
To UNSUBSCRIBE, email to [EMAIL PROTECTED]
with a subject of "unsubscribe". Trouble? Contact [EMAIL PROTECTED]

Reply via email to