This is the mail archive of the elfutils-devel@sourceware.org mailing list for the elfutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] strip: Harden against bogus input files. Don't leak temp debug file on error.


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.

Signed-off-by: Mark Wielaard <mjw@redhat.com>
---
 src/ChangeLog |  13 +++
 src/strip.c   | 262 +++++++++++++++++++++++++++++++++++++++++-----------------
 2 files changed, 200 insertions(+), 75 deletions(-)

diff --git a/src/ChangeLog b/src/ChangeLog
index 55bd4cc..02f6584 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -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.
diff --git a/src/strip.c b/src/strip.c
index 365b18d..63f5b9f 100644
--- a/src/strip.c
+++ b/src/strip.c
@@ -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.  */
@@ -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.  */
@@ -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,7 @@ 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));
       return 1;
     }
 
@@ -1973,7 +2076,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 +2101,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 +2121,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 +2157,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 +2174,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 +2195,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,
-- 
2.1.0


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]