PR24876, readelf: heap-buffer-overflow in dump_ia64_unwind
[deliverable/binutils-gdb.git] / binutils / readelf.c
index 4ed1ba1b735ce7f78ca6a09be99825a9c5f6720a..5e18734f10b9455e9bac3dd6b875fbd820730e39 100644 (file)
@@ -2412,7 +2412,7 @@ get_machine_name (unsigned e_machine)
     case EM_TPC:               return "Tenor Network TPC processor";
     case EM_SNP1K:             return "Trebia SNP 1000 processor";
       /* 100 */
-    case EM_ST200:             return "STMicroelectronics ST200 microcontroller";  
+    case EM_ST200:             return "STMicroelectronics ST200 microcontroller";
     case EM_IP2K_OLD:
     case EM_IP2K:              return "Ubicom IP2xxx 8-bit microcontrollers";
     case EM_MAX:               return "MAX Processor";
@@ -2528,7 +2528,7 @@ get_machine_name (unsigned e_machine)
     case EM_MT:                 return "Morpho Techologies MT processor";
     case EM_ALPHA:             return "Alpha";
     case EM_WEBASSEMBLY:       return "Web Assembly";
-    case EM_DLX:               return "OpenDLX";  
+    case EM_DLX:               return "OpenDLX";
     case EM_XSTORMY16:         return "Sanyo XStormy16 CPU core";
     case EM_IQ2000:            return "Vitesse IQ2000";
     case EM_M32C_OLD:
@@ -3879,22 +3879,6 @@ get_parisc_segment_type (unsigned long type)
 {
   switch (type)
     {
-    case PT_HP_TLS:            return "HP_TLS";
-    case PT_HP_CORE_NONE:      return "HP_CORE_NONE";
-    case PT_HP_CORE_VERSION:   return "HP_CORE_VERSION";
-    case PT_HP_CORE_KERNEL:    return "HP_CORE_KERNEL";
-    case PT_HP_CORE_COMM:      return "HP_CORE_COMM";
-    case PT_HP_CORE_PROC:      return "HP_CORE_PROC";
-    case PT_HP_CORE_LOADABLE:  return "HP_CORE_LOADABLE";
-    case PT_HP_CORE_STACK:     return "HP_CORE_STACK";
-    case PT_HP_CORE_SHM:       return "HP_CORE_SHM";
-    case PT_HP_CORE_MMF:       return "HP_CORE_MMF";
-    case PT_HP_PARALLEL:       return "HP_PARALLEL";
-    case PT_HP_FASTBIND:       return "HP_FASTBIND";
-    case PT_HP_OPT_ANNOT:      return "HP_OPT_ANNOT";
-    case PT_HP_HSL_ANNOT:      return "HP_HSL_ANNOT";
-    case PT_HP_STACK:          return "HP_STACK";
-    case PT_HP_CORE_UTSNAME:   return "HP_CORE_UTSNAME";
     case PT_PARISC_ARCHEXT:    return "PARISC_ARCHEXT";
     case PT_PARISC_UNWIND:     return "PARISC_UNWIND";
     case PT_PARISC_WEAKORDER:  return "PARISC_WEAKORDER";
@@ -3909,10 +3893,6 @@ get_ia64_segment_type (unsigned long type)
     {
     case PT_IA_64_ARCHEXT:     return "IA_64_ARCHEXT";
     case PT_IA_64_UNWIND:      return "IA_64_UNWIND";
-    case PT_HP_TLS:            return "HP_TLS";
-    case PT_IA_64_HP_OPT_ANOT: return "HP_OPT_ANNOT";
-    case PT_IA_64_HP_HSL_ANOT: return "HP_HSL_ANNOT";
-    case PT_IA_64_HP_STACK:    return "HP_STACK";
     default:                    return NULL;
     }
 }
@@ -3927,6 +3907,44 @@ get_tic6x_segment_type (unsigned long type)
     }
 }
 
+static const char *
+get_hpux_segment_type (unsigned long type, unsigned e_machine)
+{
+  if (e_machine == EM_PARISC)
+    switch (type)
+      {
+      case PT_HP_TLS:          return "HP_TLS";
+      case PT_HP_CORE_NONE:    return "HP_CORE_NONE";
+      case PT_HP_CORE_VERSION: return "HP_CORE_VERSION";
+      case PT_HP_CORE_KERNEL:  return "HP_CORE_KERNEL";
+      case PT_HP_CORE_COMM:    return "HP_CORE_COMM";
+      case PT_HP_CORE_PROC:    return "HP_CORE_PROC";
+      case PT_HP_CORE_LOADABLE:        return "HP_CORE_LOADABLE";
+      case PT_HP_CORE_STACK:   return "HP_CORE_STACK";
+      case PT_HP_CORE_SHM:     return "HP_CORE_SHM";
+      case PT_HP_CORE_MMF:     return "HP_CORE_MMF";
+      case PT_HP_PARALLEL:     return "HP_PARALLEL";
+      case PT_HP_FASTBIND:     return "HP_FASTBIND";
+      case PT_HP_OPT_ANNOT:    return "HP_OPT_ANNOT";
+      case PT_HP_HSL_ANNOT:    return "HP_HSL_ANNOT";
+      case PT_HP_STACK:                return "HP_STACK";
+      case PT_HP_CORE_UTSNAME: return "HP_CORE_UTSNAME";
+      default:                 return NULL;
+      }
+
+  if (e_machine == EM_IA_64)
+    switch (type)
+      {
+      case PT_HP_TLS:           return "HP_TLS";
+      case PT_IA_64_HP_OPT_ANOT: return "HP_OPT_ANNOT";
+      case PT_IA_64_HP_HSL_ANOT: return "HP_HSL_ANNOT";
+      case PT_IA_64_HP_STACK:   return "HP_STACK";
+      default:                  return NULL;
+      }
+
+  return NULL;
+}
+
 static const char *
 get_solaris_segment_type (unsigned long type)
 {
@@ -3965,12 +3983,7 @@ get_segment_type (Filedata * filedata, unsigned long p_type)
     case PT_GNU_PROPERTY: return "GNU_PROPERTY";
 
     default:
-      if (p_type >= PT_GNU_MBIND_LO && p_type <= PT_GNU_MBIND_HI)
-       {
-         sprintf (buff, "GNU_MBIND+%#lx",
-                  p_type - PT_GNU_MBIND_LO);
-       }
-      else if ((p_type >= PT_LOPROC) && (p_type <= PT_HIPROC))
+      if ((p_type >= PT_LOPROC) && (p_type <= PT_HIPROC))
        {
          const char * result;
 
@@ -4011,24 +4024,28 @@ get_segment_type (Filedata * filedata, unsigned long p_type)
        }
       else if ((p_type >= PT_LOOS) && (p_type <= PT_HIOS))
        {
-         const char * result;
+         const char * result = NULL;
 
-         switch (filedata->file_header.e_machine)
+         switch (filedata->file_header.e_ident[EI_OSABI])
            {
-           case EM_PARISC:
-             result = get_parisc_segment_type (p_type);
+           case ELFOSABI_GNU:
+           case ELFOSABI_FREEBSD:
+             if (p_type >= PT_GNU_MBIND_LO && p_type <= PT_GNU_MBIND_HI)
+               {
+                 sprintf (buff, "GNU_MBIND+%#lx", p_type - PT_GNU_MBIND_LO);
+                 result = buff;
+               }
              break;
-           case EM_IA_64:
-             result = get_ia64_segment_type (p_type);
+           case ELFOSABI_HPUX:
+             result = get_hpux_segment_type (p_type,
+                                             filedata->file_header.e_machine);
+             break;
+           case ELFOSABI_SOLARIS:
+             result = get_solaris_segment_type (p_type);
              break;
            default:
-             if (filedata->file_header.e_ident[EI_OSABI] == ELFOSABI_SOLARIS)
-               result = get_solaris_segment_type (p_type);
-             else
-               result = NULL;
              break;
            }
-
          if (result != NULL)
            return result;
 
@@ -7398,11 +7415,6 @@ struct absaddr
   bfd_vma offset;
 };
 
-#define ABSADDR(a) \
-  ((a).section \
-   ? filedata->section_headers [(a).section].sh_addr + (a).offset \
-   : (a).offset)
-
 /* Find the nearest symbol at or below ADDR.  Returns the symbol
    name, if found, and the offset from the symbol to ADDR.  */
 
@@ -7548,8 +7560,22 @@ dump_ia64_unwind (Filedata * filedata, struct ia64_unw_aux_info * aux)
       if (aux->info == NULL)
        continue;
 
+      offset = tp->info.offset;
+      if (tp->info.section)
+       {
+         if (tp->info.section >= filedata->file_header.e_shnum)
+           {
+             warn (_("Invalid section %u in table entry %ld\n"),
+                   tp->info.section, (long) (tp - aux->table));
+             res = FALSE;
+             continue;
+           }
+         offset += filedata->section_headers[tp->info.section].sh_addr;
+       }
+      offset -= aux->info_addr;
       /* PR 17531: file: 0997b4d1.  */
-      if ((ABSADDR (tp->info) - aux->info_addr) >= aux->info_size)
+      if (offset >= aux->info_size
+         || aux->info_size - offset < 8)
        {
          warn (_("Invalid offset %lx in table entry %ld\n"),
                (long) tp->info.offset, (long) (tp - aux->table));
@@ -7557,7 +7583,7 @@ dump_ia64_unwind (Filedata * filedata, struct ia64_unw_aux_info * aux)
          continue;
        }
 
-      head = aux->info + (ABSADDR (tp->info) - aux->info_addr);
+      head = aux->info + offset;
       stamp = byte_get ((unsigned char *) head, sizeof (stamp));
 
       printf ("  v%u, flags=0x%lx (%s%s), len=%lu bytes\n",
@@ -11052,9 +11078,7 @@ get_symbol_binding (Filedata * filedata, unsigned int binding)
       else if (binding >= STB_LOOS && binding <= STB_HIOS)
        {
          if (binding == STB_GNU_UNIQUE
-             && (filedata->file_header.e_ident[EI_OSABI] == ELFOSABI_GNU
-                 /* GNU is still using the default value 0.  */
-                 || filedata->file_header.e_ident[EI_OSABI] == ELFOSABI_NONE))
+             && filedata->file_header.e_ident[EI_OSABI] == ELFOSABI_GNU)
            return "UNIQUE";
          snprintf (buff, sizeof (buff), _("<OS specific>: %d"), binding);
        }
@@ -11106,9 +11130,7 @@ get_symbol_type (Filedata * filedata, unsigned int type)
 
          if (type == STT_GNU_IFUNC
              && (filedata->file_header.e_ident[EI_OSABI] == ELFOSABI_GNU
-                 || filedata->file_header.e_ident[EI_OSABI] == ELFOSABI_FREEBSD
-                 /* GNU is still using the default value 0.  */
-                 || filedata->file_header.e_ident[EI_OSABI] == ELFOSABI_NONE))
+                 || filedata->file_header.e_ident[EI_OSABI] == ELFOSABI_FREEBSD))
            return "IFUNC";
 
          snprintf (buff, sizeof (buff), _("<OS specific>: %d"), type);
@@ -11136,7 +11158,7 @@ get_symbol_visibility (unsigned int visibility)
 
 static const char *
 get_alpha_symbol_other (unsigned int other)
-{   
+{
   switch (other)
     {
     case STO_ALPHA_NOPV:       return "NOPV";
@@ -11144,7 +11166,7 @@ get_alpha_symbol_other (unsigned int other)
     default:
       error (_("Unrecognized alpah specific other value: %u"), other);
       return _("<unknown>");
-    } 
+    }
 }
 
 static const char *
@@ -11549,7 +11571,7 @@ get_symbol_version_string (Filedata *                   filedata,
 
       if (ivd.vd_ndx == (vers_data & VERSYM_VERSION))
        {
-         if (ivd.vd_ndx == 1 && ivd.vd_flags == VER_FLG_BASE) 
+         if (ivd.vd_ndx == 1 && ivd.vd_flags == VER_FLG_BASE)
            return NULL;
 
          off -= ivd.vd_next;
@@ -12598,7 +12620,7 @@ is_32bit_abs_reloc (Filedata * filedata, unsigned int reloc_type)
     case EM_OR1K:
       return reloc_type == 1; /* R_OR1K_32.  */
     case EM_PARISC:
-      return (reloc_type == 1 /* R_PARISC_DIR32.  */         
+      return (reloc_type == 1 /* R_PARISC_DIR32.  */
              || reloc_type == 2 /* R_PARISC_DIR21L.  */
              || reloc_type == 41); /* R_PARISC_SECREL32.  */
     case EM_PJ:
@@ -13345,7 +13367,7 @@ apply_relocations (Filedata *                 filedata,
            }
 
          rloc = start + rp->r_offset;
-         if ((rloc + reloc_size) > end || (rloc < start))
+         if (rloc >= end || (rloc + reloc_size) > end || (rloc < start))
            {
              warn (_("skipping invalid relocation offset 0x%lx in section %s\n"),
                    (unsigned long) rp->r_offset,
@@ -13848,10 +13870,10 @@ shdr_to_ctf_sect (ctf_sect_t *buf, Elf_Internal_Shdr *shdr, Filedata *filedata)
 static char *dump_ctf_indent_lines (ctf_sect_names_t sect ATTRIBUTE_UNUSED,
                                    char *s, void *arg)
 {
-  char *spaces = arg;
+  const char *blanks = arg;
   char *new_s;
 
-  if (asprintf (&new_s, "%s%s", spaces, s) < 0)
+  if (asprintf (&new_s, "%s%s", blanks, s) < 0)
     return s;
   return new_s;
 }
@@ -13993,7 +14015,7 @@ load_specific_debug_section (enum dwarf_section_display_enum  debug,
   struct dwarf_section * section = &debug_displays [debug].section;
   char buf [64];
   Filedata * filedata = (Filedata *) data;
-  
+
   if (section->start != NULL)
     {
       /* If it is already loaded, do nothing.  */
@@ -16460,8 +16482,6 @@ process_mips_specific (Filedata * filedata)
   if (options_offset != 0)
     {
       Elf_External_Options * eopt;
-      Elf_Internal_Options * iopt;
-      Elf_Internal_Options * option;
       size_t offset;
       int cnt;
       sect = filedata->section_headers;
@@ -16485,6 +16505,10 @@ process_mips_specific (Filedata * filedata)
                                                 sect->sh_size, _("options"));
       if (eopt)
        {
+         Elf_Internal_Options * iopt;
+         Elf_Internal_Options * option;
+         Elf_Internal_Options * iopt_end;
+
          iopt = (Elf_Internal_Options *)
               cmalloc ((sect->sh_size / sizeof (eopt)), sizeof (* iopt));
          if (iopt == NULL)
@@ -16495,7 +16519,8 @@ process_mips_specific (Filedata * filedata)
 
          offset = cnt = 0;
          option = iopt;
-
+         iopt_end = iopt + (sect->sh_size / sizeof (eopt));
+         
          while (offset <= sect->sh_size - sizeof (* eopt))
            {
              Elf_External_Options * eoption;
@@ -16538,15 +16563,25 @@ process_mips_specific (Filedata * filedata)
                  /* This shouldn't happen.  */
                  printf (" NULL       %d %lx", option->section, option->info);
                  break;
+
                case ODK_REGINFO:
                  printf (" REGINFO    ");
                  if (filedata->file_header.e_machine == EM_MIPS)
                    {
-                     /* 32bit form.  */
                      Elf32_External_RegInfo * ereg;
                      Elf32_RegInfo reginfo;
 
+                     /* 32bit form.  */
+                     if (option + 2 > iopt_end)
+                       {
+                         printf (_("<corrupt>\n"));
+                         error (_("Truncated MIPS REGINFO option\n"));
+                         cnt = 0;
+                         break;
+                       }
+
                      ereg = (Elf32_External_RegInfo *) (option + 1);
+
                      reginfo.ri_gprmask = BYTE_GET (ereg->ri_gprmask);
                      reginfo.ri_cprmask[0] = BYTE_GET (ereg->ri_cprmask[0]);
                      reginfo.ri_cprmask[1] = BYTE_GET (ereg->ri_cprmask[1]);
@@ -16567,6 +16602,14 @@ process_mips_specific (Filedata * filedata)
                      Elf64_External_RegInfo * ereg;
                      Elf64_Internal_RegInfo reginfo;
 
+                     if (option + 2 > iopt_end)
+                       {
+                         printf (_("<corrupt>\n"));
+                         error (_("Truncated MIPS REGINFO option\n"));
+                         cnt = 0;
+                         break;
+                       }
+
                      ereg = (Elf64_External_RegInfo *) (option + 1);
                      reginfo.ri_gprmask    = BYTE_GET (ereg->ri_gprmask);
                      reginfo.ri_cprmask[0] = BYTE_GET (ereg->ri_cprmask[0]);
@@ -16586,6 +16629,7 @@ process_mips_specific (Filedata * filedata)
                    }
                  ++option;
                  continue;
+
                case ODK_EXCEPTIONS:
                  fputs (" EXCEPTIONS fpe_min(", stdout);
                  process_mips_fpe_exception (option->info & OEX_FPU_MIN);
@@ -16602,6 +16646,7 @@ process_mips_specific (Filedata * filedata)
                  if (option->info & OEX_DISMISS)
                    fputs (" DISMISS", stdout);
                  break;
+
                case ODK_PAD:
                  fputs (" PAD       ", stdout);
                  if (option->info & OPAD_PREFIX)
@@ -16611,6 +16656,7 @@ process_mips_specific (Filedata * filedata)
                  if (option->info & OPAD_SYMBOL)
                    fputs (" SYMBOL", stdout);
                  break;
+
                case ODK_HWPATCH:
                  fputs (" HWPATCH   ", stdout);
                  if (option->info & OHW_R4KEOP)
@@ -16622,14 +16668,17 @@ process_mips_specific (Filedata * filedata)
                  if (option->info & OHW_R5KCVTL)
                    fputs (" R5KCVTL", stdout);
                  break;
+
                case ODK_FILL:
                  fputs (" FILL       ", stdout);
                  /* XXX Print content of info word?  */
                  break;
+
                case ODK_TAGS:
                  fputs (" TAGS       ", stdout);
                  /* XXX Print content of info word?  */
                  break;
+
                case ODK_HWAND:
                  fputs (" HWAND     ", stdout);
                  if (option->info & OHWA0_R4KEOP_CHECKED)
@@ -16637,6 +16686,7 @@ process_mips_specific (Filedata * filedata)
                  if (option->info & OHWA0_R4KEOP_CLEAN)
                    fputs (" R4KEOP_CLEAN", stdout);
                  break;
+
                case ODK_HWOR:
                  fputs (" HWOR      ", stdout);
                  if (option->info & OHWA0_R4KEOP_CHECKED)
@@ -16644,16 +16694,19 @@ process_mips_specific (Filedata * filedata)
                  if (option->info & OHWA0_R4KEOP_CLEAN)
                    fputs (" R4KEOP_CLEAN", stdout);
                  break;
+
                case ODK_GP_GROUP:
                  printf (" GP_GROUP  %#06lx  self-contained %#06lx",
                          option->info & OGP_GROUP,
                          (option->info & OGP_SELF) >> 16);
                  break;
+
                case ODK_IDENT:
                  printf (" IDENT     %#06lx  self-contained %#06lx",
                          option->info & OGP_GROUP,
                          (option->info & OGP_SELF) >> 16);
                  break;
+
                default:
                  /* This shouldn't happen.  */
                  printf (" %3d ???     %d %lx",
@@ -17955,7 +18008,7 @@ print_gnu_note (Filedata * filedata, Elf_Internal_Note *pnote)
     case NT_GNU_PROPERTY_TYPE_0:
       print_gnu_property_note (filedata, pnote);
       break;
-      
+
     default:
       /* Handle unrecognised types.  An error message should have already been
         created by get_gnu_elf_note_type(), so all that we need to do is to
@@ -18075,10 +18128,23 @@ process_netbsd_elf_note (Elf_Internal_Note * pnote)
       return TRUE;
 
     case NT_NETBSD_MARCH:
-      printf ("  NetBSD\t0x%08lx\tMARCH <%s>\n", pnote->descsz,
+      printf ("  NetBSD\t\t0x%08lx\tMARCH <%s>\n", pnote->descsz,
              pnote->descdata);
       return TRUE;
 
+#ifdef   NT_NETBSD_PAX
+    case NT_NETBSD_PAX:
+      version = byte_get ((unsigned char *) pnote->descdata, sizeof (version));
+      printf ("  NetBSD\t\t0x%08lx\tPaX <%s%s%s%s%s%s>\n", pnote->descsz,
+             ((version & NT_NETBSD_PAX_MPROTECT) ? "+mprotect" : ""),
+             ((version & NT_NETBSD_PAX_NOMPROTECT) ? "-mprotect" : ""),
+             ((version & NT_NETBSD_PAX_GUARD) ? "+guard" : ""),
+             ((version & NT_NETBSD_PAX_NOGUARD) ? "-guard" : ""),
+             ((version & NT_NETBSD_PAX_ASLR) ? "+ASLR" : ""),
+             ((version & NT_NETBSD_PAX_NOASLR) ? "-ASLR" : ""));
+      return TRUE;
+#endif
+
     default:
       printf ("  NetBSD\t0x%08lx\tUnknown note type: (0x%08lx)\n", pnote->descsz,
              pnote->type);
@@ -18267,7 +18333,7 @@ print_stapsdt_note (Elf_Internal_Note *pnote)
     }
   else
     goto stapdt_note_too_small;
-  
+
   if (data >= data_end)
     goto stapdt_note_too_small;
   maxlen = data_end - data;
@@ -18594,7 +18660,7 @@ same_section (Filedata * filedata, unsigned long addr1, unsigned long addr2)
 
   a1 = find_section_by_address (filedata, addr1);
   a2 = find_section_by_address (filedata, addr2);
-  
+
   return a1 == a2 && a1 != NULL;
 }
 
@@ -18658,7 +18724,7 @@ print_gnu_build_attribute_description (Elf_Internal_Note *  pnote,
       start = byte_get ((unsigned char *) pnote->descdata, 8);
       end = byte_get ((unsigned char *) pnote->descdata + 8, 8);
       break;
-      
+
     default:
       error (_("    <invalid description size: %lx>\n"), pnote->descsz);
       printf (_("    <invalid descsz>"));
@@ -18953,7 +19019,7 @@ print_gnu_build_attribute_name (Elf_Internal_Note * pnote)
 
   if (do_wide && left > 0)
     printf ("%-*s", left, " ");
-    
+
   return TRUE;
 }
 
@@ -18991,6 +19057,10 @@ process_note (Elf_Internal_Note *  pnote,
     /* NetBSD-specific core file notes.  */
     return process_netbsd_elf_note (pnote);
 
+  else if (const_strneq (pnote->namedata, "PaX"))
+    /* NetBSD-specific core file notes.  */
+    return process_netbsd_elf_note (pnote);
+
   else if (strneq (pnote->namedata, "SPU/", 4))
     {
       /* SPU-specific core file notes.  */
@@ -19974,7 +20044,7 @@ process_archive (Filedata * filedata, bfd_boolean is_thin_archive)
          /* PR 24049 - we cannot use filedata->file_name as this will
             have already been freed.  */
          error (_("%s: failed to read archive header\n"), arch.file_name);
-           
+
           ret = FALSE;
           break;
         }
@@ -20068,7 +20138,7 @@ process_archive (Filedata * filedata, bfd_boolean is_thin_archive)
 
          thin_filedata.handle = nested_arch.file;
          thin_filedata.file_name = qualified_name;
-         
+
           if (! process_object (& thin_filedata))
            ret = FALSE;
         }
This page took 0.033016 seconds and 4 git commands to generate.