Blame libelf/elf32_newphdr.c

Packit Service 97d2fb
/* Create new ELF program header table.
Packit Service 97d2fb
   Copyright (C) 1999-2010, 2014, 2015 Red Hat, Inc.
Packit Service 97d2fb
   This file is part of elfutils.
Packit Service 97d2fb
   Written by Ulrich Drepper <drepper@redhat.com>, 1998.
Packit Service 97d2fb
Packit Service 97d2fb
   This file is free software; you can redistribute it and/or modify
Packit Service 97d2fb
   it under the terms of either
Packit Service 97d2fb
Packit Service 97d2fb
     * the GNU Lesser General Public License as published by the Free
Packit Service 97d2fb
       Software Foundation; either version 3 of the License, or (at
Packit Service 97d2fb
       your option) any later version
Packit Service 97d2fb
Packit Service 97d2fb
   or
Packit Service 97d2fb
Packit Service 97d2fb
     * the GNU General Public License as published by the Free
Packit Service 97d2fb
       Software Foundation; either version 2 of the License, or (at
Packit Service 97d2fb
       your option) any later version
Packit Service 97d2fb
Packit Service 97d2fb
   or both in parallel, as here.
Packit Service 97d2fb
Packit Service 97d2fb
   elfutils is distributed in the hope that it will be useful, but
Packit Service 97d2fb
   WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 97d2fb
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 97d2fb
   General Public License for more details.
Packit Service 97d2fb
Packit Service 97d2fb
   You should have received copies of the GNU General Public License and
Packit Service 97d2fb
   the GNU Lesser General Public License along with this program.  If
Packit Service 97d2fb
   not, see <http://www.gnu.org/licenses/>.  */
Packit Service 97d2fb
Packit Service 97d2fb
#ifdef HAVE_CONFIG_H
Packit Service 97d2fb
# include <config.h>
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
#include <assert.h>
Packit Service 97d2fb
#include <stdlib.h>
Packit Service 97d2fb
#include <string.h>
Packit Service 97d2fb
Packit Service 97d2fb
#include "libelfP.h"
Packit Service 97d2fb
Packit Service 97d2fb
#ifndef LIBELFBITS
Packit Service 97d2fb
# define LIBELFBITS 32
Packit Service 97d2fb
#endif
Packit Service 97d2fb
Packit Service 97d2fb
Packit Service 97d2fb
ElfW2(LIBELFBITS,Phdr) *
Packit Service 97d2fb
elfw2(LIBELFBITS,newphdr) (Elf *elf, size_t count)
Packit Service 97d2fb
{
Packit Service 97d2fb
  ElfW2(LIBELFBITS,Phdr) *result;
Packit Service 97d2fb
Packit Service 97d2fb
  if (elf == NULL)
Packit Service 97d2fb
    return NULL;
Packit Service 97d2fb
Packit Service 97d2fb
  if (unlikely (elf->kind != ELF_K_ELF))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      __libelf_seterrno (ELF_E_INVALID_HANDLE);
Packit Service 97d2fb
      return NULL;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* This check is correct, it is for sh_info, which is either
Packit Service 97d2fb
     Elf32_Word or Elf64_Word, both being 32 bits.  But count is size_t
Packit Service 97d2fb
     so might not fit on 32bit ELF files.  */
Packit Service 97d2fb
  if (unlikely ((ElfW2(LIBELFBITS,Word)) count != count))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      __libelf_seterrno (ELF_E_INVALID_OPERAND);
Packit Service 97d2fb
      return NULL;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  rwlock_wrlock (elf->lock);
Packit Service 97d2fb
Packit Service 97d2fb
  if (elf->class == 0)
Packit Service 97d2fb
    elf->class = ELFW(ELFCLASS,LIBELFBITS);
Packit Service 97d2fb
  else if (unlikely (elf->class != ELFW(ELFCLASS,LIBELFBITS)))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      __libelf_seterrno (ELF_E_INVALID_CLASS);
Packit Service 97d2fb
      result = NULL;
Packit Service 97d2fb
      goto out;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  if (unlikely (elf->state.ELFW(elf,LIBELFBITS).ehdr == NULL))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR);
Packit Service 97d2fb
      result = NULL;
Packit Service 97d2fb
      goto out;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
  /* A COUNT of zero means remove existing table.  */
Packit Service 97d2fb
  if (count == 0)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* Free the old program header.  */
Packit Service 97d2fb
      if (elf->state.ELFW(elf,LIBELFBITS).phdr != NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  if (elf->state.ELFW(elf,LIBELFBITS).phdr_flags & ELF_F_MALLOCED)
Packit Service 97d2fb
	    free (elf->state.ELFW(elf,LIBELFBITS).phdr);
Packit Service 97d2fb
Packit Service 97d2fb
	  /* Set the pointer to NULL.  */
Packit Service 97d2fb
	  elf->state.ELFW(elf,LIBELFBITS).phdr = NULL;
Packit Service 97d2fb
	  /* Set the `e_phnum' member to the new value.  */
Packit Service 97d2fb
	  elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phnum = 0;
Packit Service 97d2fb
	  /* Also clear any old PN_XNUM extended value.  */
Packit Service 97d2fb
	  if (elf->state.ELFW(elf,LIBELFBITS).scns.cnt > 0)
Packit Service 97d2fb
	    elf->state.ELFW(elf,LIBELFBITS).scns.data[0]
Packit Service 97d2fb
	      .shdr.ELFW(e,LIBELFBITS)->sh_info = 0;
Packit Service 97d2fb
	  /* Also set the size.  */
Packit Service 97d2fb
	  elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phentsize =
Packit Service 97d2fb
	    sizeof (ElfW2(LIBELFBITS,Phdr));
Packit Service 97d2fb
Packit Service 97d2fb
	  elf->state.ELFW(elf,LIBELFBITS).phdr_flags |= ELF_F_DIRTY;
Packit Service 97d2fb
	  elf->flags |= ELF_F_DIRTY;
Packit Service 97d2fb
	  __libelf_seterrno (ELF_E_NOERROR);
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      result = NULL;
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else if (elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phnum != count
Packit Service 97d2fb
	   || count == PN_XNUM
Packit Service 97d2fb
	   || elf->state.ELFW(elf,LIBELFBITS).phdr == NULL)
Packit Service 97d2fb
    {
Packit Service 97d2fb
      if (unlikely (count > SIZE_MAX / sizeof (ElfW2(LIBELFBITS,Phdr))))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  __libelf_seterrno (ELF_E_INVALID_INDEX);
Packit Service 97d2fb
	  result = NULL;
Packit Service 97d2fb
	  goto out;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      Elf_Scn *scn0 = &elf->state.ELFW(elf,LIBELFBITS).scns.data[0];
Packit Service 97d2fb
      if (unlikely (count >= PN_XNUM && scn0->shdr.ELFW(e,LIBELFBITS) == NULL))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* Something is wrong with section zero, but we need it to write
Packit Service 97d2fb
	     the extended phdr count.  */
Packit Service 97d2fb
	  __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER);
Packit Service 97d2fb
	  result = NULL;
Packit Service 97d2fb
	  goto out;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* Allocate a new program header with the appropriate number of
Packit Service 97d2fb
	 elements.  */
Packit Service 97d2fb
      result = (ElfW2(LIBELFBITS,Phdr) *)
Packit Service 97d2fb
	realloc (elf->state.ELFW(elf,LIBELFBITS).phdr,
Packit Service 97d2fb
		 count * sizeof (ElfW2(LIBELFBITS,Phdr)));
Packit Service 97d2fb
      if (result == NULL)
Packit Service 97d2fb
	__libelf_seterrno (ELF_E_NOMEM);
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* Now set the result.  */
Packit Service 97d2fb
	  elf->state.ELFW(elf,LIBELFBITS).phdr = result;
Packit Service 97d2fb
	  if (count >= PN_XNUM)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      /* We have to write COUNT into the zeroth section's sh_info.  */
Packit Service 97d2fb
	      if (elf->state.ELFW(elf,LIBELFBITS).scns.cnt == 0)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  assert (elf->state.ELFW(elf,LIBELFBITS).scns.max > 0);
Packit Service 97d2fb
		  elf->state.ELFW(elf,LIBELFBITS).scns.cnt = 1;
Packit Service 97d2fb
		}
Packit Service 97d2fb
	      scn0->shdr.ELFW(e,LIBELFBITS)->sh_info = count;
Packit Service 97d2fb
	      scn0->shdr_flags |= ELF_F_DIRTY;
Packit Service 97d2fb
	      elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phnum = PN_XNUM;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	  else
Packit Service 97d2fb
	    /* Set the `e_phnum' member to the new value.  */
Packit Service 97d2fb
	    elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phnum = count;
Packit Service 97d2fb
	  /* Clear the whole memory.  */
Packit Service 97d2fb
	  memset (result, '\0', count * sizeof (ElfW2(LIBELFBITS,Phdr)));
Packit Service 97d2fb
	  /* Also set the size.  */
Packit Service 97d2fb
	  elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phentsize =
Packit Service 97d2fb
	    elf_typesize (LIBELFBITS, ELF_T_PHDR, 1);
Packit Service 97d2fb
	  /* Remember we allocated the array and mark the structure is
Packit Service 97d2fb
	     modified.  */
Packit Service 97d2fb
	  elf->state.ELFW(elf,LIBELFBITS).phdr_flags |=
Packit Service 97d2fb
	    ELF_F_DIRTY | ELF_F_MALLOCED;
Packit Service 97d2fb
	  /* We have to rewrite the entire file if the size of the
Packit Service 97d2fb
	     program header is changed.  */
Packit Service 97d2fb
	  elf->flags |= ELF_F_DIRTY;
Packit Service 97d2fb
	}
Packit Service 97d2fb
    }
Packit Service 97d2fb
  else
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* We have the same number of entries.  Just clear the array.  */
Packit Service 97d2fb
      assert (elf->state.ELFW(elf,LIBELFBITS).ehdr->e_phentsize
Packit Service 97d2fb
	      == elf_typesize (LIBELFBITS, ELF_T_PHDR, 1));
Packit Service 97d2fb
Packit Service 97d2fb
      /* Mark the structure as modified.  */
Packit Service 97d2fb
      elf->state.ELFW(elf,LIBELFBITS).phdr_flags |= ELF_F_DIRTY;
Packit Service 97d2fb
Packit Service 97d2fb
      result = elf->state.ELFW(elf,LIBELFBITS).phdr;
Packit Service 97d2fb
      memset (result, '\0', count * sizeof (ElfW2(LIBELFBITS,Phdr)));
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
 out:
Packit Service 97d2fb
  rwlock_unlock (elf->lock);
Packit Service 97d2fb
Packit Service 97d2fb
  return result;
Packit Service 97d2fb
}
Packit Service 97d2fb
INTDEF(elfw2(LIBELFBITS,newphdr))