Blame libelf/elf32_updatefile.c

Packit 032894
/* Write changed data structures.
Packit 032894
   Copyright (C) 2000-2010, 2014, 2015, 2016, 2018 Red Hat, Inc.
Packit 032894
   This file is part of elfutils.
Packit 032894
   Written by Ulrich Drepper <drepper@redhat.com>, 2000.
Packit 032894
Packit 032894
   This file is free software; you can redistribute it and/or modify
Packit 032894
   it under the terms of either
Packit 032894
Packit 032894
     * the GNU Lesser General Public License as published by the Free
Packit 032894
       Software Foundation; either version 3 of the License, or (at
Packit 032894
       your option) any later version
Packit 032894
Packit 032894
   or
Packit 032894
Packit 032894
     * the GNU General Public License as published by the Free
Packit 032894
       Software Foundation; either version 2 of the License, or (at
Packit 032894
       your option) any later version
Packit 032894
Packit 032894
   or both in parallel, as here.
Packit 032894
Packit 032894
   elfutils is distributed in the hope that it will be useful, but
Packit 032894
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 032894
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 032894
   General Public License for more details.
Packit 032894
Packit 032894
   You should have received copies of the GNU General Public License and
Packit 032894
   the GNU Lesser General Public License along with this program.  If
Packit 032894
   not, see <http://www.gnu.org/licenses/>.  */
Packit 032894
Packit 032894
#ifdef HAVE_CONFIG_H
Packit 032894
# include <config.h>
Packit 032894
#endif
Packit 032894
Packit 032894
#include <assert.h>
Packit 032894
#include <errno.h>
Packit 032894
#include <libelf.h>
Packit 032894
#include <stdbool.h>
Packit 032894
#include <stdlib.h>
Packit 032894
#include <string.h>
Packit 032894
#include <unistd.h>
Packit 032894
#include <sys/mman.h>
Packit 032894
Packit 032894
#include <system.h>
Packit 032894
#include "libelfP.h"
Packit 032894
Packit 032894
Packit 032894
#ifndef LIBELFBITS
Packit 032894
# define LIBELFBITS 32
Packit 032894
#endif
Packit 032894
Packit 032894
Packit 032894
static int
Packit 032894
compare_sections (const void *a, const void *b)
Packit 032894
{
Packit 032894
  const Elf_Scn **scna = (const Elf_Scn **) a;
Packit 032894
  const Elf_Scn **scnb = (const Elf_Scn **) b;
Packit 032894
Packit 032894
  if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_offset
Packit 032894
      < (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_offset)
Packit 032894
    return -1;
Packit 032894
Packit 032894
  if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_offset
Packit 032894
      > (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_offset)
Packit 032894
    return 1;
Packit 032894
Packit 032894
  if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_size
Packit 032894
      < (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_size)
Packit 032894
    return -1;
Packit 032894
Packit 032894
  if ((*scna)->shdr.ELFW(e,LIBELFBITS)->sh_size
Packit 032894
      > (*scnb)->shdr.ELFW(e,LIBELFBITS)->sh_size)
Packit 032894
    return 1;
Packit 032894
Packit 032894
  if ((*scna)->index < (*scnb)->index)
Packit 032894
    return -1;
Packit 032894
Packit 032894
  if ((*scna)->index > (*scnb)->index)
Packit 032894
    return 1;
Packit 032894
Packit 032894
  return 0;
Packit 032894
}
Packit 032894
Packit 032894
Packit 032894
/* Insert the sections in the list into the provided array and sort
Packit 032894
   them according to their start offsets.  For sections with equal
Packit 032894
   start offsets, the size is used; for sections with equal start
Packit 032894
   offsets and sizes, the section index is used.  Sorting by size
Packit 032894
   ensures that zero-length sections are processed first, which
Packit 032894
   is what we want since they do not advance our file writing position.  */
Packit 032894
static void
Packit 032894
sort_sections (Elf_Scn **scns, Elf_ScnList *list)
Packit 032894
{
Packit 032894
  Elf_Scn **scnp = scns;
Packit 032894
  do
Packit 032894
    for (size_t cnt = 0; cnt < list->cnt; ++cnt)
Packit 032894
      *scnp++ = &list->data[cnt];
Packit 032894
  while ((list = list->next) != NULL);
Packit 032894
Packit 032894
  qsort (scns, scnp - scns, sizeof (*scns), compare_sections);
Packit 032894
}
Packit 032894
Packit 032894
Packit 032894
static inline void
Packit 032894
fill_mmap (size_t offset, char *last_position, char *scn_start,
Packit 032894
           char *const shdr_start, char *const shdr_end)
Packit 032894
{
Packit 032894
  size_t written = 0;
Packit 032894
Packit 032894
  if (last_position < shdr_start)
Packit 032894
    {
Packit 032894
      written = MIN (scn_start + offset - last_position,
Packit 032894
                     shdr_start - last_position);
Packit 032894
Packit 032894
      memset (last_position, __libelf_fill_byte, written);
Packit 032894
    }
Packit 032894
Packit 032894
  if (last_position + written != scn_start + offset
Packit 032894
      && shdr_end < scn_start + offset)
Packit 032894
    {
Packit 032894
      char *fill_start = MAX (shdr_end, scn_start);
Packit 032894
      memset (fill_start, __libelf_fill_byte,
Packit 032894
              scn_start + offset - fill_start);
Packit 032894
    }
Packit 032894
}
Packit 032894
Packit 032894
int
Packit 032894
internal_function
Packit 032894
__elfw2(LIBELFBITS,updatemmap) (Elf *elf, int change_bo, size_t shnum)
Packit 032894
{
Packit 032894
  bool previous_scn_changed = false;
Packit 032894
Packit 032894
  /* We need the ELF header several times.  */
Packit 032894
  ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
Packit 032894
Packit 032894
  /* Write out the ELF header.  */
Packit 032894
  if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY)
Packit 032894
    {
Packit 032894
      /* If the type sizes should be different at some time we have to
Packit 032894
	 rewrite this code.  */
Packit 032894
      assert (sizeof (ElfW2(LIBELFBITS,Ehdr))
Packit 032894
	      == elf_typesize (LIBELFBITS, ELF_T_EHDR, 1));
Packit 032894
Packit 032894
      if (unlikely (change_bo))
Packit 032894
	{
Packit 032894
	  /* Today there is only one version of the ELF header.  */
Packit 032894
#undef fctp
Packit 032894
#define fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR]
Packit 032894
Packit 032894
	  /* Do the real work.  */
Packit 032894
	  (*fctp) ((char *) elf->map_address + elf->start_offset, ehdr,
Packit 032894
		   sizeof (ElfW2(LIBELFBITS,Ehdr)), 1);
Packit 032894
	}
Packit 032894
      else if (elf->map_address + elf->start_offset != ehdr)
Packit 032894
	memcpy (elf->map_address + elf->start_offset, ehdr,
Packit 032894
		sizeof (ElfW2(LIBELFBITS,Ehdr)));
Packit 032894
Packit 032894
      elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY;
Packit 032894
Packit 032894
      /* We start writing sections after the ELF header only if there is
Packit 032894
	 no program header.  */
Packit 032894
      previous_scn_changed = elf->state.ELFW(elf,LIBELFBITS).phdr == NULL;
Packit 032894
    }
Packit 032894
Packit 032894
  size_t phnum;
Packit 032894
  if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0))
Packit 032894
    return -1;
Packit 032894
Packit 032894
  /* Write out the program header table.  */
Packit 032894
  if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL
Packit 032894
      && ((elf->state.ELFW(elf,LIBELFBITS).phdr_flags | elf->flags)
Packit 032894
	  & ELF_F_DIRTY))
Packit 032894
    {
Packit 032894
      /* If the type sizes should be different at some time we have to
Packit 032894
	 rewrite this code.  */
Packit 032894
      assert (sizeof (ElfW2(LIBELFBITS,Phdr))
Packit 032894
	      == elf_typesize (LIBELFBITS, ELF_T_PHDR, 1));
Packit 032894
Packit 032894
      /* Maybe the user wants a gap between the ELF header and the program
Packit 032894
	 header.  */
Packit 032894
      if (ehdr->e_phoff > ehdr->e_ehsize)
Packit 032894
	memset (elf->map_address + elf->start_offset + ehdr->e_ehsize,
Packit 032894
		__libelf_fill_byte, ehdr->e_phoff - ehdr->e_ehsize);
Packit 032894
Packit 032894
      if (unlikely (change_bo))
Packit 032894
	{
Packit 032894
	  /* Today there is only one version of the ELF header.  */
Packit 032894
#undef fctp
Packit 032894
#define fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]
Packit 032894
Packit 032894
	  /* Do the real work.  */
Packit 032894
	  (*fctp) (elf->map_address + elf->start_offset + ehdr->e_phoff,
Packit 032894
		   elf->state.ELFW(elf,LIBELFBITS).phdr,
Packit 032894
		   sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum, 1);
Packit 032894
	}
Packit 032894
      else
Packit 032894
	memmove (elf->map_address + elf->start_offset + ehdr->e_phoff,
Packit 032894
		elf->state.ELFW(elf,LIBELFBITS).phdr,
Packit 032894
		sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
Packit 032894
Packit 032894
      elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY;
Packit 032894
Packit 032894
      /* We modified the program header.  Maybe this created a gap so
Packit 032894
	 we have to write fill bytes, if necessary.  */
Packit 032894
      previous_scn_changed = true;
Packit 032894
    }
Packit 032894
Packit 032894
  /* From now on we have to keep track of the last position to eventually
Packit 032894
     fill the gaps with the prescribed fill byte.  */
Packit 032894
  char *last_position = ((char *) elf->map_address + elf->start_offset
Packit 032894
			 + MAX (elf_typesize (LIBELFBITS, ELF_T_EHDR, 1),
Packit 032894
				ehdr->e_phoff)
Packit 032894
			 + elf_typesize (LIBELFBITS, ELF_T_PHDR, phnum));
Packit 032894
Packit 032894
  /* Write all the sections.  Well, only those which are modified.  */
Packit 032894
  if (shnum > 0)
Packit 032894
    {
Packit 032894
      if (unlikely (shnum > SIZE_MAX / sizeof (Elf_Scn *)))
Packit 032894
	return 1;
Packit 032894
Packit 032894
      Elf_ScnList *list = &elf->state.ELFW(elf,LIBELFBITS).scns;
Packit 032894
      Elf_Scn **scns = (Elf_Scn **) malloc (shnum * sizeof (Elf_Scn *));
Packit 032894
      if (unlikely (scns == NULL))
Packit 032894
	{
Packit 032894
	  __libelf_seterrno (ELF_E_NOMEM);
Packit 032894
	  return -1;
Packit 032894
	}
Packit 032894
      char *const shdr_start = ((char *) elf->map_address + elf->start_offset
Packit 032894
				+ ehdr->e_shoff);
Packit 032894
      char *const shdr_end = shdr_start + shnum * ehdr->e_shentsize;
Packit 032894
Packit 032894
#undef shdr_fctp
Packit 032894
#define shdr_fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]
Packit 032894
#define shdr_dest ((ElfW2(LIBELFBITS,Shdr) *) shdr_start)
Packit 032894
Packit 032894
      /* Get all sections into the array and sort them.  */
Packit 032894
      sort_sections (scns, list);
Packit 032894
Packit 032894
      /* We possibly have to copy the section header data because moving
Packit 032894
	 the sections might overwrite the data.  */
Packit 032894
      for (size_t cnt = 0; cnt < shnum; ++cnt)
Packit 032894
	{
Packit 032894
	  Elf_Scn *scn = scns[cnt];
Packit 032894
Packit 032894
	  if (!elf->state.ELFW(elf,LIBELFBITS).shdr_malloced
Packit 032894
	      && (scn->shdr_flags & ELF_F_MALLOCED) == 0
Packit 032894
	      && scn->shdr.ELFW(e,LIBELFBITS) != &shdr_dest[scn->index])
Packit 032894
	    {
Packit 032894
	      assert ((char *) elf->map_address + elf->start_offset
Packit 032894
		      < (char *) scn->shdr.ELFW(e,LIBELFBITS));
Packit 032894
	      assert ((char *) scn->shdr.ELFW(e,LIBELFBITS)
Packit 032894
		      < ((char *) elf->map_address + elf->start_offset
Packit 032894
			 + elf->maximum_size));
Packit 032894
Packit 032894
	      void *p = malloc (sizeof (ElfW2(LIBELFBITS,Shdr)));
Packit 032894
	      if (unlikely (p == NULL))
Packit 032894
		{
Packit 032894
		  free (scns);
Packit 032894
		  __libelf_seterrno (ELF_E_NOMEM);
Packit 032894
		  return -1;
Packit 032894
		}
Packit 032894
	      scn->shdr.ELFW(e,LIBELFBITS)
Packit 032894
		= memcpy (p, scn->shdr.ELFW(e,LIBELFBITS),
Packit 032894
			  sizeof (ElfW2(LIBELFBITS,Shdr)));
Packit 032894
	    }
Packit 032894
Packit 032894
	  /* If the file is mmaped and the original position of the
Packit 032894
	     section in the file is lower than the new position we
Packit 032894
	     need to save the section content since otherwise it is
Packit 032894
	     overwritten before it can be copied.  If there are
Packit 032894
	     multiple data segments in the list only the first can be
Packit 032894
	     from the file.  */
Packit 032894
	  if (((char *) elf->map_address + elf->start_offset
Packit 032894
	       <= (char  *) scn->data_list.data.d.d_buf)
Packit 032894
	      && ((char *) scn->data_list.data.d.d_buf
Packit 032894
		  < ((char *) elf->map_address + elf->start_offset
Packit 032894
		     + elf->maximum_size))
Packit 032894
	      && (((char *) elf->map_address + elf->start_offset
Packit 032894
		   + scn->shdr.ELFW(e,LIBELFBITS)->sh_offset)
Packit 032894
		  > (char *) scn->data_list.data.d.d_buf))
Packit 032894
	    {
Packit 032894
	      void *p = malloc (scn->data_list.data.d.d_size);
Packit 032894
	      if (unlikely (p == NULL))
Packit 032894
		{
Packit 032894
		  free (scns);
Packit 032894
		  __libelf_seterrno (ELF_E_NOMEM);
Packit 032894
		  return -1;
Packit 032894
		}
Packit 032894
	      scn->data_list.data.d.d_buf = scn->data_base
Packit 032894
		= memcpy (p, scn->data_list.data.d.d_buf,
Packit 032894
			  scn->data_list.data.d.d_size);
Packit 032894
	    }
Packit 032894
	}
Packit 032894
Packit 032894
      /* Iterate over all the section in the order in which they
Packit 032894
	 appear in the output file.  */
Packit 032894
      for (size_t cnt = 0; cnt < shnum; ++cnt)
Packit 032894
	{
Packit 032894
	  Elf_Scn *scn = scns[cnt];
Packit 032894
	  if (scn->index == 0)
Packit 032894
	    {
Packit 032894
	      /* The dummy section header entry.  It should not be
Packit 032894
		 possible to mark this "section" as dirty.  */
Packit 032894
	      assert ((scn->flags & ELF_F_DIRTY) == 0);
Packit 032894
	      continue;
Packit 032894
	    }
Packit 032894
Packit 032894
	  ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
Packit 032894
	  if (shdr->sh_type == SHT_NOBITS)
Packit 032894
	    goto next;
Packit 032894
Packit 032894
	  char *scn_start = ((char *) elf->map_address
Packit 032894
			     + elf->start_offset + shdr->sh_offset);
Packit 032894
	  Elf_Data_List *dl = &scn->data_list;
Packit 032894
	  bool scn_changed = false;
Packit 032894
Packit 032894
	  if (scn->data_list_rear != NULL)
Packit 032894
	    do
Packit 032894
	      {
Packit 032894
		assert (dl->data.d.d_off >= 0);
Packit 032894
		assert ((GElf_Off) dl->data.d.d_off <= shdr->sh_size);
Packit 032894
		assert (dl->data.d.d_size <= (shdr->sh_size
Packit 032894
					      - (GElf_Off) dl->data.d.d_off));
Packit 032894
Packit 032894
		/* If there is a gap, fill it.  */
Packit 032894
		if (scn_start + dl->data.d.d_off > last_position
Packit 032894
		    && (dl->data.d.d_off == 0
Packit 032894
			|| ((scn->flags | dl->flags | elf->flags)
Packit 032894
			    & ELF_F_DIRTY) != 0))
Packit 032894
		  {
Packit 032894
		    fill_mmap (dl->data.d.d_off, last_position, scn_start,
Packit 032894
		               shdr_start, shdr_end);
Packit 032894
		  }
Packit 032894
Packit 032894
		last_position = scn_start + dl->data.d.d_off;
Packit 032894
Packit 032894
		if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY)
Packit 032894
		  {
Packit 032894
		    /* Let it go backward if the sections use a bogus
Packit 032894
		       layout with overlaps.  We'll overwrite the stupid
Packit 032894
		       user's section data with the latest one, rather than
Packit 032894
		       crashing.  */
Packit 032894
Packit 032894
		    if (unlikely (change_bo
Packit 032894
				  && dl->data.d.d_size != 0
Packit 032894
				  && dl->data.d.d_type != ELF_T_BYTE))
Packit 032894
		      {
Packit 032894
#undef fctp
Packit 032894
#define fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]
Packit 032894
Packit 032894
			size_t align;
Packit 032894
			align = __libelf_type_align (ELFW(ELFCLASS,LIBELFBITS),
Packit 032894
						     dl->data.d.d_type);
Packit 032894
			if ((((uintptr_t) last_position)
Packit 032894
			     & (uintptr_t) (align - 1)) == 0)
Packit 032894
			  {
Packit 032894
			    /* No need to copy, we can convert directly.  */
Packit 032894
			    (*fctp) (last_position, dl->data.d.d_buf,
Packit 032894
				     dl->data.d.d_size, 1);
Packit 032894
			  }
Packit 032894
			else
Packit 032894
			  {
Packit 032894
			    /* We have to do the conversion on properly
Packit 032894
			       aligned memory first.  align is a power of 2,
Packit 032894
			       but posix_memalign only works for alignments
Packit 032894
			       which are a multiple of sizeof (void *).
Packit 032894
			       So use normal malloc for smaller alignments.  */
Packit 032894
			    size_t size = dl->data.d.d_size;
Packit 032894
			    void *converted;
Packit 032894
			    if (align < sizeof (void *))
Packit 032894
			      converted = malloc (size);
Packit 032894
			    else
Packit 032894
			      {
Packit 032894
				int res;
Packit 032894
				res = posix_memalign (&converted, align, size);
Packit 032894
				if (res != 0)
Packit 032894
				  converted = NULL;
Packit 032894
			      }
Packit 032894
Packit 032894
			    if (converted == NULL)
Packit 032894
			      {
Packit 032894
				free (scns);
Packit 032894
				__libelf_seterrno (ELF_E_NOMEM);
Packit 032894
				return 1;
Packit 032894
			      }
Packit 032894
Packit 032894
			    (*fctp) (converted, dl->data.d.d_buf, size, 1);
Packit 032894
Packit 032894
			    /* And then write it to the mmapped file.  */
Packit 032894
			    memcpy (last_position, converted, size);
Packit 032894
			    free (converted);
Packit 032894
			  }
Packit 032894
Packit 032894
			last_position += dl->data.d.d_size;
Packit 032894
		      }
Packit 032894
		    else if (dl->data.d.d_size != 0)
Packit 032894
		      {
Packit 032894
			memmove (last_position, dl->data.d.d_buf,
Packit 032894
				 dl->data.d.d_size);
Packit 032894
			last_position += dl->data.d.d_size;
Packit 032894
		      }
Packit 032894
Packit 032894
		    scn_changed = true;
Packit 032894
		  }
Packit 032894
		else
Packit 032894
		  last_position += dl->data.d.d_size;
Packit 032894
Packit 032894
		assert (scn_start + dl->data.d.d_off + dl->data.d.d_size
Packit 032894
			== last_position);
Packit 032894
Packit 032894
		dl->flags &= ~ELF_F_DIRTY;
Packit 032894
Packit 032894
		dl = dl->next;
Packit 032894
	      }
Packit 032894
	    while (dl != NULL);
Packit 032894
	  else
Packit 032894
	    {
Packit 032894
	      /* If the previous section (or the ELF/program
Packit 032894
		 header) changed we might have to fill the gap.  */
Packit 032894
	      if (scn_start > last_position && previous_scn_changed)
Packit 032894
		fill_mmap (0, last_position, scn_start,
Packit 032894
		           shdr_start, shdr_end);
Packit 032894
Packit 032894
	      /* We have to trust the existing section header information.  */
Packit 032894
	      last_position = scn_start + shdr->sh_size;
Packit 032894
	    }
Packit 032894
Packit 032894
Packit 032894
	  previous_scn_changed = scn_changed;
Packit 032894
	next:
Packit 032894
	  scn->flags &= ~ELF_F_DIRTY;
Packit 032894
	}
Packit 032894
Packit 032894
      /* Fill the gap between last section and section header table if
Packit 032894
	 necessary.  */
Packit 032894
      if ((elf->flags & ELF_F_DIRTY)
Packit 032894
	  && last_position < ((char *) elf->map_address + elf->start_offset
Packit 032894
			      + ehdr->e_shoff))
Packit 032894
	memset (last_position, __libelf_fill_byte,
Packit 032894
		(char *) elf->map_address + elf->start_offset + ehdr->e_shoff
Packit 032894
		- last_position);
Packit 032894
Packit 032894
      /* Write the section header table entry if necessary.  */
Packit 032894
      for (size_t cnt = 0; cnt < shnum; ++cnt)
Packit 032894
	{
Packit 032894
	  Elf_Scn *scn = scns[cnt];
Packit 032894
Packit 032894
	  if ((scn->shdr_flags | elf->flags) & ELF_F_DIRTY)
Packit 032894
	    {
Packit 032894
	      if (unlikely (change_bo))
Packit 032894
		(*shdr_fctp) (&shdr_dest[scn->index],
Packit 032894
			      scn->shdr.ELFW(e,LIBELFBITS),
Packit 032894
			      sizeof (ElfW2(LIBELFBITS,Shdr)), 1);
Packit 032894
	      else
Packit 032894
		memcpy (&shdr_dest[scn->index],
Packit 032894
			scn->shdr.ELFW(e,LIBELFBITS),
Packit 032894
			sizeof (ElfW2(LIBELFBITS,Shdr)));
Packit 032894
Packit 032894
	      /* If we previously made a copy of the section header
Packit 032894
		 entry we now have to adjust the pointer again so
Packit 032894
		 point to new place in the mapping.  */
Packit 032894
	      if (!elf->state.ELFW(elf,LIBELFBITS).shdr_malloced
Packit 032894
		  && (scn->shdr_flags & ELF_F_MALLOCED) == 0
Packit 032894
		  && scn->shdr.ELFW(e,LIBELFBITS) != &shdr_dest[scn->index])
Packit 032894
		{
Packit 032894
		  free (scn->shdr.ELFW(e,LIBELFBITS));
Packit 032894
		  scn->shdr.ELFW(e,LIBELFBITS) = &shdr_dest[scn->index];
Packit 032894
		}
Packit 032894
Packit 032894
	      scn->shdr_flags &= ~ELF_F_DIRTY;
Packit 032894
	    }
Packit 032894
	}
Packit 032894
      free (scns);
Packit 032894
    }
Packit 032894
Packit 032894
  /* That was the last part.  Clear the overall flag.  */
Packit 032894
  elf->flags &= ~ELF_F_DIRTY;
Packit 032894
Packit 032894
  /* Make sure the content hits the disk.  */
Packit 032894
  char *msync_start = ((char *) elf->map_address
Packit 032894
		       + (elf->start_offset & ~(sysconf (_SC_PAGESIZE) - 1)));
Packit 032894
  char *msync_end = ((char *) elf->map_address
Packit 032894
		     + elf->start_offset + ehdr->e_shoff
Packit 032894
		     + ehdr->e_shentsize * shnum);
Packit 032894
  (void) msync (msync_start, msync_end - msync_start, MS_SYNC);
Packit 032894
Packit 032894
  return 0;
Packit 032894
}
Packit 032894
Packit 032894
Packit 032894
/* Size of the buffer we use to generate the blocks of fill bytes.  */
Packit 032894
#define FILLBUFSIZE	4096
Packit 032894
Packit 032894
/* If we have to convert the section buffer contents we have to use
Packit 032894
   temporary buffer.  Only buffers up to MAX_TMPBUF bytes are allocated
Packit 032894
   on the stack.  */
Packit 032894
#define MAX_TMPBUF	32768
Packit 032894
Packit 032894
Packit 032894
/* Helper function to write out fill bytes.  */
Packit 032894
static int
Packit 032894
fill (int fd, int64_t pos, size_t len, char *fillbuf, size_t *filledp)
Packit 032894
{
Packit 032894
  size_t filled = *filledp;
Packit 032894
  size_t fill_len = MIN (len, FILLBUFSIZE);
Packit 032894
Packit 032894
  if (unlikely (fill_len > filled) && filled < FILLBUFSIZE)
Packit 032894
    {
Packit 032894
      /* Initialize a few more bytes.  */
Packit 032894
      memset (fillbuf + filled, __libelf_fill_byte, fill_len - filled);
Packit 032894
      *filledp = filled = fill_len;
Packit 032894
    }
Packit 032894
Packit 032894
  do
Packit 032894
    {
Packit 032894
      /* This many bytes we want to write in this round.  */
Packit 032894
      size_t n = MIN (filled, len);
Packit 032894
Packit 032894
      if (unlikely ((size_t) pwrite_retry (fd, fillbuf, n, pos) != n))
Packit 032894
	{
Packit 032894
	  __libelf_seterrno (ELF_E_WRITE_ERROR);
Packit 032894
	  return 1;
Packit 032894
	}
Packit 032894
Packit 032894
      pos += n;
Packit 032894
      len -= n;
Packit 032894
    }
Packit 032894
  while (len > 0);
Packit 032894
Packit 032894
  return 0;
Packit 032894
}
Packit 032894
Packit 032894
Packit 032894
int
Packit 032894
internal_function
Packit 032894
__elfw2(LIBELFBITS,updatefile) (Elf *elf, int change_bo, size_t shnum)
Packit 032894
{
Packit 032894
  char fillbuf[FILLBUFSIZE];
Packit 032894
  size_t filled = 0;
Packit 032894
  bool previous_scn_changed = false;
Packit 032894
Packit 032894
  /* We need the ELF header several times.  */
Packit 032894
  ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
Packit 032894
Packit 032894
  /* Write out the ELF header.  */
Packit 032894
  if ((elf->state.ELFW(elf,LIBELFBITS).ehdr_flags | elf->flags) & ELF_F_DIRTY)
Packit 032894
    {
Packit 032894
      ElfW2(LIBELFBITS,Ehdr) tmp_ehdr;
Packit 032894
      ElfW2(LIBELFBITS,Ehdr) *out_ehdr = ehdr;
Packit 032894
Packit 032894
      /* If the type sizes should be different at some time we have to
Packit 032894
	 rewrite this code.  */
Packit 032894
      assert (sizeof (ElfW2(LIBELFBITS,Ehdr))
Packit 032894
	      == elf_typesize (LIBELFBITS, ELF_T_EHDR, 1));
Packit 032894
Packit 032894
      if (unlikely (change_bo))
Packit 032894
	{
Packit 032894
	  /* Today there is only one version of the ELF header.  */
Packit 032894
#undef fctp
Packit 032894
#define fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_EHDR]
Packit 032894
Packit 032894
	  /* Write the converted ELF header in a temporary buffer.  */
Packit 032894
	  (*fctp) (&tmp_ehdr, ehdr, sizeof (ElfW2(LIBELFBITS,Ehdr)), 1);
Packit 032894
Packit 032894
	  /* This is the buffer we want to write.  */
Packit 032894
	  out_ehdr = &tmp_ehdr;
Packit 032894
	}
Packit 032894
Packit 032894
      /* Write out the ELF header.  */
Packit 032894
      if (unlikely (pwrite_retry (elf->fildes, out_ehdr,
Packit 032894
				  sizeof (ElfW2(LIBELFBITS,Ehdr)), 0)
Packit 032894
		    != sizeof (ElfW2(LIBELFBITS,Ehdr))))
Packit 032894
	{
Packit 032894
	  __libelf_seterrno (ELF_E_WRITE_ERROR);
Packit 032894
	  return 1;
Packit 032894
	}
Packit 032894
Packit 032894
      elf->state.ELFW(elf,LIBELFBITS).ehdr_flags &= ~ELF_F_DIRTY;
Packit 032894
Packit 032894
      /* We start writing sections after the ELF header only if there is
Packit 032894
	 no program header.  */
Packit 032894
      previous_scn_changed = elf->state.ELFW(elf,LIBELFBITS).phdr == NULL;
Packit 032894
    }
Packit 032894
Packit 032894
  /* If the type sizes should be different at some time we have to
Packit 032894
     rewrite this code.  */
Packit 032894
  assert (sizeof (ElfW2(LIBELFBITS,Phdr))
Packit 032894
	  == elf_typesize (LIBELFBITS, ELF_T_PHDR, 1));
Packit 032894
Packit 032894
  size_t phnum;
Packit 032894
  if (unlikely (__elf_getphdrnum_rdlock (elf, &phnum) != 0))
Packit 032894
    return -1;
Packit 032894
Packit 032894
  /* Write out the program header table.  */
Packit 032894
  if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL
Packit 032894
      && ((elf->state.ELFW(elf,LIBELFBITS).phdr_flags | elf->flags)
Packit 032894
	  & ELF_F_DIRTY))
Packit 032894
    {
Packit 032894
      ElfW2(LIBELFBITS,Phdr) *tmp_phdr = NULL;
Packit 032894
      ElfW2(LIBELFBITS,Phdr) *out_phdr = elf->state.ELFW(elf,LIBELFBITS).phdr;
Packit 032894
Packit 032894
      /* Maybe the user wants a gap between the ELF header and the program
Packit 032894
	 header.  */
Packit 032894
      if (ehdr->e_phoff > ehdr->e_ehsize
Packit 032894
	  && unlikely (fill (elf->fildes, ehdr->e_ehsize,
Packit 032894
			     ehdr->e_phoff - ehdr->e_ehsize, fillbuf, &filled)
Packit 032894
		       != 0))
Packit 032894
	return 1;
Packit 032894
Packit 032894
      if (unlikely (change_bo))
Packit 032894
	{
Packit 032894
	  /* Today there is only one version of the ELF header.  */
Packit 032894
#undef fctp
Packit 032894
#define fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_PHDR]
Packit 032894
Packit 032894
	  /* Allocate sufficient memory.  */
Packit 032894
	  tmp_phdr = (ElfW2(LIBELFBITS,Phdr) *)
Packit 032894
	    malloc (sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
Packit 032894
	  if (unlikely (tmp_phdr == NULL))
Packit 032894
	    {
Packit 032894
	      __libelf_seterrno (ELF_E_NOMEM);
Packit 032894
	      return 1;
Packit 032894
	    }
Packit 032894
Packit 032894
	  /* Write the converted ELF header in a temporary buffer.  */
Packit 032894
	  (*fctp) (tmp_phdr, elf->state.ELFW(elf,LIBELFBITS).phdr,
Packit 032894
		   sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum, 1);
Packit 032894
Packit 032894
	  /* This is the buffer we want to write.  */
Packit 032894
	  out_phdr = tmp_phdr;
Packit 032894
	}
Packit 032894
Packit 032894
      /* Write out the ELF header.  */
Packit 032894
      size_t phdr_size = sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum;
Packit 032894
      if (unlikely ((size_t) pwrite_retry (elf->fildes, out_phdr,
Packit 032894
					   phdr_size, ehdr->e_phoff)
Packit 032894
		    != phdr_size))
Packit 032894
	{
Packit 032894
	  __libelf_seterrno (ELF_E_WRITE_ERROR);
Packit 032894
	  return 1;
Packit 032894
	}
Packit 032894
Packit 032894
      /* This is a no-op we we have not allocated any memory.  */
Packit 032894
      free (tmp_phdr);
Packit 032894
Packit 032894
      elf->state.ELFW(elf,LIBELFBITS).phdr_flags &= ~ELF_F_DIRTY;
Packit 032894
Packit 032894
      /* We modified the program header.  Maybe this created a gap so
Packit 032894
	 we have to write fill bytes, if necessary.  */
Packit 032894
      previous_scn_changed = true;
Packit 032894
    }
Packit 032894
Packit 032894
  /* From now on we have to keep track of the last position to eventually
Packit 032894
     fill the gaps with the prescribed fill byte.  */
Packit 032894
  int64_t last_offset;
Packit 032894
  if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL)
Packit 032894
    last_offset = elf_typesize (LIBELFBITS, ELF_T_EHDR, 1);
Packit 032894
  else
Packit 032894
    last_offset = (ehdr->e_phoff + sizeof (ElfW2(LIBELFBITS,Phdr)) * phnum);
Packit 032894
Packit 032894
  /* Write all the sections.  Well, only those which are modified.  */
Packit 032894
  if (shnum > 0)
Packit 032894
    {
Packit 032894
      if (unlikely (shnum > SIZE_MAX / (sizeof (Elf_Scn *)
Packit 032894
					+ sizeof (ElfW2(LIBELFBITS,Shdr)))))
Packit 032894
	return 1;
Packit 032894
Packit 032894
      int64_t shdr_offset = elf->start_offset + ehdr->e_shoff;
Packit 032894
#undef shdr_fctp
Packit 032894
#define shdr_fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][ELF_T_SHDR]
Packit 032894
Packit 032894
      ElfW2(LIBELFBITS,Shdr) *shdr_data;
Packit 032894
      ElfW2(LIBELFBITS,Shdr) *shdr_data_mem = NULL;
Packit 032894
      if (change_bo || elf->state.ELFW(elf,LIBELFBITS).shdr == NULL
Packit 032894
	  || (elf->flags & ELF_F_DIRTY))
Packit 032894
	{
Packit 032894
	  shdr_data_mem = (ElfW2(LIBELFBITS,Shdr) *)
Packit 032894
	    malloc (shnum * sizeof (ElfW2(LIBELFBITS,Shdr)));
Packit 032894
	  if (unlikely (shdr_data_mem == NULL))
Packit 032894
	    {
Packit 032894
	      __libelf_seterrno (ELF_E_NOMEM);
Packit 032894
	      return -1;
Packit 032894
	    }
Packit 032894
	  shdr_data = shdr_data_mem;
Packit 032894
	}
Packit 032894
      else
Packit 032894
	shdr_data = elf->state.ELFW(elf,LIBELFBITS).shdr;
Packit 032894
      int shdr_flags = elf->flags;
Packit 032894
Packit 032894
      /* Get all sections into the array and sort them.  */
Packit 032894
      Elf_ScnList *list = &elf->state.ELFW(elf,LIBELFBITS).scns;
Packit 032894
      Elf_Scn **scns = (Elf_Scn **) malloc (shnum * sizeof (Elf_Scn *));
Packit 032894
      if (unlikely (scns == NULL))
Packit 032894
	{
Packit 032894
	  free (shdr_data_mem);
Packit 032894
	  __libelf_seterrno (ELF_E_NOMEM);
Packit 032894
	  return -1;
Packit 032894
	}
Packit 032894
      sort_sections (scns, list);
Packit 032894
Packit 032894
      for (size_t cnt = 0; cnt < shnum; ++cnt)
Packit 032894
	{
Packit 032894
	  Elf_Scn *scn = scns[cnt];
Packit 032894
	  if (scn->index == 0)
Packit 032894
	    {
Packit 032894
	      /* The dummy section header entry.  It should not be
Packit 032894
		 possible to mark this "section" as dirty.  */
Packit 032894
	      assert ((scn->flags & ELF_F_DIRTY) == 0);
Packit 032894
	      goto next;
Packit 032894
	    }
Packit 032894
Packit 032894
	  ElfW2(LIBELFBITS,Shdr) *shdr = scn->shdr.ELFW(e,LIBELFBITS);
Packit 032894
	  if (shdr->sh_type == SHT_NOBITS)
Packit 032894
	    goto next;
Packit 032894
Packit 032894
	  int64_t scn_start = elf->start_offset + shdr->sh_offset;
Packit 032894
	  Elf_Data_List *dl = &scn->data_list;
Packit 032894
	  bool scn_changed = false;
Packit 032894
Packit 032894
	  if (scn->data_list_rear != NULL)
Packit 032894
	    do
Packit 032894
	      {
Packit 032894
		/* If there is a gap, fill it.  */
Packit 032894
		if (scn_start + dl->data.d.d_off > last_offset
Packit 032894
		    && ((previous_scn_changed && dl->data.d.d_off == 0)
Packit 032894
			|| ((scn->flags | dl->flags | elf->flags)
Packit 032894
			    & ELF_F_DIRTY) != 0))
Packit 032894
		  {
Packit 032894
		    if (unlikely (fill (elf->fildes, last_offset,
Packit 032894
					(scn_start + dl->data.d.d_off)
Packit 032894
					- last_offset, fillbuf,
Packit 032894
					&filled) != 0))
Packit 032894
		      {
Packit 032894
		      fail_free:
Packit 032894
			free (shdr_data_mem);
Packit 032894
			free (scns);
Packit 032894
			return 1;
Packit 032894
		      }
Packit 032894
		  }
Packit 032894
Packit 032894
		last_offset = scn_start + dl->data.d.d_off;
Packit 032894
Packit 032894
		if ((scn->flags | dl->flags | elf->flags) & ELF_F_DIRTY)
Packit 032894
		  {
Packit 032894
		    char tmpbuf[MAX_TMPBUF];
Packit 032894
		    void *buf = dl->data.d.d_buf;
Packit 032894
Packit 032894
		    /* Let it go backward if the sections use a bogus
Packit 032894
		       layout with overlaps.  We'll overwrite the stupid
Packit 032894
		       user's section data with the latest one, rather than
Packit 032894
		       crashing.  */
Packit 032894
Packit 032894
		    if (unlikely (change_bo))
Packit 032894
		      {
Packit 032894
#undef fctp
Packit 032894
#define fctp __elf_xfctstom[ELFW(ELFCLASS, LIBELFBITS) - 1][dl->data.d.d_type]
Packit 032894
Packit 032894
			buf = tmpbuf;
Packit 032894
			if (dl->data.d.d_size > MAX_TMPBUF)
Packit 032894
			  {
Packit 032894
			    buf = malloc (dl->data.d.d_size);
Packit 032894
			    if (unlikely (buf == NULL))
Packit 032894
			      {
Packit 032894
				__libelf_seterrno (ELF_E_NOMEM);
Packit 032894
				goto fail_free;
Packit 032894
			      }
Packit 032894
			  }
Packit 032894
Packit 032894
			/* Do the real work.  */
Packit 032894
			(*fctp) (buf, dl->data.d.d_buf, dl->data.d.d_size, 1);
Packit 032894
		      }
Packit 032894
Packit 032894
		    ssize_t n = pwrite_retry (elf->fildes, buf,
Packit 032894
					      dl->data.d.d_size,
Packit 032894
					      last_offset);
Packit 032894
		    if (unlikely ((size_t) n != dl->data.d.d_size))
Packit 032894
		      {
Packit 032894
			if (buf != dl->data.d.d_buf && buf != tmpbuf)
Packit 032894
			  free (buf);
Packit 032894
Packit 032894
			__libelf_seterrno (ELF_E_WRITE_ERROR);
Packit 032894
			goto fail_free;
Packit 032894
		      }
Packit 032894
Packit 032894
		    if (buf != dl->data.d.d_buf && buf != tmpbuf)
Packit 032894
		      free (buf);
Packit 032894
Packit 032894
		    scn_changed = true;
Packit 032894
		  }
Packit 032894
Packit 032894
		last_offset += dl->data.d.d_size;
Packit 032894
Packit 032894
		dl->flags &= ~ELF_F_DIRTY;
Packit 032894
Packit 032894
		dl = dl->next;
Packit 032894
	      }
Packit 032894
	    while (dl != NULL);
Packit 032894
	  else
Packit 032894
	    {
Packit 032894
	      /* If the previous section (or the ELF/program
Packit 032894
		 header) changed we might have to fill the gap.  */
Packit 032894
	      if (scn_start > last_offset && previous_scn_changed)
Packit 032894
		{
Packit 032894
		  if (unlikely (fill (elf->fildes, last_offset,
Packit 032894
				      scn_start - last_offset, fillbuf,
Packit 032894
				      &filled) != 0))
Packit 032894
		    goto fail_free;
Packit 032894
		}
Packit 032894
Packit 032894
	      last_offset = scn_start + shdr->sh_size;
Packit 032894
	    }
Packit 032894
Packit 032894
	  previous_scn_changed = scn_changed;
Packit 032894
	next:
Packit 032894
	  /* Collect the section header table information.  */
Packit 032894
	  if (unlikely (change_bo))
Packit 032894
	    (*shdr_fctp) (&shdr_data[scn->index],
Packit 032894
			  scn->shdr.ELFW(e,LIBELFBITS),
Packit 032894
			  sizeof (ElfW2(LIBELFBITS,Shdr)), 1);
Packit 032894
	  else if (elf->state.ELFW(elf,LIBELFBITS).shdr == NULL
Packit 032894
		   || (elf->flags & ELF_F_DIRTY))
Packit 032894
	    memcpy (&shdr_data[scn->index], scn->shdr.ELFW(e,LIBELFBITS),
Packit 032894
		    sizeof (ElfW2(LIBELFBITS,Shdr)));
Packit 032894
Packit 032894
	  shdr_flags |= scn->shdr_flags;
Packit 032894
	  scn->shdr_flags &= ~ELF_F_DIRTY;
Packit 032894
	}
Packit 032894
Packit 032894
      /* Fill the gap between last section and section header table if
Packit 032894
	 necessary.  */
Packit 032894
      if ((elf->flags & ELF_F_DIRTY) && last_offset < shdr_offset
Packit 032894
	  && unlikely (fill (elf->fildes, last_offset,
Packit 032894
			     shdr_offset - last_offset,
Packit 032894
			     fillbuf, &filled) != 0))
Packit 032894
	goto fail_free;
Packit 032894
Packit 032894
      /* Write out the section header table.  */
Packit 032894
      if (shdr_flags & ELF_F_DIRTY
Packit 032894
	  && unlikely ((size_t) pwrite_retry (elf->fildes, shdr_data,
Packit 032894
					      sizeof (ElfW2(LIBELFBITS,Shdr))
Packit 032894
					      * shnum, shdr_offset)
Packit 032894
		       != sizeof (ElfW2(LIBELFBITS,Shdr)) * shnum))
Packit 032894
	{
Packit 032894
	  __libelf_seterrno (ELF_E_WRITE_ERROR);
Packit 032894
	  goto fail_free;
Packit 032894
	}
Packit 032894
Packit 032894
      free (shdr_data_mem);
Packit 032894
      free (scns);
Packit 032894
    }
Packit 032894
Packit 032894
  /* That was the last part.  Clear the overall flag.  */
Packit 032894
  elf->flags &= ~ELF_F_DIRTY;
Packit 032894
Packit 032894
  return 0;
Packit 032894
}