Blob Blame History Raw
commit ed9d3bc176b3f0318551d9214b1cec4e49197842
Author: Roland McGrath <roland@redhat.com>
Date:   Thu Jan 1 21:22:18 2009 -0800

    Fill gaps and update bookkeeping between all sections, not only before a dirty one.
---
 libelf/ChangeLog          |    7 ++
 libelf/elf32_updatefile.c |  142 +++++++++++++++++++++++++++------------------
 2 files changed, 93 insertions(+), 56 deletions(-)

diff --git a/libelf/ChangeLog b/libelf/ChangeLog
index 9578f8b..bb487b1 100644
--- a/libelf/ChangeLog
+++ b/libelf/ChangeLog
@@ -1,3 +1,10 @@
+2009-01-01  Roland McGrath  <roland@redhat.com>
+
+	* elf32_updatefile.c (__elfw2(LIBELFBITS,updatemmap)):
+	Fill gaps and update bookkeeping between all sections,
+	not only before a dirty one.
+	(__elfw2(LIBELFBITS,updatefile)): Likewise.
+
 2008-12-11  Roland McGrath  <roland@redhat.com>
 
 	* elf32_updatefile.c (__elfw2(LIBELFBITS,updatemmap)): Handle
diff --git a/libelf/elf32_updatefile.c b/libelf/elf32_updatefile.c
index e88f4a4..4e170cb 100644
--- a/libelf/elf32_updatefile.c
+++ b/libelf/elf32_updatefile.c
@@ -1,5 +1,5 @@
 /* Write changed data structures.
-   Copyright (C) 2000, 2001, 2002, 2004, 2005, 2006, 2007, 2008 Red Hat, Inc.
+   Copyright (C) 2000,2001,2002,2004,2005,2006,2007,2008,2009 Red Hat, Inc.
    This file is part of Red Hat elfutils.
    Written by Ulrich Drepper <drepper@redhat.com>, 2000.
 
@@ -127,7 +127,6 @@ internal_function
 __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum)
 {
   ElfW2(LIBELFBITS,Ehdr) *ehdr;
-  char *last_position;
 
   /* We need the ELF header several times.  */
   ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
@@ -204,10 +203,11 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum)
 
   /* From now on we have to keep track of the last position to eventually
      fill the gaps with the prescribed fill byte.  */
-  last_position = ((char *) elf->map_address + elf->start_offset
-		   + MAX (elf_typesize (LIBELFBITS, ELF_T_EHDR, 1),
-			  ehdr->e_phoff)
-		   + elf_typesize (LIBELFBITS, ELF_T_PHDR, ehdr->e_phnum));
+  char *last_position = ((char *) elf->map_address + elf->start_offset
+			 + MAX (elf_typesize (LIBELFBITS, ELF_T_EHDR, 1),
+				ehdr->e_phoff)
+			 + elf_typesize (LIBELFBITS,
+					 ELF_T_PHDR, ehdr->e_phnum));
 
   /* Write all the sections.  Well, only those which are modified.  */
   if (shnum > 0)
@@ -278,6 +278,35 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum)
 	    }
 	}
 
+      /* Prepare to write at START, and then update LAST_POSITION.
+	 If LAST_POSITION was before START, fill in the gap.  */
+      inline void prepare_position (char *start)
+      {
+	if (start > last_position)
+	  {
+	    /* This code assumes that the data blocks for
+	       a section are ordered by offset.  */
+	    size_t written = 0;
+
+	    if (last_position < shdr_start)
+	      {
+		written = MIN (start - last_position,
+			       shdr_start - last_position);
+
+		memset (last_position, __libelf_fill_byte, written);
+	      }
+
+	    if (last_position + written != start && shdr_end < start)
+	      memset (shdr_end, __libelf_fill_byte, start - shdr_end);
+	  }
+
+	/* Let it go backward if the sections use a bogus layout with
+	   overlaps.  We'll overwrite the stupid user's section data
+	   with the latest one, rather than crashing.  */
+
+	last_position = start;
+      }
+
       /* Iterate over all the section in the order in which they
 	 appear in the output file.  */
       for (size_t cnt = 0; cnt < shnum; ++cnt)
@@ -298,38 +327,10 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum)
 		assert (dl->data.d.d_size <= (shdr->sh_size
 					      - (GElf_Off) dl->data.d.d_off));
 
+		prepare_position (scn_start + dl->data.d.d_off);
+
 		if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY)
 		  {
-		    if (scn_start + dl->data.d.d_off > last_position)
-		      {
-			/* This code assumes that the data blocks for
-			   a section are ordered by offset.  */
-			size_t written = 0;
-
-			if (last_position < shdr_start)
-			  {
-			    written = MIN (scn_start + dl->data.d.d_off
-					   - last_position,
-					   shdr_start - last_position);
-
-			    memset (last_position, __libelf_fill_byte,
-				    written);
-			  }
-
-			if (last_position + written
-			    != scn_start + dl->data.d.d_off
-			    && shdr_end < scn_start + dl->data.d.d_off)
-			  memset (shdr_end, __libelf_fill_byte,
-				  scn_start + dl->data.d.d_off - shdr_end);
-		      }
-
-		    /* Let it go backward if the sections use a bogus
-		       layout with overlaps.  We'll overwrite the stupid
-		       user's section data with the latest one, rather than
-		       crashing.  */
-
-		    last_position = scn_start + dl->data.d.d_off;
-
 		    if (unlikely (change_bo))
 		      {
 #if EV_NUM != 2
@@ -362,9 +363,19 @@ __elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum)
 		dl = dl->next;
 	      }
 	    while (dl != NULL);
-	  else if (shdr->sh_type != SHT_NOBITS && scn->index != 0)
-	    /* We have to trust the existing section header information.  */
-	    last_position += shdr->sh_size;
+	  else if (shdr->sh_type != SHT_NOBITS && scn->index != 0
+		   && shdr->sh_size != 0)
+	    {
+	      /* We have to trust the existing section header information.
+
+		 If there are any contents at all, we must be sure we've
+		 filled in any gap before them, even if it turns out we
+		 aren't touching the contents after the gap.  */
+
+	      prepare_position (scn_start);
+
+	      last_position += shdr->sh_size;
+	    }
 
 	  scn->flags &= ~ELF_F_DIRTY;
 	}
@@ -622,31 +633,39 @@ __elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum)
 	  off_t scn_start = elf->start_offset + shdr->sh_offset;
 	  Elf_Data_List *dl = &scn->data_list;
 
+	  /* Prepare to write at START, and then update LAST_OFFSET.
+	     If LAST_OFFSET was before START, fill in the gap.  */
+	  inline bool prepare_offset (off_t start)
+	  {
+	    if (start > last_offset)
+	      {
+		if (unlikely (fill (elf->fildes, last_offset,
+				    start - last_offset, fillbuf,
+				    &filled) != 0))
+		  return true;
+	      }
+
+	    /* Let it go backward if the sections use a bogus layout with
+	       overlaps.  We'll overwrite the stupid user's section data
+	       with the latest one, rather than crashing.  */
+
+	    last_offset = start;
+
+	    return false;
+	  }
+
 	  if (shdr->sh_type != SHT_NOBITS && scn->data_list_rear != NULL
 	      && scn->index != 0)
 	    do
 	      {
+		if (unlikely (prepare_offset (scn_start + dl->data.d.d_off)))
+		  return 1;
+
 		if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY)
 		  {
 		    char tmpbuf[MAX_TMPBUF];
 		    void *buf = dl->data.d.d_buf;
 
-		    if (scn_start + dl->data.d.d_off > last_offset)
-		      {
-			if (unlikely (fill (elf->fildes, last_offset,
-					    (scn_start + dl->data.d.d_off)
-					    - last_offset, fillbuf,
-					    &filled) != 0))
-			  return 1;
-		      }
-
-		    /* Let it go backward if the sections use a bogus
-		       layout with overlaps.  We'll overwrite the stupid
-		       user's section data with the latest one, rather than
-		       crashing.  */
-
-		    last_offset = scn_start + dl->data.d.d_off;
-
 		    if (unlikely (change_bo))
 		      {
 #if EV_NUM != 2
@@ -696,7 +715,18 @@ __elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum)
 	      }
 	    while (dl != NULL);
 	  else if (shdr->sh_type != SHT_NOBITS && scn->index != 0)
-	    last_offset = scn_start + shdr->sh_size;
+	    {
+	      /* We have to trust the existing section header information.
+
+		 If there are any contents at all, we must be sure we've
+		 filled in any gap before them, even if it turns out we
+		 aren't touching the contents after the gap.  */
+
+	      if (shdr->sh_size != 0 && unlikely (prepare_offset (scn_start)))
+		return 1;
+
+	      last_offset = scn_start + shdr->sh_size;
+	    }
 
 	  /* Collect the section header table information.  */
 	  if (unlikely (change_bo))