public inbox for elfutils@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] RFC: strip with mixed allocated/non-allocated sections
@ 2018-07-29 22:36 Mark Wielaard
  2018-08-30  9:51 ` Mark Wielaard
  0 siblings, 1 reply; 2+ messages in thread
From: Mark Wielaard @ 2018-07-29 22:36 UTC (permalink / raw)
  To: elfutils-devel; +Cc: nickc, Mark Wielaard

Normally in non-ET_REL files all allocated sections come before
all non-allocated sections. eu-strip relies on this when stripping
a file and calculating the file offsets. But recently on Fedora
there are non-allocated .gnu.build.attributes NOTE sections in
the middle of the allocated sections, with a sh_offset field that
is larger then the next section. This confuses eu-strip so much that
it might corrupt the stripped file.

Work around this by calculating the sh_offset fields in two phases
when detecting mixed allocated/non-allocated sections. First handle
the allocated ones, then use the offset after the last allocated
section to calculate the offsets of the non-allocated sections left
in the stripped file.
---
 src/strip.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 65 insertions(+), 15 deletions(-)

diff --git a/src/strip.c b/src/strip.c
index 791347c..1367de7 100644
--- a/src/strip.c
+++ b/src/strip.c
@@ -661,6 +661,11 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
       memset (shdr_info, '\0', (shnum + 2) * sizeof (struct shdr_info));
     }
 
+  /* Track whether allocated sections all come before non-allocated ones.  */
+  bool seen_allocated = false;
+  bool seen_unallocated = false;
+  bool mixed_allocated_unallocated = false;
+
   /* Prepare section information data structure.  */
   scn = NULL;
   cnt = 1;
@@ -676,6 +681,17 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
       if (gelf_getshdr (scn, &shdr_info[cnt].shdr) == NULL)
 	INTERNAL_ERROR (fname);
 
+      /* Normally (in non-ET_REL files) we see all allocated sections first,
+	 then all non-allocated.  */
+      if ((shdr_info[cnt].shdr.sh_flags & SHF_ALLOC) == 0)
+	seen_unallocated = true;
+      else
+	{
+	  if (seen_unallocated && seen_allocated)
+	    mixed_allocated_unallocated = true;
+	  seen_allocated = true;
+	}
+
       /* Get the name of the section.  */
       shdr_info[cnt].name = elf_strptr (elf, shstrndx,
 					shdr_info[cnt].shdr.sh_name);
@@ -1535,24 +1551,58 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
 	      }
 	  }
 
-	/* If we have to, compute the offset of the section.  */
-	if (shdr_info[cnt].shdr.sh_offset == 0)
-	  shdr_info[cnt].shdr.sh_offset
-	    = ((lastoffset + shdr_info[cnt].shdr.sh_addralign - 1)
-	       & ~((GElf_Off) (shdr_info[cnt].shdr.sh_addralign - 1)));
-
-	/* Set the section header in the new file.  */
-	if (unlikely (gelf_update_shdr (scn, &shdr_info[cnt].shdr) == 0))
-	  /* There cannot be any overflows.  */
-	  INTERNAL_ERROR (fname);
+	/* If we have to, compute the offset of the section.
+	   If allocate and unallocated sections are mixed, we only update
+	   the allocated ones now.  The unallocated ones come second.  */
+	if (! mixed_allocated_unallocated
+	    || (shdr_info[cnt].shdr.sh_flags & SHF_ALLOC) != 0)
+	  {
+	    if (shdr_info[cnt].shdr.sh_offset == 0)
+	      shdr_info[cnt].shdr.sh_offset
+		= ((lastoffset + shdr_info[cnt].shdr.sh_addralign - 1)
+		   & ~((GElf_Off) (shdr_info[cnt].shdr.sh_addralign - 1)));
+
+	    /* Set the section header in the new file.  */
+	    if (unlikely (gelf_update_shdr (scn, &shdr_info[cnt].shdr) == 0))
+	      /* There cannot be any overflows.  */
+	      INTERNAL_ERROR (fname);
 
-	/* Remember the last section written so far.  */
-	GElf_Off filesz = (shdr_info[cnt].shdr.sh_type != SHT_NOBITS
-			   ? shdr_info[cnt].shdr.sh_size : 0);
-	if (lastoffset < shdr_info[cnt].shdr.sh_offset + filesz)
-	  lastoffset = shdr_info[cnt].shdr.sh_offset + filesz;
+	    /* Remember the last section written so far.  */
+	    GElf_Off filesz = (shdr_info[cnt].shdr.sh_type != SHT_NOBITS
+			       ? shdr_info[cnt].shdr.sh_size : 0);
+	    if (lastoffset < shdr_info[cnt].shdr.sh_offset + filesz)
+	      lastoffset = shdr_info[cnt].shdr.sh_offset + filesz;
+	  }
       }
 
+  /* We might have to update the unallocated sections after we done the
+     allocated ones.  lastoffset is set to right after the last allocated
+     section.  */
+  if (mixed_allocated_unallocated)
+    for (cnt = 1; cnt <= shdridx; ++cnt)
+      if (shdr_info[cnt].idx > 0)
+	{
+	  scn = elf_getscn (newelf, shdr_info[cnt].idx);
+	  if ((shdr_info[cnt].shdr.sh_flags & SHF_ALLOC) == 0)
+	    {
+	      if (shdr_info[cnt].shdr.sh_offset == 0)
+		shdr_info[cnt].shdr.sh_offset
+		  = ((lastoffset + shdr_info[cnt].shdr.sh_addralign - 1)
+		     & ~((GElf_Off) (shdr_info[cnt].shdr.sh_addralign - 1)));
+
+	      /* Set the section header in the new file.  */
+	      if (unlikely (gelf_update_shdr (scn, &shdr_info[cnt].shdr) == 0))
+		/* There cannot be any overflows.  */
+		INTERNAL_ERROR (fname);
+
+	      /* Remember the last section written so far.  */
+	      GElf_Off filesz = (shdr_info[cnt].shdr.sh_type != SHT_NOBITS
+				 ? shdr_info[cnt].shdr.sh_size : 0);
+	      if (lastoffset < shdr_info[cnt].shdr.sh_offset + filesz)
+		lastoffset = shdr_info[cnt].shdr.sh_offset + filesz;
+	    }
+	}
+
   /* Adjust symbol references if symbol tables changed.  */
   if (any_symtab_changes)
     /* Find all relocation sections which use this symbol table.  */
-- 
1.8.3.1

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [PATCH] RFC: strip with mixed allocated/non-allocated sections
  2018-07-29 22:36 [PATCH] RFC: strip with mixed allocated/non-allocated sections Mark Wielaard
@ 2018-08-30  9:51 ` Mark Wielaard
  0 siblings, 0 replies; 2+ messages in thread
From: Mark Wielaard @ 2018-08-30  9:51 UTC (permalink / raw)
  To: elfutils-devel; +Cc: nickc

On Mon, 2018-07-30 at 00:35 +0200, Mark Wielaard wrote:
> Normally in non-ET_REL files all allocated sections come before
> all non-allocated sections. eu-strip relies on this when stripping
> a file and calculating the file offsets. But recently on Fedora
> there are non-allocated .gnu.build.attributes NOTE sections in
> the middle of the allocated sections, with a sh_offset field that
> is larger then the next section. This confuses eu-strip so much that
> it might corrupt the stripped file.
> 
> Work around this by calculating the sh_offset fields in two phases
> when detecting mixed allocated/non-allocated sections. First handle
> the allocated ones, then use the offset after the last allocated
> section to calculate the offsets of the non-allocated sections left
> in the stripped file.

This has been integrated in the fedora package for the last 4 weeks and
seems to work as intended. I have added a ChangeLog entry and pushed to
master.

Cheers,

Mark

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2018-08-30  9:51 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-07-29 22:36 [PATCH] RFC: strip with mixed allocated/non-allocated sections Mark Wielaard
2018-08-30  9:51 ` Mark Wielaard

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).