]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
strip: Harden against bogus input files. Don't leak tmp debug file on error.
authorMark Wielaard <mjw@redhat.com>
Tue, 12 May 2015 13:59:04 +0000 (15:59 +0200)
committerMark Wielaard <mjw@redhat.com>
Mon, 18 May 2015 13:48:04 +0000 (15:48 +0200)
There were various places where a bogus/unexpected input file would cause
eu-strip to crash. Also on an unexpected error eu-strip would leak the temp
debug file it was writing.

https://bugzilla.redhat.com/show_bug.cgi?id=1170810#c34

Signed-off-by: Mark Wielaard <mjw@redhat.com>
src/ChangeLog
src/strip.c

index 55bd4ccf9214f49b1806c30154f049d85891a1d5..02f658423d42a032d819d6362e028298e7821fe8 100644 (file)
@@ -1,3 +1,16 @@
+2015-05-12  Mark Wielaard  <mjw@redhat.com>
+
+       * strip.c (debug_fd): New static variable.
+       (tmp_debug_fname): Likewise.
+       (cleanup_debug): New function using the above to clean up temporary
+       debug file.
+       (INTERNAL_ERROR): Call cleanup_debug.
+       (handle_elf): Use debug_fd and tmp_debug_fname statics and call
+       cleanup_debug before any error. Use output_fname instead of fname in
+       error messages when it exists (-o was given). SHT_NOBITS sections
+       can also be moved freely even if SHF_ALLOC is set. Add various
+       sanity checks. Use elf_assert instead of plain assert.
+
 2015-05-08  Mark Wielaard  <mjw@redhat.com>
 
        * nm.c (show_symbols): Call gelf_fsize with EV_CURRENT.
index 365b18dda41c379263f7321ffe94f22ca87ee4bb..d63b6a822f583aadd99dba5ab35139e7541e385d 100644 (file)
@@ -115,9 +115,18 @@ static int handle_elf (int fd, Elf *elf, const char *prefix,
 static int handle_ar (int fd, Elf *elf, const char *prefix, const char *fname,
                      struct timespec tvp[2]);
 
+static int debug_fd = -1;
+static char *tmp_debug_fname = NULL;
+
+/* Close debug file descriptor, if opened. And remove temporary debug file.  */
+static void cleanup_debug ();
+
 #define INTERNAL_ERROR(fname) \
-  error (EXIT_FAILURE, 0, gettext ("%s: INTERNAL ERROR %d (%s): %s"),      \
-        fname, __LINE__, PACKAGE_VERSION, elf_errmsg (-1))
+  do { \
+    cleanup_debug (); \
+    error (EXIT_FAILURE, 0, gettext ("%s: INTERNAL ERROR %d (%s): %s"),      \
+          fname, __LINE__, PACKAGE_VERSION, elf_errmsg (-1)); \
+  } while (0)
 
 
 /* Name of the output file.  */
@@ -395,7 +404,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
   char *fullname = alloca (prefix_len + 1 + fname_len);
   char *cp = fullname;
   Elf *debugelf = NULL;
-  char *tmp_debug_fname = NULL;
+  tmp_debug_fname = NULL;
   int result = 0;
   size_t shdridx = 0;
   size_t shstrndx;
@@ -449,7 +458,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
        }
     }
 
-  int debug_fd = -1;
+  debug_fd = -1;
 
   /* Get the EBL handling.  Removing all debugging symbols with the -g
      option or resolving all relocations between debug sections with
@@ -474,7 +483,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
         the debug file if the file would not contain any
         information.  */
       size_t debug_fname_len = strlen (debug_fname);
-      tmp_debug_fname = (char *) alloca (debug_fname_len + sizeof (".XXXXXX"));
+      tmp_debug_fname = (char *) xmalloc (debug_fname_len + sizeof (".XXXXXX"));
       strcpy (mempcpy (tmp_debug_fname, debug_fname, debug_fname_len),
              ".XXXXXX");
 
@@ -495,13 +504,19 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
 
   /* Get the section header string table index.  */
   if (unlikely (elf_getshdrstrndx (elf, &shstrndx) < 0))
-    error (EXIT_FAILURE, 0,
-          gettext ("cannot get section header string table index"));
+    {
+      cleanup_debug ();
+      error (EXIT_FAILURE, 0,
+            gettext ("cannot get section header string table index"));
+    }
 
   /* Get the number of phdrs in the old file.  */
   size_t phnum;
   if (elf_getphdrnum (elf, &phnum) != 0)
-    error (EXIT_FAILURE, 0, gettext ("cannot get number of phdrs"));
+    {
+      cleanup_debug ();
+      error (EXIT_FAILURE, 0, gettext ("cannot get number of phdrs"));
+    }
 
   /* We now create a new ELF descriptor for the same file.  We
      construct it almost exactly in the same way with some information
@@ -517,7 +532,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
          && unlikely (gelf_newphdr (newelf, phnum) == 0)))
     {
       error (0, 0, gettext ("cannot create new file '%s': %s"),
-            output_fname, elf_errmsg (-1));
+            output_fname ?: fname, elf_errmsg (-1));
       goto fail;
     }
 
@@ -619,9 +634,10 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
        goto illformed;
 
       /* Sections in files other than relocatable object files which
-        are not loaded can be freely moved by us.  In relocatable
-        object files everything can be moved.  */
+        don't contain any file content or are not loaded can be freely
+        moved by us.  In relocatable object files everything can be moved.  */
       if (ehdr->e_type == ET_REL
+         || shdr_info[cnt].shdr.sh_type == SHT_NOBITS
          || (shdr_info[cnt].shdr.sh_flags & SHF_ALLOC) == 0)
        shdr_info[cnt].shdr.sh_offset = 0;
 
@@ -637,7 +653,8 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
          /* Cross-reference the sections contained in the section
             group.  */
          shdr_info[cnt].data = elf_getdata (shdr_info[cnt].scn, NULL);
-         if (shdr_info[cnt].data == NULL)
+         if (shdr_info[cnt].data == NULL
+             || shdr_info[cnt].data->d_size < sizeof (Elf32_Word))
            INTERNAL_ERROR (fname);
 
          /* XXX Fix for unaligned access.  */
@@ -708,7 +725,9 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
        while (idx != 0)
          {
            /* The section group data is already loaded.  */
-           assert (shdr_info[idx].data != NULL);
+           elf_assert (shdr_info[idx].data != NULL
+                       && shdr_info[idx].data->d_buf != NULL
+                       && shdr_info[idx].data->d_size >= sizeof (Elf32_Word));
 
            /* If the references section group is a normal section
               group and has one element remaining, or if it is an
@@ -764,11 +783,16 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
                  for (size_t in = 1;
                       in < shdr_info[cnt].data->d_size / sizeof (Elf32_Word);
                       ++in)
-                   if (shdr_info[grpref[in]].idx != 0)
+                   if (grpref[in] < shnum)
                      {
-                       shdr_info[cnt].idx = 1;
-                       break;
+                       if (shdr_info[grpref[in]].idx != 0)
+                         {
+                           shdr_info[cnt].idx = 1;
+                           break;
+                         }
                      }
+                   else
+                     goto illformed;
                }
            }
 
@@ -897,7 +921,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
 
              inline void check_preserved (size_t i)
              {
-               if (i != 0 && shdr_info[i].idx != 0
+               if (i != 0 && i < shnum + 2 && shdr_info[i].idx != 0
                    && shdr_info[i].debug_data == NULL)
                  {
                    if (shdr_info[i].data == NULL)
@@ -926,9 +950,12 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
        {
          scn = elf_newscn (debugelf);
          if (scn == NULL)
-           error (EXIT_FAILURE, 0,
-                  gettext ("while generating output file: %s"),
-                  elf_errmsg (-1));
+           {
+             cleanup_debug ();
+             error (EXIT_FAILURE, 0,
+                    gettext ("while generating output file: %s"),
+                    elf_errmsg (-1));
+           }
 
          bool discard_section = (shdr_info[cnt].idx > 0
                                  && shdr_info[cnt].debug_data == NULL
@@ -968,6 +995,8 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
            {
              /* Copy the original data before it gets modified.  */
              shdr_info[cnt].debug_data = debugdata;
+             if (debugdata->d_buf == NULL)
+               INTERNAL_ERROR (fname);
              debugdata->d_buf = memcpy (xmalloc (debugdata->d_size),
                                         debugdata->d_buf, debugdata->d_size);
            }
@@ -1003,8 +1032,11 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
   /* We need a string table for the section headers.  */
   shst = ebl_strtabinit (true);
   if (shst == NULL)
-    error (EXIT_FAILURE, errno, gettext ("while preparing output for '%s'"),
-          output_fname ?: fname);
+    {
+      cleanup_debug ();
+      error (EXIT_FAILURE, errno, gettext ("while preparing output for '%s'"),
+            output_fname ?: fname);
+    }
 
   /* Assign new section numbers.  */
   shdr_info[0].idx = 0;
@@ -1016,8 +1048,12 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
        /* Create a new section.  */
        shdr_info[cnt].newscn = elf_newscn (newelf);
        if (shdr_info[cnt].newscn == NULL)
-         error (EXIT_FAILURE, 0, gettext ("while generating output file: %s"),
-                elf_errmsg (-1));
+         {
+           cleanup_debug ();
+           error (EXIT_FAILURE, 0,
+                  gettext ("while generating output file: %s"),
+                  elf_errmsg (-1));
+         }
 
        elf_assert (elf_ndxscn (shdr_info[cnt].newscn) == shdr_info[cnt].idx);
 
@@ -1053,15 +1089,21 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
       /* Create the section.  */
       shdr_info[cnt].newscn = elf_newscn (newelf);
       if (shdr_info[cnt].newscn == NULL)
-       error (EXIT_FAILURE, 0,
-              gettext ("while create section header section: %s"),
-              elf_errmsg (-1));
+       {
+         cleanup_debug ();
+         error (EXIT_FAILURE, 0,
+                gettext ("while create section header section: %s"),
+                elf_errmsg (-1));
+       }
       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)
-       error (EXIT_FAILURE, 0, gettext ("cannot allocate section data: %s"),
-              elf_errmsg (-1));
+       {
+         cleanup_debug ();
+         error (EXIT_FAILURE, 0, gettext ("cannot allocate section data: %s"),
+                elf_errmsg (-1));
+       }
 
       char *debug_basename = basename (debug_fname_embed ?: debug_fname);
       off_t crc_offset = strlen (debug_basename) + 1;
@@ -1110,18 +1152,24 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
   /* Create the section.  */
   shdr_info[cnt].newscn = elf_newscn (newelf);
   if (shdr_info[cnt].newscn == NULL)
-    error (EXIT_FAILURE, 0,
-          gettext ("while create section header section: %s"),
-          elf_errmsg (-1));
+    {
+      cleanup_debug ();
+      error (EXIT_FAILURE, 0,
+            gettext ("while create section header section: %s"),
+            elf_errmsg (-1));
+    }
   elf_assert (elf_ndxscn (shdr_info[cnt].newscn) == idx);
 
   /* Finalize the string table and fill in the correct indices in the
      section headers.  */
   shstrtab_data = elf_newdata (shdr_info[cnt].newscn);
   if (shstrtab_data == NULL)
-    error (EXIT_FAILURE, 0,
-          gettext ("while create section header string table: %s"),
-          elf_errmsg (-1));
+    {
+      cleanup_debug ();
+      error (EXIT_FAILURE, 0,
+            gettext ("while create section header string table: %s"),
+            elf_errmsg (-1));
+    }
   ebl_strtabfinalize (shst, shstrtab_data);
 
   /* We have to set the section size.  */
@@ -1135,7 +1183,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
        Elf_Data *newdata;
 
        scn = elf_getscn (newelf, shdr_info[cnt].idx);
-       assert (scn != NULL);
+       elf_assert (scn != NULL);
 
        /* Update the name.  */
        shdr_info[cnt].shdr.sh_name = ebl_strtaboffset (shdr_info[cnt].se);
@@ -1148,13 +1196,17 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
 
        if (shdr_info[cnt].shdr.sh_type == SHT_GROUP)
          {
-           assert (shdr_info[cnt].data != NULL);
+           elf_assert (shdr_info[cnt].data != NULL
+                       && shdr_info[cnt].data->d_buf != NULL);
 
            Elf32_Word *grpref = (Elf32_Word *) shdr_info[cnt].data->d_buf;
            for (size_t inner = 0;
                 inner < shdr_info[cnt].data->d_size / sizeof (Elf32_Word);
                 ++inner)
-             grpref[inner] = shdr_info[grpref[inner]].idx;
+             if (grpref[inner] < shnum)
+               grpref[inner] = shdr_info[grpref[inner]].idx;
+             else
+               goto illformed;
          }
 
        /* Handle the SHT_REL, SHT_RELA, and SHF_INFO_LINK flag.  */
@@ -1196,14 +1248,14 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
 
                if (shdr_info[cnt].symtab_idx != 0)
                  {
-                   assert (shdr_info[cnt].shdr.sh_type == SHT_SYMTAB_SHNDX);
+                   elf_assert (shdr_info[cnt].shdr.sh_type == SHT_SYMTAB_SHNDX);
                    /* This section has extended section information.
                       We have to modify that information, too.  */
                    shndxdata = elf_getdata (shdr_info[shdr_info[cnt].symtab_idx].scn,
                                             NULL);
 
                    elf_assert ((versiondata->d_size / sizeof (Elf32_Word))
-                           >= shdr_info[cnt].data->d_size / elsize);
+                               >= shdr_info[cnt].data->d_size / elsize);
                  }
 
                if (shdr_info[cnt].version_idx != 0)
@@ -1215,8 +1267,10 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
                    versiondata = elf_getdata (shdr_info[shdr_info[cnt].version_idx].scn,
                                               NULL);
 
-                   elf_assert ((versiondata->d_size / sizeof (GElf_Versym))
-                           >= shdr_info[cnt].data->d_size / elsize);
+                   elf_assert (versiondata != NULL
+                               && versiondata->d_buf != NULL
+                               && ((versiondata->d_size / sizeof (GElf_Versym))
+                                   >= shdr_info[cnt].data->d_size / elsize));
                  }
 
                shdr_info[cnt].newsymidx
@@ -1270,7 +1324,8 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
                      sec = shdr_info[sym->st_shndx].idx;
                    else
                      {
-                       elf_assert (shndxdata != NULL);
+                       elf_assert (shndxdata != NULL
+                                   && shndxdata->d_buf != NULL);
 
                        sec = shdr_info[xshndx].idx;
                      }
@@ -1379,6 +1434,8 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
              /* libelf will use d_size to set sh_size.  */
              Elf_Data *debugdata = elf_getdata (elf_getscn (debugelf,
                                                             cnt), NULL);
+             if (debugdata == NULL)
+               INTERNAL_ERROR (fname);
              debugdata->d_size = newdata->d_size;
            }
        }
@@ -1390,6 +1447,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
          continue;
 
        const Elf32_Word symtabidx = shdr_info[cnt].old_sh_link;
+       elf_assert (symtabidx < shnum + 2);
        const Elf32_Word *const newsymidx = shdr_info[symtabidx].newsymidx;
        switch (shdr_info[cnt].shdr.sh_type)
          {
@@ -1416,10 +1474,14 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
                                       : elf_getscn (newelf,
                                                     shdr_info[cnt].idx),
                                       NULL);
-           assert (d != NULL);
+           elf_assert (d != NULL && d->d_buf != NULL
+                       && shdr_info[cnt].shdr.sh_entsize != 0);
            size_t nrels = (shdr_info[cnt].shdr.sh_size
                            / shdr_info[cnt].shdr.sh_entsize);
 
+           size_t symsize = gelf_fsize (elf, ELF_T_SYM, 1, EV_CURRENT);
+           const Elf32_Word symidxn = (shdr_info[symtabidx].data->d_size
+                                       / symsize);
            if (shdr_info[cnt].shdr.sh_type == SHT_REL)
              for (size_t relidx = 0; relidx < nrels; ++relidx)
                {
@@ -1428,6 +1490,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
                    INTERNAL_ERROR (fname);
 
                  size_t symidx = GELF_R_SYM (rel_mem.r_info);
+                 elf_assert (symidx < symidxn);
                  if (newsymidx[symidx] != symidx)
                    {
                      rel_mem.r_info
@@ -1446,6 +1509,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
                    INTERNAL_ERROR (fname);
 
                  size_t symidx = GELF_R_SYM (rel_mem.r_info);
+                 elf_assert (symidx < symidxn);
                  if (newsymidx[symidx] != symidx)
                    {
                      rel_mem.r_info
@@ -1464,7 +1528,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
 
            /* We have to recompute the hash table.  */
 
-           assert (shdr_info[cnt].idx > 0);
+           elf_assert (shdr_info[cnt].idx > 0);
 
            /* The hash section in the new file.  */
            scn = elf_getscn (newelf, shdr_info[cnt].idx);
@@ -1473,30 +1537,38 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
            Elf_Data *symd = elf_getdata (elf_getscn (newelf,
                                                      shdr_info[symtabidx].idx),
                                          NULL);
-           assert (symd != NULL);
+           elf_assert (symd != NULL && symd->d_buf != NULL);
 
            /* The hash table data.  */
            Elf_Data *hashd = elf_getdata (scn, NULL);
-           assert (hashd != NULL);
+           elf_assert (hashd != NULL && hashd->d_buf != NULL);
 
            if (shdr_info[cnt].shdr.sh_entsize == sizeof (Elf32_Word))
              {
                /* Sane arches first.  */
+               elf_assert (hashd->d_size >= 2 * sizeof (Elf32_Word));
                Elf32_Word *bucket = (Elf32_Word *) hashd->d_buf;
 
                size_t strshndx = shdr_info[symtabidx].old_sh_link;
                size_t elsize = gelf_fsize (elf, ELF_T_SYM, 1, EV_CURRENT);
 
+               Elf32_Word nchain = bucket[1];
+               Elf32_Word nbucket = bucket[0];
+               uint64_t used_buf = ((2ULL + nchain + nbucket)
+                                    * sizeof (Elf32_Word));
+               elf_assert (used_buf <= hashd->d_size);
+
                /* Adjust the nchain value.  The symbol table size
                   changed.  We keep the same size for the bucket array.  */
                bucket[1] = symd->d_size / elsize;
-               Elf32_Word nbucket = bucket[0];
                bucket += 2;
                Elf32_Word *chain = bucket + nbucket;
 
                /* New size of the section.  */
-               hashd->d_size = ((2 + symd->d_size / elsize + nbucket)
+               size_t n_size = ((2 + symd->d_size / elsize + nbucket)
                                 * sizeof (Elf32_Word));
+               elf_assert (n_size <= hashd->d_size);
+               hashd->d_size = n_size;
                update_section_size (hashd);
 
                /* Clear the arrays.  */
@@ -1513,7 +1585,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
 
                    const char *name = elf_strptr (elf, strshndx,
                                                   sym->st_name);
-                   elf_assert (name != NULL);
+                   elf_assert (name != NULL && nbucket != 0);
                    size_t hidx = elf_hash (name) % nbucket;
 
                    if (bucket[hidx] == 0)
@@ -1522,7 +1594,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
                      {
                        hidx = bucket[hidx];
 
-                       while (chain[hidx] != 0)
+                       while (chain[hidx] != 0 && chain[hidx] < nchain)
                          hidx = chain[hidx];
 
                        chain[hidx] = inner;
@@ -1540,16 +1612,25 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
                size_t strshndx = shdr_info[symtabidx].old_sh_link;
                size_t elsize = gelf_fsize (elf, ELF_T_SYM, 1, EV_CURRENT);
 
+               elf_assert (symd->d_size >= 2 * sizeof (Elf64_Xword));
+               Elf64_Xword nbucket = bucket[0];
+               Elf64_Xword nchain = bucket[1];
+               uint64_t maxwords = hashd->d_size / sizeof (Elf64_Xword);
+               elf_assert (maxwords >= 2
+                           && maxwords - 2 >= nbucket
+                           && maxwords - 2 - nbucket >= nchain);
+
                /* Adjust the nchain value.  The symbol table size
                   changed.  We keep the same size for the bucket array.  */
                bucket[1] = symd->d_size / elsize;
-               Elf64_Xword nbucket = bucket[0];
                bucket += 2;
                Elf64_Xword *chain = bucket + nbucket;
 
                /* New size of the section.  */
-               hashd->d_size = ((2 + symd->d_size / elsize + nbucket)
+               size_t n_size = ((2 + symd->d_size / elsize + nbucket)
                                 * sizeof (Elf64_Xword));
+               elf_assert (n_size <= hashd->d_size);
+               hashd->d_size = n_size;
                update_section_size (hashd);
 
                /* Clear the arrays.  */
@@ -1566,7 +1647,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
 
                    const char *name = elf_strptr (elf, strshndx,
                                                   sym->st_name);
-                   elf_assert (name != NULL);
+                   elf_assert (name != NULL && nbucket != 0);
                    size_t hidx = elf_hash (name) % nbucket;
 
                    if (bucket[hidx] == 0)
@@ -1575,7 +1656,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
                      {
                        hidx = bucket[hidx];
 
-                       while (chain[hidx] != 0)
+                       while (chain[hidx] != 0 && chain[hidx] < nchain)
                          hidx = chain[hidx];
 
                        chain[hidx] = inner;
@@ -1589,7 +1670,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
            if (no_symtab_updates ())
              break;
 
-           assert (shdr_info[cnt].idx > 0);
+           elf_assert (shdr_info[cnt].idx > 0);
 
            /* The symbol version section in the new file.  */
            scn = elf_getscn (newelf, shdr_info[cnt].idx);
@@ -1597,19 +1678,22 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
            /* The symbol table data.  */
            symd = elf_getdata (elf_getscn (newelf, shdr_info[symtabidx].idx),
                                NULL);
-           assert (symd != NULL);
+           elf_assert (symd != NULL && symd->d_buf != NULL);
+           size_t symz = gelf_fsize (elf, ELF_T_SYM, 1, EV_CURRENT);
+           const Elf32_Word syms = (shdr_info[symtabidx].data->d_size / symz);
 
            /* The version symbol data.  */
            Elf_Data *verd = elf_getdata (scn, NULL);
-           assert (verd != NULL);
+           elf_assert (verd != NULL && verd->d_buf != NULL);
 
            /* The symbol version array.  */
            GElf_Half *verstab = (GElf_Half *) verd->d_buf;
 
            /* Walk through the list and */
            size_t elsize = gelf_fsize (elf, verd->d_type, 1, EV_CURRENT);
-           for (size_t inner = 1; inner < verd->d_size / elsize; ++inner)
-             if (newsymidx[inner] != 0)
+           Elf32_Word vers = verd->d_size / elsize;
+           for (size_t inner = 1; inner < vers && inner < syms; ++inner)
+             if (newsymidx[inner] != 0 && newsymidx[inner] < vers)
                /* Overwriting the same array works since the
                   reordering can only move entries to lower indices
                   in the array.  */
@@ -1633,8 +1717,12 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
            scn = elf_getscn (newelf, shdr_info[cnt].idx);
            GElf_Shdr shdr_mem;
            GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
-           assert (shdr != NULL);
+           elf_assert (shdr != NULL);
 
+           size_t symsz = gelf_fsize (elf, ELF_T_SYM, 1, EV_CURRENT);
+           const Elf32_Word symn = (shdr_info[symtabidx].data->d_size
+                                    / symsz);
+           elf_assert (shdr->sh_info < symn);
            shdr->sh_info = newsymidx[shdr->sh_info];
 
            (void) gelf_update_shdr (scn, shdr);
@@ -1678,18 +1766,23 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
              /* OK, lets relocate all trivial cross debug section
                 relocations. */
              Elf_Data *reldata = elf_getdata (scn, NULL);
+             if (reldata == NULL || reldata->d_buf == NULL)
+               INTERNAL_ERROR (fname);
              /* We actually wanted the rawdata, but since we already
                 accessed it earlier as elf_getdata () that won't
                 work. But debug sections are all ELF_T_BYTE, so it
                 doesn't really matter.  */
              Elf_Data *tdata = elf_getdata (tscn, NULL);
-             if (tdata->d_type != ELF_T_BYTE)
+             if (tdata == NULL || tdata->d_buf == NULL
+                 || tdata->d_type != ELF_T_BYTE)
                INTERNAL_ERROR (fname);
 
              /* Pick up the symbol table and shndx table to
                 resolve relocation symbol indexes.  */
              Elf64_Word symt = shdr->sh_link;
              Elf_Data *symdata, *xndxdata;
+             elf_assert (symt < shnum + 2);
+             elf_assert (shdr_info[symt].symtab_idx < shnum + 2);
              symdata = (shdr_info[symt].debug_data
                         ?: shdr_info[symt].data);
              xndxdata = (shdr_info[shdr_info[symt].symtab_idx].debug_data
@@ -1722,6 +1815,9 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
                                                  &xndx);
                Elf32_Word sec = (sym->st_shndx == SHN_XINDEX
                                  ? xndx : sym->st_shndx);
+               if (sec >= shnum + 2)
+                 INTERNAL_ERROR (fname);
+
                if (ebl_debugscn_p (ebl, shdr_info[sec].name))
                  {
                    size_t size;
@@ -1745,7 +1841,10 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
 
                    if (offset > tdata->d_size
                        || tdata->d_size - offset < size)
-                     error (0, 0, gettext ("bad relocation"));
+                     {
+                       cleanup_debug ();
+                       error (EXIT_FAILURE, 0, gettext ("bad relocation"));
+                     }
 
                    /* When the symbol value is zero then for SHT_REL
                       sections this is all that needs to be checked.
@@ -1817,6 +1916,9 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
                return false;
              }
 
+             if (shdr->sh_entsize == 0)
+               INTERNAL_ERROR (fname);
+
              size_t nrels = shdr->sh_size / shdr->sh_entsize;
              size_t next = 0;
              if (shdr->sh_type == SHT_REL)
@@ -1863,7 +1965,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
       if (unlikely (elf_update (debugelf, ELF_C_WRITE) == -1))
        {
          error (0, 0, gettext ("while writing '%s': %s"),
-                debug_fname, elf_errmsg (-1));
+                tmp_debug_fname, elf_errmsg (-1));
          result = 1;
          goto fail_close;
        }
@@ -1879,6 +1981,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
        }
 
       /* The temporary file does not exist anymore.  */
+      free (tmp_debug_fname);
       tmp_debug_fname = NULL;
 
       if (!remove_shdrs)
@@ -1951,7 +2054,8 @@ while computing checksum for debug information"));
   if (gelf_update_ehdr (newelf, newehdr) == 0)
     {
       error (0, 0, gettext ("%s: error while creating ELF header: %s"),
-            fname, elf_errmsg (-1));
+            output_fname ?: fname, elf_errmsg (-1));
+      cleanup_debug ();
       return 1;
     }
 
@@ -1960,6 +2064,7 @@ while computing checksum for debug information"));
     {
       error (0, 0, gettext ("%s: error while reading the file: %s"),
             fname, elf_errmsg (-1));
+      cleanup_debug ();
       return 1;
     }
 
@@ -1973,7 +2078,7 @@ while computing checksum for debug information"));
   if (elf_update (newelf, ELF_C_WRITE) == -1)
     {
       error (0, 0, gettext ("while writing '%s': %s"),
-            fname, elf_errmsg (-1));
+            output_fname ?: fname, elf_errmsg (-1));
       result = 1;
     }
 
@@ -1998,7 +2103,7 @@ while computing checksum for debug information"));
              || ftruncate64 (fd, shdr_info[shdridx].shdr.sh_offset) < 0)
            {
              error (0, errno, gettext ("while writing '%s'"),
-                    fname);
+                    output_fname ?: fname);
              result = 1;
            }
        }
@@ -2018,7 +2123,7 @@ while computing checksum for debug information"));
              || ftruncate64 (fd, shdr_info[shdridx].shdr.sh_offset) < 0)
            {
              error (0, errno, gettext ("while writing '%s'"),
-                    fname);
+                    output_fname ?: fname);
              result = 1;
            }
        }
@@ -2054,8 +2159,8 @@ while computing checksum for debug information"));
   /* That was it.  Close the descriptors.  */
   if (elf_end (newelf) != 0)
     {
-      error (0, 0, gettext ("error while finishing '%s': %s"), fname,
-            elf_errmsg (-1));
+      error (0, 0, gettext ("error while finishing '%s': %s"),
+            output_fname ?: fname, elf_errmsg (-1));
       result = 1;
     }
 
@@ -2071,13 +2176,7 @@ while computing checksum for debug information"));
   if (ebl != NULL)
     ebl_closebackend (ebl);
 
-  /* Close debug file descriptor, if opened */
-  if (debug_fd >= 0)
-    {
-      if (tmp_debug_fname != NULL)
-       unlink (tmp_debug_fname);
-      close (debug_fd);
-    }
+  cleanup_debug ();
 
   /* If requested, preserve the timestamp.  */
   if (tvp != NULL)
@@ -2098,6 +2197,21 @@ cannot set access and modification date of '%s'"),
   return result;
 }
 
+static void
+cleanup_debug ()
+{
+  if (debug_fd >= 0)
+    {
+      if (tmp_debug_fname != NULL)
+       {
+         unlink (tmp_debug_fname);
+         free (tmp_debug_fname);
+         tmp_debug_fname = NULL;
+       }
+      close (debug_fd);
+      debug_fd = -1;
+    }
+}
 
 static int
 handle_ar (int fd, Elf *elf, const char *prefix, const char *fname,