Blame libelf/elf32_getphdr.c

Packit Service 97d2fb
/* Get ELF program header table.
Packit Service 97d2fb
   Copyright (C) 1998-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 <errno.h>
Packit Service 97d2fb
#include <stdbool.h>
Packit Service 97d2fb
#include <stdlib.h>
Packit Service 97d2fb
#include <unistd.h>
Packit Service 97d2fb
#include <assert.h>
Packit Service 97d2fb
Packit Service 97d2fb
#include <system.h>
Packit Service 97d2fb
#include "libelfP.h"
Packit Service 97d2fb
#include "common.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
ElfW2(LIBELFBITS,Phdr) *
Packit Service 97d2fb
__elfw2(LIBELFBITS,getphdr_wrlock) (Elf *elf)
Packit Service 97d2fb
{
Packit Service 97d2fb
  ElfW2(LIBELFBITS,Phdr) *result;
Packit Service 97d2fb
Packit Service 97d2fb
  /* If the program header entry has already been filled in the code
Packit Service 97d2fb
     below must already have been run.  So the class is set, too.  No
Packit Service 97d2fb
     need to waste any more time here.  */
Packit Service 97d2fb
  result = elf->state.ELFW(elf,LIBELFBITS).phdr;
Packit Service 97d2fb
  if (likely (result != NULL))
Packit Service 97d2fb
    return result;
Packit Service 97d2fb
Packit Service 97d2fb
  if (elf->class == 0)
Packit Service 97d2fb
    elf->class = ELFW(ELFCLASS,LIBELFBITS);
Packit Service 97d2fb
  else if (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 (likely (result == NULL))
Packit Service 97d2fb
    {
Packit Service 97d2fb
      /* Read the section header table.  */
Packit Service 97d2fb
      ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
Packit Service 97d2fb
Packit Service 97d2fb
      /* If no program header exists return NULL.  */
Packit Service 97d2fb
      size_t phnum;
Packit Service 97d2fb
      if (__elf_getphdrnum_rdlock (elf, &phnum) != 0)
Packit Service 97d2fb
	goto out;
Packit Service 97d2fb
      if (phnum == 0 || ehdr->e_phoff == 0)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  __libelf_seterrno (ELF_E_NO_PHDR);
Packit Service 97d2fb
	  goto out;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      /* Check this doesn't overflow.  */
Packit Service 97d2fb
      size_t size = phnum * sizeof (ElfW2(LIBELFBITS,Phdr));
Packit Service 97d2fb
Packit Service 97d2fb
      if (phnum > SIZE_MAX / sizeof (ElfW2(LIBELFBITS,Phdr))
Packit Service 97d2fb
	  || ehdr->e_phoff > elf->maximum_size
Packit Service 97d2fb
	  || elf->maximum_size - ehdr->e_phoff < size)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  __libelf_seterrno (ELF_E_INVALID_DATA);
Packit Service 97d2fb
	  goto out;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      if (elf->map_address != NULL)
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* First see whether the information in the ELF header is
Packit Service 97d2fb
	     valid and it does not ask for too much.  */
Packit Service 97d2fb
	  if (unlikely (ehdr->e_phoff >= elf->maximum_size)
Packit Service 97d2fb
	      || unlikely (elf->maximum_size - ehdr->e_phoff < size))
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      /* Something is wrong.  */
Packit Service 97d2fb
	      __libelf_seterrno (ELF_E_INVALID_PHDR);
Packit Service 97d2fb
	      goto out;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  /* All the data is already mapped.  Use it.  */
Packit Service 97d2fb
	  void *file_phdr = ((char *) elf->map_address
Packit Service 97d2fb
			     + elf->start_offset + ehdr->e_phoff);
Packit Service 97d2fb
	  if (ehdr->e_ident[EI_DATA] == MY_ELFDATA
Packit Service 97d2fb
	      && (ALLOW_UNALIGNED
Packit Service 97d2fb
		  || ((uintptr_t) file_phdr
Packit Service 97d2fb
		      & (__alignof__ (ElfW2(LIBELFBITS,Phdr)) - 1)) == 0))
Packit Service 97d2fb
	    /* Simply use the mapped data.  */
Packit Service 97d2fb
	    elf->state.ELFW(elf,LIBELFBITS).phdr = file_phdr;
Packit Service 97d2fb
	  else
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      ElfW2(LIBELFBITS,Phdr) *notcvt;
Packit Service 97d2fb
	      ElfW2(LIBELFBITS,Phdr) *phdr;
Packit Service 97d2fb
Packit Service 97d2fb
	      /* Allocate memory for the program headers.  We know the number
Packit Service 97d2fb
		 of entries from the ELF header.  */
Packit Service 97d2fb
	      phdr = elf->state.ELFW(elf,LIBELFBITS).phdr =
Packit Service 97d2fb
		(ElfW2(LIBELFBITS,Phdr) *) malloc (size);
Packit Service 97d2fb
	      if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  __libelf_seterrno (ELF_E_NOMEM);
Packit Service 97d2fb
		  goto out;
Packit Service 97d2fb
		}
Packit Service 97d2fb
	      elf->state.ELFW(elf,LIBELFBITS).phdr_flags |=
Packit Service 97d2fb
		ELF_F_MALLOCED | ELF_F_DIRTY;
Packit Service 97d2fb
Packit Service 97d2fb
	      /* Now copy the data and at the same time convert the
Packit Service 97d2fb
		 byte order.  */
Packit Service 97d2fb
Packit Service 97d2fb
	      if (ehdr->e_ident[EI_DATA] == MY_ELFDATA)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  assert (! ALLOW_UNALIGNED);
Packit Service 97d2fb
		  memcpy (phdr, file_phdr, size);
Packit Service 97d2fb
		}
Packit Service 97d2fb
	      else
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  bool copy = ! (ALLOW_UNALIGNED
Packit Service 97d2fb
				 || ((uintptr_t) file_phdr
Packit Service 97d2fb
				     & (__alignof__ (ElfW2(LIBELFBITS,Phdr))
Packit Service 97d2fb
					- 1)) == 0);
Packit Service 97d2fb
		  if (! copy)
Packit Service 97d2fb
		    notcvt = file_phdr;
Packit Service 97d2fb
		  else
Packit Service 97d2fb
		    {
Packit Service 97d2fb
		      notcvt = (ElfW2(LIBELFBITS,Phdr) *) malloc (size);
Packit Service 97d2fb
		      if (unlikely (notcvt == NULL))
Packit Service 97d2fb
			{
Packit Service 97d2fb
			  __libelf_seterrno (ELF_E_NOMEM);
Packit Service 97d2fb
			  goto out;
Packit Service 97d2fb
			}
Packit Service 97d2fb
		      memcpy (notcvt, file_phdr, size);
Packit Service 97d2fb
		    }
Packit Service 97d2fb
Packit Service 97d2fb
		  for (size_t cnt = 0; cnt < phnum; ++cnt)
Packit Service 97d2fb
		    {
Packit Service 97d2fb
		      CONVERT_TO (phdr[cnt].p_type, notcvt[cnt].p_type);
Packit Service 97d2fb
		      CONVERT_TO (phdr[cnt].p_offset, notcvt[cnt].p_offset);
Packit Service 97d2fb
		      CONVERT_TO (phdr[cnt].p_vaddr, notcvt[cnt].p_vaddr);
Packit Service 97d2fb
		      CONVERT_TO (phdr[cnt].p_paddr, notcvt[cnt].p_paddr);
Packit Service 97d2fb
		      CONVERT_TO (phdr[cnt].p_filesz, notcvt[cnt].p_filesz);
Packit Service 97d2fb
		      CONVERT_TO (phdr[cnt].p_memsz, notcvt[cnt].p_memsz);
Packit Service 97d2fb
		      CONVERT_TO (phdr[cnt].p_flags, notcvt[cnt].p_flags);
Packit Service 97d2fb
		      CONVERT_TO (phdr[cnt].p_align, notcvt[cnt].p_align);
Packit Service 97d2fb
		    }
Packit Service 97d2fb
Packit Service 97d2fb
		  if (copy)
Packit Service 97d2fb
		    free (notcvt);
Packit Service 97d2fb
		}
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else if (likely (elf->fildes != -1))
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* Allocate memory for the program headers.  We know the number
Packit Service 97d2fb
	     of entries from the ELF header.  */
Packit Service 97d2fb
	  elf->state.ELFW(elf,LIBELFBITS).phdr =
Packit Service 97d2fb
	    (ElfW2(LIBELFBITS,Phdr) *) malloc (size);
Packit Service 97d2fb
	  if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      __libelf_seterrno (ELF_E_NOMEM);
Packit Service 97d2fb
	      goto out;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	  elf->state.ELFW(elf,LIBELFBITS).phdr_flags |= ELF_F_MALLOCED;
Packit Service 97d2fb
Packit Service 97d2fb
	  /* Read the header.  */
Packit Service 97d2fb
	  ssize_t n = pread_retry (elf->fildes,
Packit Service 97d2fb
				   elf->state.ELFW(elf,LIBELFBITS).phdr, size,
Packit Service 97d2fb
				   elf->start_offset + ehdr->e_phoff);
Packit Service 97d2fb
	  if (unlikely ((size_t) n != size))
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      /* Severe problems.  We cannot read the data.  */
Packit Service 97d2fb
	      __libelf_seterrno (ELF_E_READ_ERROR);
Packit Service 97d2fb
	      free (elf->state.ELFW(elf,LIBELFBITS).phdr);
Packit Service 97d2fb
	      elf->state.ELFW(elf,LIBELFBITS).phdr = NULL;
Packit Service 97d2fb
	      goto out;
Packit Service 97d2fb
	    }
Packit Service 97d2fb
Packit Service 97d2fb
	  /* If the byte order of the file is not the same as the one
Packit Service 97d2fb
	     of the host convert the data now.  */
Packit Service 97d2fb
	  if (ehdr->e_ident[EI_DATA] != MY_ELFDATA)
Packit Service 97d2fb
	    {
Packit Service 97d2fb
	      ElfW2(LIBELFBITS,Phdr) *phdr
Packit Service 97d2fb
		= elf->state.ELFW(elf,LIBELFBITS).phdr;
Packit Service 97d2fb
Packit Service 97d2fb
	      for (size_t cnt = 0; cnt < phnum; ++cnt)
Packit Service 97d2fb
		{
Packit Service 97d2fb
		  CONVERT (phdr[cnt].p_type);
Packit Service 97d2fb
		  CONVERT (phdr[cnt].p_offset);
Packit Service 97d2fb
		  CONVERT (phdr[cnt].p_vaddr);
Packit Service 97d2fb
		  CONVERT (phdr[cnt].p_paddr);
Packit Service 97d2fb
		  CONVERT (phdr[cnt].p_filesz);
Packit Service 97d2fb
		  CONVERT (phdr[cnt].p_memsz);
Packit Service 97d2fb
		  CONVERT (phdr[cnt].p_flags);
Packit Service 97d2fb
		  CONVERT (phdr[cnt].p_align);
Packit Service 97d2fb
		}
Packit Service 97d2fb
	    }
Packit Service 97d2fb
	}
Packit Service 97d2fb
      else
Packit Service 97d2fb
	{
Packit Service 97d2fb
	  /* The file descriptor was already enabled and not all data was
Packit Service 97d2fb
	     read.  */
Packit Service 97d2fb
	  __libelf_seterrno (ELF_E_FD_DISABLED);
Packit Service 97d2fb
	  goto out;
Packit Service 97d2fb
	}
Packit Service 97d2fb
Packit Service 97d2fb
      result = elf->state.ELFW(elf,LIBELFBITS).phdr;
Packit Service 97d2fb
    }
Packit Service 97d2fb
Packit Service 97d2fb
 out:
Packit Service 97d2fb
  return result;
Packit Service 97d2fb
}
Packit Service 97d2fb
Packit Service 97d2fb
ElfW2(LIBELFBITS,Phdr) *
Packit Service 97d2fb
elfw2(LIBELFBITS,getphdr) (Elf *elf)
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
  /* If the program header entry has already been filled in the code
Packit Service 97d2fb
   * in getphdr_wrlock must already have been run.  So the class is
Packit Service 97d2fb
   * set, too.  No need to waste any more time here.  */
Packit Service 97d2fb
  result = elf->state.ELFW(elf,LIBELFBITS).phdr;
Packit Service 97d2fb
  if (likely (result != NULL))
Packit Service 97d2fb
    return result;
Packit Service 97d2fb
Packit Service 97d2fb
  rwlock_wrlock (elf->lock);
Packit Service 97d2fb
  result = __elfw2(LIBELFBITS,getphdr_wrlock) (elf);
Packit Service 97d2fb
  rwlock_unlock (elf->lock);
Packit Service 97d2fb
Packit Service 97d2fb
  return result;
Packit Service 97d2fb
}
Packit Service 97d2fb
INTDEF(elfw2(LIBELFBITS,getphdr))