Fix illegal memory accesses in readelf when parsing a corrupt binary.
[binutils-gdb.git] / binutils / readelf.c
index ede5747e40d00ea26d32cacefabd4860d4ec72f4..20df6f899609536adc50ca69fd4c3c84267c42f9 100644 (file)
@@ -676,8 +676,14 @@ find_section_in_set (const char * name, unsigned int * set)
   if (set != NULL)
     {
       while ((i = *set++) > 0)
-       if (streq (SECTION_NAME (section_headers + i), name))
-         return section_headers + i;
+       {
+         /* See PR 21156 for a reproducer.  */
+         if (i >= elf_header.e_shnum)
+           continue; /* FIXME: Should we issue an error message ?  */
+
+         if (streq (SECTION_NAME (section_headers + i), name))
+           return section_headers + i;
+       }
     }
 
   return find_section (name);
@@ -4136,7 +4142,18 @@ get_section_type_name (unsigned int sh_type)
              if (elf_header.e_ident[EI_OSABI] == ELFOSABI_SOLARIS)
                result = get_solaris_section_type (sh_type);
              else
-               result = NULL;
+               {
+                 switch (sh_type)
+                   {
+                   case SHT_GNU_INCREMENTAL_INPUTS: result = "GNU_INCREMENTAL_INPUTS"; break;
+                   case SHT_GNU_ATTRIBUTES: result = "GNU_ATTRIBUTES"; break;
+                   case SHT_GNU_HASH: result = "GNU_HASH"; break;
+                   case SHT_GNU_LIBLIST: result = "GNU_LIBLIST"; break;
+                   default:
+                     result = NULL;
+                     break;
+                   }
+               }
              break;
            }
 
@@ -11596,6 +11613,9 @@ process_syminfo (FILE * file ATTRIBUTE_UNUSED)
   return 1;
 }
 
+#define IN_RANGE(START,END,ADDR,OFF)           \
+  (((ADDR) >= (START)) && ((ADDR) + (OFF) < (END)))
+
 /* Check to see if the given reloc needs to be handled in a target specific
    manner.  If so then process the reloc and return TRUE otherwise return
    FALSE.
@@ -11678,12 +11698,12 @@ target_specific_reloc_handling (Elf_Internal_Rela * reloc,
                    value = reloc->r_addend + (symtab[sym_index].st_value
                                               - saved_sym->st_value);
 
-                   if (start + reloc->r_offset + reloc_size >= end)
-                     /* PR 21137 */
-                     error (_("MSP430 sym diff reloc writes past end of section (%p vs %p)\n"),
-                            start + reloc->r_offset + reloc_size, end);
-                   else
+                   if (IN_RANGE (start, end, start + reloc->r_offset, reloc_size))
                      byte_put (start + reloc->r_offset, value, reloc_size);
+                   else
+                     /* PR 21137 */
+                     error (_("MSP430 sym diff reloc contains invalid offset: 0x%lx\n"),
+                            (long) reloc->r_offset);
                  }
 
                saved_sym = NULL;
@@ -11737,11 +11757,11 @@ target_specific_reloc_handling (Elf_Internal_Rela * reloc,
                    value = reloc->r_addend + (symtab[sym_index].st_value
                                               - saved_sym->st_value);
 
-                   if (start + reloc->r_offset + reloc_size >= end)
-                     error (_("MN10300 sym diff reloc writes past end of section (%p vs %p)\n"),
-                            start + reloc->r_offset + reloc_size, end);
-                   else
+                   if (IN_RANGE (start, end, start + reloc->r_offset, reloc_size))
                      byte_put (start + reloc->r_offset, value, reloc_size);
+                   else
+                     error (_("MN10300 sym diff reloc contains invalid offset: 0x%lx\n"),
+                            (long) reloc->r_offset);
                  }
 
                saved_sym = NULL;
@@ -11789,20 +11809,20 @@ target_specific_reloc_handling (Elf_Internal_Rela * reloc,
            break;
 
          case 0x41: /* R_RL78_ABS32.  */
-           if (start + reloc->r_offset + 4 >= end)
-             error (_("RL78 sym diff reloc writes past end of section (%p vs %p)\n"),
-                    start + reloc->r_offset + 2, end);
-           else
+           if (IN_RANGE (start, end, start + reloc->r_offset, 4))
              byte_put (start + reloc->r_offset, value, 4);
+           else
+             error (_("RL78 sym diff reloc contains invalid offset: 0x%lx\n"),
+                    (long) reloc->r_offset);
            value = 0;
            return TRUE;
 
          case 0x43: /* R_RL78_ABS16.  */
-           if (start + reloc->r_offset + 2 >= end)
-             error (_("RL78 sym diff reloc writes past end of section (%p vs %p)\n"),
-                    start + reloc->r_offset + 2, end);
-           else
+           if (IN_RANGE (start, end, start + reloc->r_offset, 2))
              byte_put (start + reloc->r_offset, value, 2);
+           else
+             error (_("RL78 sym diff reloc contains invalid offset: 0x%lx\n"),
+                    (long) reloc->r_offset);
            value = 0;
            return TRUE;
 
@@ -12691,10 +12711,20 @@ dump_section_as_strings (Elf_Internal_Shdr * section, FILE * file)
          new_size -= 12;
        }
 
-      if (uncompressed_size
-         && uncompress_section_contents (& start,
-                                         uncompressed_size, & new_size))
-       num_bytes = new_size;
+      if (uncompressed_size)
+       {
+         if (uncompress_section_contents (& start,
+                                          uncompressed_size, & new_size))
+           num_bytes = new_size;
+         else
+           {
+             error (_("Unable to decompress section %s\n"),
+                    printable_section_name (section));
+             return;
+           }
+       }
+      else
+       start = real_start;
     }
 
   /* If the section being dumped has relocations against it the user might
@@ -12829,14 +12859,19 @@ dump_section_as_bytes (Elf_Internal_Shdr * section,
        {
          if (uncompress_section_contents (& start, uncompressed_size,
                                           & new_size))
-           section_size = new_size;
+           {
+             section_size = new_size;
+           }
          else
            {
              error (_("Unable to decompress section %s\n"),
                     printable_section_name (section));
+             /* FIXME: Print the section anyway ?  */
              return;
            }
        }
+      else
+       start = real_start;
     }
 
   if (relocate)
@@ -12986,15 +13021,24 @@ load_specific_debug_section (enum dwarf_section_display_enum debug,
          size -= 12;
        }
 
-      if (uncompressed_size
-         && uncompress_section_contents (&start, uncompressed_size,
-                                         &size))
+      if (uncompressed_size)
        {
-         /* Free the compressed buffer, update the section buffer
-            and the section size if uncompress is successful.  */
-         free (section->start);
-         section->start = start;
+         if (uncompress_section_contents (&start, uncompressed_size,
+                                          &size))
+           {
+             /* Free the compressed buffer, update the section buffer
+                and the section size if uncompress is successful.  */
+             free (section->start);
+             section->start = start;
+           }
+         else
+           {
+             error (_("Unable to decompress section %s\n"),
+                    printable_section_name (sec));
+             return 0;
+           }
        }
+
       section->size = size;
     }