Blob Blame History Raw
commit 7bf4b63a4980788e6c1969cae02f0483e79c069f
Author: Mark Wielaard <mjw@redhat.com>
Date:   Thu Oct 6 16:06:32 2016 +0200

    strip: Don't remove real symbols from allocated symbol tables.
    
    Having a symbol in an allocated symbol table (like .dynsym) that
    points to an unallocated section is wrong. Traditionally strip
    has removed such symbols if they are section or group symbols.
    But removing a real symbol from an allocate symbol table is hard
    and probably a mistake. Really removing it means rewriting the
    dynamic segment and hash sections. Since we don't do that, don't
    remove the symbol (and corrupt the ELF file). Do warn and set
    the symbol section to SHN_UNDEF.
    
    https://bugzilla.redhat.com/show_bug.cgi?id=1380961
    
    Signed-off-by: Mark Wielaard <mjw@redhat.com>

diff --git a/src/ChangeLog b/src/ChangeLog
index e5b3b20..70d11f2 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,8 @@
+2016-10-06  Mark Wielaard  <mjw@redhat.com>
+
+	* strip.c (handle_elf): Don't remove real symbols from allocated
+	symbol tables.
+
 2016-08-25  Mark Wielaard  <mjw@redhat.com>
 
 	* strip.c (handle_elf): Recompress with ELF_CHF_FORCE.
diff --git a/src/strip.c b/src/strip.c
index da093e9..819b67e 100644
--- a/src/strip.c
+++ b/src/strip.c
@@ -1341,15 +1341,12 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
 
 		    /* Get the full section index, if necessary from the
 		       XINDEX table.  */
-		    if (sym->st_shndx != SHN_XINDEX)
-		      sec = shdr_info[sym->st_shndx].idx;
-		    else
-		      {
-			elf_assert (shndxdata != NULL
-				    && shndxdata->d_buf != NULL);
-
-			sec = shdr_info[xshndx].idx;
-		      }
+		    if (sym->st_shndx == SHN_XINDEX)
+		      elf_assert (shndxdata != NULL
+				  && shndxdata->d_buf != NULL);
+		    size_t sidx = (sym->st_shndx != SHN_XINDEX
+				   ? sym->st_shndx : xshndx);
+		    sec = shdr_info[sidx].idx;
 
 		    if (sec != 0)
 		      {
@@ -1387,6 +1384,24 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
 			    shdr_info[cnt].shdr.sh_info = destidx - 1;
 			  }
 		      }
+		    else if ((shdr_info[cnt].shdr.sh_flags & SHF_ALLOC) != 0
+			     && GELF_ST_TYPE (sym->st_info) != STT_SECTION
+			     && shdr_info[sidx].shdr.sh_type != SHT_GROUP)
+		      {
+			/* Removing a real symbol from an allocated
+			   symbol table is hard and probably a
+			   mistake.  Really removing it means
+			   rewriting the dynamic segment and hash
+			   sections.  Just warn and set the symbol
+			   section to UNDEF.  */
+			error (0, 0,
+			       gettext ("Cannot remove symbol [%zd] from allocated symbol table [%zd]"), inner, cnt);
+			sym->st_shndx = SHN_UNDEF;
+			if (gelf_update_sym (shdr_info[cnt].data, destidx,
+					     sym) == 0)
+			  INTERNAL_ERROR (fname);
+			shdr_info[cnt].newsymidx[inner] = destidx++;
+		      }
 		    else if (debug_fname != NULL
 			     && shdr_info[cnt].debug_data == NULL)
 		      /* The symbol points to a section that is discarded
@@ -1394,8 +1409,6 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
 			 this is a section or group signature symbol
 			 for a section which has been removed.  */
 		      {
-			size_t sidx = (sym->st_shndx != SHN_XINDEX
-					? sym->st_shndx : xshndx);
 			elf_assert (GELF_ST_TYPE (sym->st_info) == STT_SECTION
 				    || ((shdr_info[sidx].shdr.sh_type
 					 == SHT_GROUP)