Add more fixes for inavlid memory accesses triggered by corrupt files.
authorNick Clifton <nickc@redhat.com>
Fri, 7 Nov 2014 13:39:45 +0000 (13:39 +0000)
committerNick Clifton <nickc@redhat.com>
Fri, 7 Nov 2014 13:39:45 +0000 (13:39 +0000)
PR binutils/17531
* readelf.c (get_data): Avoid allocating memory when we know that
the read will fail.
(find_section_by_type): New function.
(get_unwind_section_word): Check for invalid symbol indicies.
Check for invalid reloc types.
(get_32bit_dynamic_section): Add range checks.
(get_64bit_dynamic_section): Add range checks.
(process_dynamic_section): Check for a corrupt time value.
(process_symbol_table): Add range checks.
(dump_section_as_strings): Add string length range checks.
(display_tag_value): Likewise.
(display_arm_attribute): Likewise.
(display_gnu_attribute): Likewise.
(display_tic6x_attribute): Likewise.
(display_msp430x_attribute): Likewise.
(process_mips_specific): Add range check.

binutils/ChangeLog
binutils/readelf.c

index 6a04543..b0c6bb2 100644 (file)
@@ -1,3 +1,23 @@
+2014-11-07  Nick Clifton  <nickc@redhat.com>
+
+       PR binutils/17531
+       * readelf.c (get_data): Avoid allocating memory when we know that
+       the read will fail.
+       (find_section_by_type): New function.
+       (get_unwind_section_word): Check for invalid symbol indicies.
+       Check for invalid reloc types.
+       (get_32bit_dynamic_section): Add range checks.
+       (get_64bit_dynamic_section): Add range checks.
+       (process_dynamic_section): Check for a corrupt time value.
+       (process_symbol_table): Add range checks.
+       (dump_section_as_strings): Add string length range checks.
+       (display_tag_value): Likewise.
+       (display_arm_attribute): Likewise.
+       (display_gnu_attribute): Likewise.
+       (display_tic6x_attribute): Likewise.
+       (display_msp430x_attribute): Likewise.
+       (process_mips_specific): Add range check.
+
 2014-11-06  Nick Clifton  <nickc@redhat.com>
 
        PR binutils/17552, binutils/17533
index 089ea13..5bd3a4b 100644 (file)
@@ -322,6 +322,16 @@ get_data (void * var, FILE * file, long offset, size_t size, size_t nmemb,
       return NULL;
     }
 
+  /* Be kind to memory chekers (eg valgrind, address sanitizer) by not
+     attempting to allocate memory when the read is bound to fail.  */
+  if (offset + archive_file_offset + size * nmemb > current_file_size)
+    {
+      if (reason)
+       error (_("Reading 0x%lx bytes extends past end of file for %s\n"),
+              (unsigned long) (size * nmemb), reason);
+      return NULL;
+    }
+
   mvar = var;
   if (mvar == NULL)
     {
@@ -587,6 +597,21 @@ find_section_by_address (bfd_vma addr)
   return NULL;
 }
 
+static Elf_Internal_Shdr *
+find_section_by_type (unsigned int type)
+{
+  unsigned int i;
+
+  for (i = 0; i < elf_header.e_shnum; i++)
+    {
+      Elf_Internal_Shdr *sec = section_headers + i;
+      if (sec->sh_type == type)
+       return sec;
+    }
+
+  return NULL;
+}
+
 /* Return a pointer to section NAME, or NULL if no such section exists,
    restricted to the list of sections given in SET.  */
 
@@ -5722,9 +5747,10 @@ process_section_groups (FILE * file)
                  strtab_sec = sec;
                  if (strtab)
                    free (strtab);
+
                  strtab = (char *) get_data (NULL, file, strtab_sec->sh_offset,
-                                              1, strtab_sec->sh_size,
-                                              _("string table"));
+                                             1, strtab_sec->sh_size,
+                                             _("string table"));
                  strtab_size = strtab != NULL ? strtab_sec->sh_size : 0;
                }
              group_name = sym->st_name < strtab_size
@@ -6135,8 +6161,8 @@ process_relocs (FILE * file)
                      strsec = section_headers + symsec->sh_link;
 
                      strtab = (char *) get_data (NULL, file, strsec->sh_offset,
-                                                  1, strsec->sh_size,
-                                                  _("string table"));
+                                                 1, strsec->sh_size,
+                                                 _("string table"));
                      strtablen = strtab == NULL ? 0 : strsec->sh_size;
                    }
 
@@ -7067,8 +7093,6 @@ get_unwind_section_word (struct arm_unw_aux_info *  aux,
       if (aux->symtab == NULL)
        continue;
 
-      sym = aux->symtab + ELF32_R_SYM (rp->r_info);
-
       if (arm_sec->rel_type == SHT_REL)
        {
          offset = word & 0x7fffffff;
@@ -7084,6 +7108,15 @@ get_unwind_section_word (struct arm_unw_aux_info *  aux,
          break;
        }
 
+      /* PR 17531 file: 027-1241568-0.004.  */
+      if (ELF32_R_SYM (rp->r_info) >= aux->nsyms)
+       {
+         error (_("Bad symbol index in unwind relocation (%lu > %lu)\n"),
+                (unsigned long) ELF32_R_SYM (rp->r_info), aux->nsyms);
+         break;
+       }
+
+      sym = aux->symtab + ELF32_R_SYM (rp->r_info);
       offset += sym->st_value;
       prelval = offset - (arm_sec->sec->sh_addr + rp->r_offset);
 
@@ -7091,26 +7124,38 @@ get_unwind_section_word (struct arm_unw_aux_info *  aux,
       if (elf_header.e_machine == EM_ARM)
        {
          relname = elf_arm_reloc_type (ELF32_R_TYPE (rp->r_info));
+         if (relname == NULL)
+           {
+             warn (_("Skipping unknown ARM relocation type: %d\n"),
+                   (int) ELF32_R_TYPE (rp->r_info));
+             continue;
+           }
 
          if (streq (relname, "R_ARM_NONE"))
              continue;
 
          if (! streq (relname, "R_ARM_PREL31"))
            {
-             warn (_("Skipping unexpected relocation type %s\n"), relname);
+             warn (_("Skipping unexpected ARM relocation type %s\n"), relname);
              continue;
            }
        }
       else if (elf_header.e_machine == EM_TI_C6000)
        {
          relname = elf_tic6x_reloc_type (ELF32_R_TYPE (rp->r_info));
+         if (relname == NULL)
+           {
+             warn (_("Skipping unknown C6000 relocation type: %d\n"),
+                   (int) ELF32_R_TYPE (rp->r_info));
+             continue;
+           }
 
          if (streq (relname, "R_C6000_NONE"))
            continue;
 
          if (! streq (relname, "R_C6000_PREL31"))
            {
-             warn (_("Skipping unexpected relocation type %s\n"), relname);
+             warn (_("Skipping unexpected C6000 relocation type %s\n"), relname);
              continue;
            }
 
@@ -8133,11 +8178,11 @@ get_32bit_dynamic_section (FILE * file)
   if (!edyn)
     return 0;
 
-/* SGI's ELF has more than one section in the DYNAMIC segment, and we
-   might not have the luxury of section headers.  Look for the DT_NULL
-   terminator to determine the number of entries.  */
+  /* SGI's ELF has more than one section in the DYNAMIC segment, and we
+     might not have the luxury of section headers.  Look for the DT_NULL
+     terminator to determine the number of entries.  */
   for (ext = edyn, dynamic_nent = 0;
-       (char *) ext < (char *) edyn + dynamic_size;
+       (char *) ext < (char *) edyn + dynamic_size - sizeof (* entry);
        ext++)
     {
       dynamic_nent++;
@@ -8174,16 +8219,18 @@ get_64bit_dynamic_section (FILE * file)
   Elf64_External_Dyn * ext;
   Elf_Internal_Dyn * entry;
 
+  /* Read in the data.  */
   edyn = (Elf64_External_Dyn *) get_data (NULL, file, dynamic_addr, 1,
                                           dynamic_size, _("dynamic section"));
   if (!edyn)
     return 0;
 
-/* SGI's ELF has more than one section in the DYNAMIC segment, and we
-   might not have the luxury of section headers.  Look for the DT_NULL
-   terminator to determine the number of entries.  */
+  /* SGI's ELF has more than one section in the DYNAMIC segment, and we
+     might not have the luxury of section headers.  Look for the DT_NULL
+     terminator to determine the number of entries.  */
   for (ext = edyn, dynamic_nent = 0;
-       (char *) ext < (char *) edyn + dynamic_size;
+       /* PR 17533 file: 033-67080-0.004 - do not read off the end of the buffer.  */
+       (char *) ext < ((char *) edyn) + dynamic_size - sizeof (* ext);
        ext++)
     {
       dynamic_nent++;
@@ -8200,6 +8247,7 @@ get_64bit_dynamic_section (FILE * file)
       return 0;
     }
 
+  /* Convert from external to internal formats.  */
   for (ext = edyn, entry = dynamic_section;
        entry < dynamic_section + dynamic_nent;
        ext++, entry++)
@@ -8300,6 +8348,7 @@ process_dynamic_section (FILE * file)
            section.sh_entsize = sizeof (Elf32_External_Sym);
          else
            section.sh_entsize = sizeof (Elf64_External_Sym);
+         section.sh_name = string_table_length;
 
          dynamic_symbols = GET_ELF_SYMBOLS (file, &section, & num_dynamic_syms);
          if (num_dynamic_syms < 1)
@@ -8372,7 +8421,7 @@ process_dynamic_section (FILE * file)
              /* 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"),
+               error (_("Bad value (%d) for SYMINENT entry\n"),
                       (int) entry->d_un.d_val);
            }
          else if (entry->d_tag == DT_SYMINSZ)
@@ -8829,9 +8878,13 @@ process_dynamic_section (FILE * file)
              time_t atime = entry->d_un.d_val;
 
              tmp = gmtime (&atime);
-             printf ("%04u-%02u-%02uT%02u:%02u:%02u\n",
-                     tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday,
-                     tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+             /* PR 17533 file: 041-1244816-0.004.  */
+             if (tmp == NULL)
+               printf (_("<corrupt time val: %lx"), atime);
+             else
+               printf ("%04u-%02u-%02uT%02u:%02u:%02u\n",
+                       tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday,
+                       tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
 
            }
          break;
@@ -9775,6 +9828,7 @@ process_symbol_table (FILE * file)
   bfd_vma * gnubuckets = NULL;
   bfd_vma * gnuchains = NULL;
   bfd_vma gnusymidx = 0;
+  bfd_size_type ngnuchains = 0;
 
   if (!do_syms && !do_dyn_syms && !do_histogram)
     return 1;
@@ -9936,6 +9990,7 @@ process_symbol_table (FILE * file)
        }
 
       gnuchains = get_dynamic_data (file, maxchain, 4);
+      ngnuchains = maxchain;
 
     no_gnu_hash:
       if (gnuchains == NULL)
@@ -9994,7 +10049,7 @@ process_symbol_table (FILE * file)
                    print_dynamic_symbol (si, hn);
                    si++;
                  }
-               while ((gnuchains[off++] & 1) == 0);
+               while (off < ngnuchains && (gnuchains[off++] & 1) == 0);
              }
        }
     }
@@ -10345,7 +10400,9 @@ process_symbol_table (FILE * file)
            bfd_vma off, length = 1;
 
            for (off = gnubuckets[hn] - gnusymidx;
-                (gnuchains[off] & 1) == 0; ++off)
+                /* PR 17531 file: 010-77222-0.004.  */
+                off < ngnuchains && (gnuchains[off] & 1) == 0;
+                ++off)
              ++length;
            lengths[hn] = length;
            if (length > maxlength)
@@ -10515,7 +10572,7 @@ target_specific_reloc_handling (Elf_Internal_Rela * reloc,
 
          default:
            if (saved_sym != NULL)
-             error (_("Unhandled MSP430 reloc type found after SYM_DIFF reloc"));
+             error (_("Unhandled MSP430 reloc type found after SYM_DIFF reloc\n"));
            break;
          }
        break;
@@ -10551,7 +10608,7 @@ target_specific_reloc_handling (Elf_Internal_Rela * reloc,
            break;
          default:
            if (saved_sym != NULL)
-             error (_("Unhandled MN10300 reloc type found after SYM_DIFF reloc"));
+             error (_("Unhandled MN10300 reloc type found after SYM_DIFF reloc\n"));
            break;
          }
        break;
@@ -11254,15 +11311,18 @@ dump_section_as_strings (Elf_Internal_Shdr * section, FILE * file)
 
       if (data < end)
        {
+         size_t maxlen = end - data;
+
 #ifndef __MSVCRT__
          /* PR 11128: Use two separate invocations in order to work
              around bugs in the Solaris 8 implementation of printf.  */
          printf ("  [%6tx]  ", data - start);
-         printf ("%s\n", data);
 #else
-         printf ("  [%6Ix]  %s\n", (size_t) (data - start), data);
+         printf ("  [%6Ix]  ", (size_t) (data - start));
 #endif
-         data += strlen (data);
+         print_symbol ((int) maxlen, data);
+         putchar ('\n');
+         data += strnlen (data, maxlen);
          some_strings_shown = TRUE;
        }
     }
@@ -11707,9 +11767,13 @@ display_tag_value (int tag,
     }
   else if (tag & 1)
     {
-      /* FIXME: we could read beyond END here.  */
-      printf ("\"%s\"\n", p);
-      p += strlen ((char *) p) + 1;
+      /* PR 17531 file: 027-19978-0.004.  */
+      size_t maxlen = (end - p) - 1;
+
+      putchar ('"');
+      print_symbol ((int) maxlen, (const char *) p);
+      printf ("\"\n");
+      p += strnlen ((char *) p, maxlen) + 1;
     }
   else
     {
@@ -11927,10 +11991,17 @@ display_arm_attribute (unsigned char * p,
              break;
 
            case 32: /* Tag_compatibility.  */
-             val = read_uleb128 (p, &len, end);
-             p += len;
-             printf (_("flag = %d, vendor = %s\n"), val, p);
-             p += strlen ((char *) p) + 1;
+             {
+               size_t maxlen;
+
+               val = read_uleb128 (p, &len, end);
+               p += len;
+               maxlen = (end - p) - 1;
+               printf (_("flag = %d, vendor = "), val);
+               print_symbol ((int) maxlen, (const char *) p);
+               putchar ('\n');
+               p += strnlen ((char *) p, maxlen) + 1;
+             }
              break;
 
            case 64: /* Tag_nodefaults.  */
@@ -11945,14 +12016,15 @@ display_arm_attribute (unsigned char * p,
                {
                  val = read_uleb128 (p, &len, end);
                  p += len;
-                 if ((unsigned int)val >= ARRAY_SIZE (arm_attr_tag_CPU_arch))
+                 if ((unsigned int) val >= ARRAY_SIZE (arm_attr_tag_CPU_arch))
                    printf ("??? (%d)\n", val);
                  else
                    printf ("%s\n", arm_attr_tag_CPU_arch[val]);
                }
              else
                printf ("???\n");
-             while (*(p++) != '\0' /* NUL terminator.  */);
+             while (p < end && *(p++) != '\0' /* NUL terminator.  */)
+               ;
              break;
 
            default:
@@ -11999,15 +12071,20 @@ display_gnu_attribute (unsigned char * p,
     {
       val = read_uleb128 (p, &len, end);
       p += len;
+
+      printf (_("flag = %d, vendor = "), val);
       if (p == end)
        {
-         printf (_("flag = %d, vendor = <corrupt>\n"), val);
+         printf (_("<corrupt>\n"));
          warn (_("corrupt vendor attribute\n"));
        }
       else
        {
-         printf (_("flag = %d, vendor = %s\n"), val, p);
-         p += strlen ((char *) p) + 1;
+         size_t maxlen = (end - p) - 1;
+
+         print_symbol ((int) maxlen, (const char *) p);
+         putchar ('\n');
+         p += strnlen ((char *) p, maxlen) + 1;
        }
       return p;
     }
@@ -12083,7 +12160,7 @@ display_power_gnu_attribute (unsigned char * p,
     {
       if (p == end)
        {
-         warn (_("corrupt Tag_GNU_Power_ABI_Struct_Return"));
+         warn (_("corrupt Tag_GNU_Power_ABI_Struct_Return\n"));
          return p;
        }
 
@@ -12117,6 +12194,7 @@ display_sparc_hwcaps (int mask)
   if (mask)
     {
       int first = 1;
+
       if (mask & ELF_SPARC_HWCAP_MUL32)
        fputs ("mul32", stdout), first = 0;
       if (mask & ELF_SPARC_HWCAP_DIV32)
@@ -12151,8 +12229,8 @@ display_sparc_hwcaps (int mask)
        printf ("%scspare", first ? "" : "|"), first = 0;
     }
   else
-    fputc('0', stdout);
-  fputc('\n', stdout);
+    fputc ('0', stdout);
+  fputc ('\n', stdout);
 }
 
 static void
@@ -12161,6 +12239,7 @@ display_sparc_hwcaps2 (int mask)
   if (mask)
     {
       int first = 1;
+
       if (mask & ELF_SPARC_HWCAP2_FJATHPLUS)
        fputs ("fjathplus", stdout), first = 0;
       if (mask & ELF_SPARC_HWCAP2_VIS3B)
@@ -12185,8 +12264,8 @@ display_sparc_hwcaps2 (int mask)
        printf ("%sfjaes", first ? "" : "|"), first = 0;
     }
   else
-    fputc('0', stdout);
-  fputc('\n', stdout);
+    fputc ('0', stdout);
+  fputc ('\n', stdout);
 }
 
 static unsigned char *
@@ -12502,18 +12581,32 @@ display_tic6x_attribute (unsigned char * p,
       return p;
 
     case Tag_ABI_compatibility:
-      val = read_uleb128 (p, &len, end);
-      p += len;
-      printf ("  Tag_ABI_compatibility: ");
-      printf (_("flag = %d, vendor = %s\n"), val, p);
-      p += strlen ((char *) p) + 1;
-      return p;
+      {
+       size_t maxlen;
+
+       val = read_uleb128 (p, &len, end);
+       p += len;
+       printf ("  Tag_ABI_compatibility: ");
+       maxlen = (end - p) - 1;
+       printf (_("flag = %d, vendor = "), val);
+       print_symbol ((int) maxlen, (const char *) p);
+       putchar ('\n');
+       p += strnlen ((char *) p, maxlen) + 1;
+       return p;
+      }
 
     case Tag_ABI_conformance:
-      printf ("  Tag_ABI_conformance: ");
-      printf ("\"%s\"\n", p);
-      p += strlen ((char *) p) + 1;
-      return p;
+      {
+       size_t maxlen;
+
+       printf ("  Tag_ABI_conformance: ");
+       maxlen = (end - p) - 1;
+       putchar ('"');
+       print_symbol ((int) maxlen, (const char *) p);
+       printf ("\"\n");
+       p += strnlen ((char *) p, maxlen) + 1;
+       return p;
+      }
     }
 
   return display_tag_value (tag, p, end);
@@ -12622,8 +12715,13 @@ display_msp430x_attribute (unsigned char * p,
 
       if (tag & 1)
        {
-         printf ("\"%s\"\n", p);
-         p += strlen ((char *) p) + 1;
+         size_t maxlen;
+
+         maxlen = (end - p) - 1;
+         putchar ('"');
+         print_symbol ((int) maxlen, (const char *) p);
+         printf ("\"\n");
+         p += strnlen ((char *) p, maxlen) + 1;
        }
       else
        {
@@ -12645,11 +12743,6 @@ process_attributes (FILE * file,
                    unsigned char * (* display_proc_gnu_attribute) (unsigned char *, int, const unsigned char * const))
 {
   Elf_Internal_Shdr * sect;
-  unsigned char * contents;
-  unsigned char * p;
-  unsigned char * end;
-  bfd_vma section_len;
-  bfd_vma len;
   unsigned i;
 
   /* Find the section header so that we get the size.  */
@@ -12657,6 +12750,9 @@ process_attributes (FILE * file,
        i < elf_header.e_shnum;
        i++, sect++)
     {
+      unsigned char * contents;
+      unsigned char * p;
+
       if (sect->sh_type != proc_type && sect->sh_type != SHT_GNU_ATTRIBUTES)
        continue;
 
@@ -12668,47 +12764,52 @@ process_attributes (FILE * file,
       p = contents;
       if (*p == 'A')
        {
-         len = sect->sh_size - 1;
+         bfd_vma section_len;
+
+         section_len = sect->sh_size - 1;
          p++;
 
-         while (len > 0)
+         while (section_len > 0)
            {
+             bfd_vma attr_len;
              unsigned int namelen;
              bfd_boolean public_section;
              bfd_boolean gnu_section;
 
-             if (len <= 4)
+             if (section_len <= 4)
                {
                  error (_("Tag section ends prematurely\n"));
                  break;
                }
-             section_len = byte_get (p, 4);
+             attr_len = byte_get (p, 4);
              p += 4;
 
-             if (section_len > len)
+             if (attr_len > section_len)
                {
-                 error (_("Length of attribute (%u) greater than length of section (%u)\n"),
-                         (unsigned) section_len, (unsigned) len);
-                 section_len = len;
+                 error (_("Bad attribute length (%u > %u)\n"),
+                         (unsigned) attr_len, (unsigned) section_len);
+                 attr_len = section_len;
                }
              /* PR 17531: file: 001-101425-0.004  */
-             else if (section_len < 5)
+             else if (attr_len < 5)
                {
-                 error (_("Attribute length of %u is too small\n"), (unsigned) section_len);
+                 error (_("Attribute length of %u is too small\n"), (unsigned) attr_len);
                  break;
                }
-             
-             len -= section_len;
-             section_len -= 4;
 
-             namelen = strnlen ((char *) p, section_len) + 1;
-             if (namelen == 0 || namelen >= section_len)
+             section_len -= attr_len;
+             attr_len -= 4;
+
+             namelen = strnlen ((char *) p, attr_len) + 1;
+             if (namelen == 0 || namelen >= attr_len)
                {
                  error (_("Corrupt attribute section name\n"));
                  break;
                }
 
-             printf (_("Attribute Section: %s\n"), p);
+             printf (_("Attribute Section: "));
+             print_symbol (INT_MAX, (const char *) p);
+             putchar ('\n');
 
              if (public_name && streq ((char *) p, public_name))
                public_section = TRUE;
@@ -12721,16 +12822,17 @@ process_attributes (FILE * file,
                gnu_section = FALSE;
 
              p += namelen;
-             section_len -= namelen;
+             attr_len -= namelen;
 
-             while (section_len > 0)
+             while (attr_len > 0 && p < contents + sect->sh_size)
                {
                  int tag;
                  int val;
                  bfd_vma size;
+                 unsigned char * end;
 
                  /* PR binutils/17531: Safe handling of corrupt files.  */
-                 if (section_len < 6)
+                 if (attr_len < 6)
                    {
                      error (_("Unused bytes at end of section\n"));
                      section_len = 0;
@@ -12739,11 +12841,11 @@ process_attributes (FILE * file,
 
                  tag = *(p++);
                  size = byte_get (p, 4);
-                 if (size > section_len)
+                 if (size > attr_len)
                    {
                      error (_("Bad subsection length (%u > %u)\n"),
-                             (unsigned) size, (unsigned) section_len);
-                     size = section_len;
+                             (unsigned) size, (unsigned) attr_len);
+                     size = attr_len;
                    }
                  /* PR binutils/17531: Safe handling of corrupt files.  */
                  if (size < 6)
@@ -12754,8 +12856,9 @@ process_attributes (FILE * file,
                      break;
                    }
 
-                 section_len -= size;
+                 attr_len -= size;
                  end = p + size - 1;
+                 assert (end <= contents + sect->sh_size);
                  p += 4;
 
                  switch (tag)
@@ -12787,24 +12890,28 @@ process_attributes (FILE * file,
                      break;
                    }
 
-                 if (public_section)
+                 if (public_section && display_pub_attribute != NULL)
                    {
                      while (p < end)
                        p = display_pub_attribute (p, end);
+                     assert (p <= end);
                    }
-                 else if (gnu_section)
+                 else if (gnu_section && display_proc_gnu_attribute != NULL)
                    {
                      while (p < end)
                        p = display_gnu_attribute (p,
                                                   display_proc_gnu_attribute,
                                                   end);
+                     assert (p <= end);
                    }
-                 else
+                 else if (p < end)
                    {
-                     printf (_("  Unknown section contexts\n"));
+                     printf (_("  Unknown attribute:\n"));
                      display_raw_attribute (p, end);
                      p = end;
                    }
+                 else
+                   attr_len = 0;
                }
            }
        }
@@ -13093,7 +13200,10 @@ process_mips_specific (FILE * file)
     /* No information available.  */
     return 0;
 
-  for (entry = dynamic_section; entry->d_tag != DT_NULL; ++entry)
+  for (entry = dynamic_section;
+       /* PR 17531 file: 012-50589-0.004.  */
+       entry < dynamic_section + dynamic_nent && entry->d_tag != DT_NULL;
+       ++entry)
     switch (entry->d_tag)
       {
       case DT_MIPS_LIBLIST:
@@ -13234,8 +13344,13 @@ process_mips_specific (FILE * file)
       sect = section_headers;
 
       /* Find the section header so that we get the size.  */
-      while (sect->sh_type != SHT_MIPS_OPTIONS)
-       ++sect;
+      sect = find_section_by_type (SHT_MIPS_OPTIONS);
+      /* PR 17533 file: 012-277276-0.004.  */ 
+      if (sect == NULL)
+       {
+         error (_("No MIPS_OPTIONS header found\n"));
+         return 0;
+       }
 
       eopt = (Elf_External_Options *) get_data (NULL, file, options_offset, 1,
                                                 sect->sh_size, _("options"));