Imported Upstream version 0.160
[platform/upstream/elfutils.git] / src / strip.c
index 5e9c883..c9a1d8d 100644 (file)
@@ -1,5 +1,5 @@
 /* Discard section not used at runtime from object files.
-   Copyright (C) 2000-2012 Red Hat, Inc.
+   Copyright (C) 2000-2012, 2014 Red Hat, Inc.
    This file is part of elfutils.
    Written by Ulrich Drepper <drepper@redhat.com>, 2000.
 
@@ -432,6 +432,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
   Elf_Data debuglink_crc_data;
   bool any_symtab_changes = false;
   Elf_Data *shstrtab_data = NULL;
+  void *debuglink_buf = NULL;
 
   /* Create the full name of the file.  */
   if (prefix != NULL)
@@ -564,6 +565,11 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
       goto fail_close;
     }
 
+  if (shstrndx >= shnum)
+    goto illformed;
+
+#define elf_assert(test) do { if (!(test)) goto illformed; } while (0)
+
   /* Storage for section information.  We leave room for two more
      entries since we unconditionally create a section header string
      table.  Maybe some weird tool created an ELF file without one.
@@ -585,7 +591,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
     {
       /* This should always be true (i.e., there should not be any
         holes in the numbering).  */
-      assert (elf_ndxscn (scn) == cnt);
+      elf_assert (elf_ndxscn (scn) == cnt);
 
       shdr_info[cnt].scn = scn;
 
@@ -598,6 +604,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
                                        shdr_info[cnt].shdr.sh_name);
       if (shdr_info[cnt].name == NULL)
        {
+       illformed:
          error (0, 0, gettext ("illformed file '%s'"), fname);
          goto fail_close;
        }
@@ -607,6 +614,8 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
 
       /* Remember the shdr.sh_link value.  */
       shdr_info[cnt].old_sh_link = shdr_info[cnt].shdr.sh_link;
+      if (shdr_info[cnt].old_sh_link >= shnum)
+       goto illformed;
 
       /* Sections in files other than relocatable object files which
         are not loaded can be freely moved by us.  In relocatable
@@ -619,7 +628,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
         appropriate reference.  */
       if (unlikely (shdr_info[cnt].shdr.sh_type == SHT_SYMTAB_SHNDX))
        {
-         assert (shdr_info[shdr_info[cnt].shdr.sh_link].symtab_idx == 0);
+         elf_assert (shdr_info[shdr_info[cnt].shdr.sh_link].symtab_idx == 0);
          shdr_info[shdr_info[cnt].shdr.sh_link].symtab_idx = cnt;
        }
       else if (unlikely (shdr_info[cnt].shdr.sh_type == SHT_GROUP))
@@ -636,7 +645,12 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
          for (inner = 1;
               inner < shdr_info[cnt].data->d_size / sizeof (Elf32_Word);
               ++inner)
-           shdr_info[grpref[inner]].group_idx = cnt;
+           {
+             if (grpref[inner] < shnum)
+               shdr_info[grpref[inner]].group_idx = cnt;
+             else
+               goto illformed;
+           }
 
          if (inner == 1 || (inner == 2 && (grpref[0] & GRP_COMDAT) == 0))
            /* If the section group contains only one element and this
@@ -647,7 +661,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
        }
       else if (unlikely (shdr_info[cnt].shdr.sh_type == SHT_GNU_versym))
        {
-         assert (shdr_info[shdr_info[cnt].shdr.sh_link].version_idx == 0);
+         elf_assert (shdr_info[shdr_info[cnt].shdr.sh_link].version_idx == 0);
          shdr_info[shdr_info[cnt].shdr.sh_link].version_idx = cnt;
        }
 
@@ -655,7 +669,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
         discarded right away.  */
       if ((shdr_info[cnt].shdr.sh_flags & SHF_GROUP) != 0)
        {
-         assert (shdr_info[cnt].group_idx != 0);
+         elf_assert (shdr_info[cnt].group_idx != 0);
 
          if (shdr_info[shdr_info[cnt].group_idx].idx == 0)
            {
@@ -731,10 +745,14 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
            {
              /* If a relocation section is marked as being removed make
                 sure the section it is relocating is removed, too.  */
-             if ((shdr_info[cnt].shdr.sh_type == SHT_REL
+             if (shdr_info[cnt].shdr.sh_type == SHT_REL
                   || shdr_info[cnt].shdr.sh_type == SHT_RELA)
-                 && shdr_info[shdr_info[cnt].shdr.sh_info].idx != 0)
-               shdr_info[cnt].idx = 1;
+               {
+                 if (shdr_info[cnt].shdr.sh_info >= shnum)
+                   goto illformed;
+                 else if (shdr_info[shdr_info[cnt].shdr.sh_info].idx != 0)
+                   shdr_info[cnt].idx = 1;
+               }
 
              /* If a group section is marked as being removed make
                 sure all the sections it contains are being removed, too.  */
@@ -778,7 +796,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
                  if (shdr_info[cnt].symtab_idx != 0
                      && shdr_info[shdr_info[cnt].symtab_idx].data == NULL)
                    {
-                     assert (shdr_info[cnt].shdr.sh_type == SHT_SYMTAB);
+                     elf_assert (shdr_info[cnt].shdr.sh_type == SHT_SYMTAB);
 
                      shdr_info[shdr_info[cnt].symtab_idx].data
                        = elf_getdata (shdr_info[shdr_info[cnt].symtab_idx].scn,
@@ -818,6 +836,9 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
                      else if (scnidx == SHN_XINDEX)
                        scnidx = xndx;
 
+                     if (scnidx >= shnum)
+                       goto illformed;
+
                      if (shdr_info[scnidx].idx == 0)
                        /* This symbol table has a real symbol in
                           a discarded section.  So preserve the
@@ -848,11 +869,15 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
                }
 
              /* Handle references through sh_info.  */
-             if (SH_INFO_LINK_P (&shdr_info[cnt].shdr)
-                 && shdr_info[shdr_info[cnt].shdr.sh_info].idx == 0)
+             if (SH_INFO_LINK_P (&shdr_info[cnt].shdr))
                {
-                 shdr_info[shdr_info[cnt].shdr.sh_info].idx = 1;
-                 changes |= shdr_info[cnt].shdr.sh_info < cnt;
+                 if (shdr_info[cnt].shdr.sh_info >= shnum)
+                   goto illformed;
+                 else if ( shdr_info[shdr_info[cnt].shdr.sh_info].idx == 0)
+                   {
+                     shdr_info[shdr_info[cnt].shdr.sh_info].idx = 1;
+                     changes |= shdr_info[cnt].shdr.sh_info < cnt;
+                   }
                }
 
              /* Mark the section as investigated.  */
@@ -994,7 +1019,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
          error (EXIT_FAILURE, 0, gettext ("while generating output file: %s"),
                 elf_errmsg (-1));
 
-       assert (elf_ndxscn (shdr_info[cnt].newscn) == shdr_info[cnt].idx);
+       elf_assert (elf_ndxscn (shdr_info[cnt].newscn) == shdr_info[cnt].idx);
 
        /* Add this name to the section header string table.  */
        shdr_info[cnt].se = ebl_strtabadd (shst, shdr_info[cnt].name, 0);
@@ -1031,7 +1056,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
        error (EXIT_FAILURE, 0,
               gettext ("while create section header section: %s"),
               elf_errmsg (-1));
-      assert (elf_ndxscn (shdr_info[cnt].newscn) == shdr_info[cnt].idx);
+      elf_assert (elf_ndxscn (shdr_info[cnt].newscn) == shdr_info[cnt].idx);
 
       shdr_info[cnt].data = elf_newdata (shdr_info[cnt].newscn);
       if (shdr_info[cnt].data == NULL)
@@ -1046,7 +1071,8 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
       shdr_info[cnt].data->d_align = 4;
       shdr_info[cnt].shdr.sh_size = shdr_info[cnt].data->d_size
        = crc_offset + 4;
-      shdr_info[cnt].data->d_buf = xcalloc (1, shdr_info[cnt].data->d_size);
+      debuglink_buf = xcalloc (1, shdr_info[cnt].data->d_size);
+      shdr_info[cnt].data->d_buf = debuglink_buf;
 
       strcpy (shdr_info[cnt].data->d_buf, debug_basename);
 
@@ -1087,7 +1113,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
     error (EXIT_FAILURE, 0,
           gettext ("while create section header section: %s"),
           elf_errmsg (-1));
-  assert (elf_ndxscn (shdr_info[cnt].newscn) == idx);
+  elf_assert (elf_ndxscn (shdr_info[cnt].newscn) == idx);
 
   /* Finalize the string table and fill in the correct indices in the
      section headers.  */
@@ -1177,20 +1203,20 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
                    shndxdata = elf_getdata (shdr_info[shdr_info[cnt].symtab_idx].scn,
                                             NULL);
 
-                   assert ((versiondata->d_size / sizeof (Elf32_Word))
+                   elf_assert ((versiondata->d_size / sizeof (Elf32_Word))
                            >= shdr_info[cnt].data->d_size / elsize);
                  }
 
                if (shdr_info[cnt].version_idx != 0)
                  {
-                   assert (shdr_info[cnt].shdr.sh_type == SHT_DYNSYM);
+                   elf_assert (shdr_info[cnt].shdr.sh_type == SHT_DYNSYM);
                    /* This section has associated version
                       information.  We have to modify that
                       information, too.  */
                    versiondata = elf_getdata (shdr_info[shdr_info[cnt].version_idx].scn,
                                               NULL);
 
-                   assert ((versiondata->d_size / sizeof (GElf_Versym))
+                   elf_assert ((versiondata->d_size / sizeof (GElf_Versym))
                            >= shdr_info[cnt].data->d_size / elsize);
                  }
 
@@ -1245,7 +1271,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
                      sec = shdr_info[sym->st_shndx].idx;
                    else
                      {
-                       assert (shndxdata != NULL);
+                       elf_assert (shndxdata != NULL);
 
                        sec = shdr_info[xshndx].idx;
                      }
@@ -1266,7 +1292,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
                            nxshndx = sec;
                          }
 
-                       assert (sec < SHN_LORESERVE || shndxdata != NULL);
+                       elf_assert (sec < SHN_LORESERVE || shndxdata != NULL);
 
                        if ((inner != destidx || nshndx != sym->st_shndx
                             || (shndxdata != NULL && nxshndx != xshndx))
@@ -1293,9 +1319,11 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
                      {
                        size_t sidx = (sym->st_shndx != SHN_XINDEX
                                        ? sym->st_shndx : xshndx);
-                       assert (GELF_ST_TYPE (sym->st_info) == STT_SECTION
-                               || (shdr_info[sidx].shdr.sh_type == SHT_GROUP
-                                   && shdr_info[sidx].shdr.sh_info == inner));
+                       elf_assert (GELF_ST_TYPE (sym->st_info) == STT_SECTION
+                                   || ((shdr_info[sidx].shdr.sh_type
+                                        == SHT_GROUP)
+                                       && (shdr_info[sidx].shdr.sh_info
+                                           == inner)));
                      }
                  }
 
@@ -1483,11 +1511,11 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
                  {
                    GElf_Sym sym_mem;
                    GElf_Sym *sym = gelf_getsym (symd, inner, &sym_mem);
-                   assert (sym != NULL);
+                   elf_assert (sym != NULL);
 
                    const char *name = elf_strptr (elf, strshndx,
                                                   sym->st_name);
-                   assert (name != NULL);
+                   elf_assert (name != NULL);
                    size_t hidx = elf_hash (name) % nbucket;
 
                    if (bucket[hidx] == 0)
@@ -1506,8 +1534,8 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
            else
              {
                /* Alpha and S390 64-bit use 64-bit SHT_HASH entries.  */
-               assert (shdr_info[cnt].shdr.sh_entsize
-                       == sizeof (Elf64_Xword));
+               elf_assert (shdr_info[cnt].shdr.sh_entsize
+                           == sizeof (Elf64_Xword));
 
                Elf64_Xword *bucket = (Elf64_Xword *) hashd->d_buf;
 
@@ -1537,11 +1565,11 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
                  {
                    GElf_Sym sym_mem;
                    GElf_Sym *sym = gelf_getsym (symd, inner, &sym_mem);
-                   assert (sym != NULL);
+                   elf_assert (sym != NULL);
 
                    const char *name = elf_strptr (elf, strshndx,
                                                   sym->st_name);
-                   assert (name != NULL);
+                   elf_assert (name != NULL);
                    size_t hidx = elf_hash (name) % nbucket;
 
                    if (bucket[hidx] == 0)
@@ -2013,6 +2041,9 @@ while computing checksum for debug information"));
              free (shdr_info[cnt].debug_data->d_buf);
          }
 
+      /* Free data we allocated for the .gnu_debuglink section. */
+      free (debuglink_buf);
+
       /* Free the memory.  */
       if ((shnum + 2) * sizeof (struct shdr_info) > MAX_STACK_ALLOC)
        free (shdr_info);