1151 lines · 33.9 KB · C
RawDownload
/* Create descriptor for processing file.   Copyright (C) 1998-2010, 2012, 2014, 2015, 2016 Red Hat, Inc.   This file is part of elfutils.   Written by Ulrich Drepper <drepper@redhat.com>, 1998.    This file is free software; you can redistribute it and/or modify   it under the terms of either      * the GNU Lesser General Public License as published by the Free       Software Foundation; either version 3 of the License, or (at       your option) any later version    or      * the GNU General Public License as published by the Free       Software Foundation; either version 2 of the License, or (at       your option) any later version    or both in parallel, as here.    elfutils is distributed in the hope that it will be useful, but   WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU   General Public License for more details.    You should have received copies of the GNU General Public License and   the GNU Lesser General Public License along with this program.  If   not, see <http://www.gnu.org/licenses/>.  */ #ifdef HAVE_CONFIG_H# include <config.h>#endif #include <assert.h>#include <ctype.h>#include <errno.h>#include <fcntl.h>#include <stdbool.h>#include <stddef.h>#include <string.h>#include <unistd.h>#include <sys/mman.h>#include <sys/stat.h> #include <system.h>#include "libelfP.h"#include "common.h"  /* Create descriptor for archive in memory.  */static inline Elf *file_read_ar (int fildes, void *map_address, off_t offset, size_t maxsize,	      Elf_Cmd cmd, Elf *parent){  Elf *elf;   /* Create a descriptor.  */  elf = allocate_elf (fildes, map_address, offset, maxsize, cmd, parent,                      ELF_K_AR, 0);  if (elf != NULL)    {      /* We don't read all the symbol tables in advance.  All this will	 happen on demand.  */      elf->state.ar.offset = offset + SARMAG;       elf->state.ar.elf_ar_hdr.ar_rawname = elf->state.ar.raw_name;    }   return elf;}  static size_tget_shnum (void *map_address, unsigned char *e_ident, int fildes, off_t offset,	   size_t maxsize){  size_t result;  union  {    Elf32_Ehdr *e32;    Elf64_Ehdr *e64;    void *p;  } ehdr;  union  {    Elf32_Ehdr e32;    Elf64_Ehdr e64;  } ehdr_mem;  bool is32 = e_ident[EI_CLASS] == ELFCLASS32;   /* Make the ELF header available.  */  if (e_ident[EI_DATA] == MY_ELFDATA      && (ALLOW_UNALIGNED	  || (((size_t) e_ident	       & ((is32 ? __alignof__ (Elf32_Ehdr) : __alignof__ (Elf64_Ehdr))		  - 1)) == 0)))    ehdr.p = e_ident;  else    {      /* We already read the ELF header.  We have to copy the header	 since we possibly modify the data here and the caller	 expects the memory it passes in to be preserved.  */      ehdr.p = &ehdr_mem;       if (is32)	{	  if (ALLOW_UNALIGNED)	    {	      ehdr_mem.e32.e_shnum = ((Elf32_Ehdr *) e_ident)->e_shnum;	      ehdr_mem.e32.e_shoff = ((Elf32_Ehdr *) e_ident)->e_shoff;	    }	  else	    memcpy (&ehdr_mem, e_ident, sizeof (Elf32_Ehdr)); 	  if (e_ident[EI_DATA] != MY_ELFDATA)	    {	      CONVERT (ehdr_mem.e32.e_shnum);	      CONVERT (ehdr_mem.e32.e_shoff);	    }	}      else	{	  if (ALLOW_UNALIGNED)	    {	      ehdr_mem.e64.e_shnum = ((Elf64_Ehdr *) e_ident)->e_shnum;	      ehdr_mem.e64.e_shoff = ((Elf64_Ehdr *) e_ident)->e_shoff;	    }	  else	    memcpy (&ehdr_mem, e_ident, sizeof (Elf64_Ehdr)); 	  if (e_ident[EI_DATA] != MY_ELFDATA)	    {	      CONVERT (ehdr_mem.e64.e_shnum);	      CONVERT (ehdr_mem.e64.e_shoff);	    }	}    }   if (is32)    {      /* Get the number of sections from the ELF header.  */      result = ehdr.e32->e_shnum;       if (unlikely (result == 0) && ehdr.e32->e_shoff != 0)	{	  if (unlikely (ehdr.e32->e_shoff >= maxsize)	      || unlikely (maxsize - ehdr.e32->e_shoff < sizeof (Elf32_Shdr)))	    /* Cannot read the first section header.  */	    return 0; 	  if (likely (map_address != NULL) && e_ident[EI_DATA] == MY_ELFDATA	      && (ALLOW_UNALIGNED		  || (((size_t) ((char *) map_address + ehdr.e32->e_shoff))		      & (__alignof__ (Elf32_Shdr) - 1)) == 0))	    /* We can directly access the memory.  */	    result = ((Elf32_Shdr *) ((char *) map_address + ehdr.e32->e_shoff				      + offset))->sh_size;	  else	    {	      Elf32_Word size; 	      if (likely (map_address != NULL))		/* gcc will optimize the memcpy to a simple memory		   access while taking care of alignment issues.  */		memcpy (&size, &((Elf32_Shdr *) ((char *) map_address						 + ehdr.e32->e_shoff						 + offset))->sh_size,			sizeof (Elf32_Word));	      else		if (unlikely (pread_retry (fildes, &size, sizeof (Elf32_Word),					   offset + ehdr.e32->e_shoff					   + offsetof (Elf32_Shdr, sh_size))			      != sizeof (Elf32_Word)))		  return (size_t) -1l; 	      if (e_ident[EI_DATA] != MY_ELFDATA)		CONVERT (size); 	      result = size;	    }	}       /* If the section headers were truncated, pretend none were there.  */      if (ehdr.e32->e_shoff > maxsize	  || maxsize - ehdr.e32->e_shoff < sizeof (Elf32_Shdr) * result)	result = 0;    }  else    {      /* Get the number of sections from the ELF header.  */      result = ehdr.e64->e_shnum;       if (unlikely (result == 0) && ehdr.e64->e_shoff != 0)	{	  if (unlikely (ehdr.e64->e_shoff >= maxsize)	      || unlikely (ehdr.e64->e_shoff + sizeof (Elf64_Shdr) > maxsize))	    /* Cannot read the first section header.  */	    return 0; 	  Elf64_Xword size;	  if (likely (map_address != NULL) && e_ident[EI_DATA] == MY_ELFDATA	      && (ALLOW_UNALIGNED		  || (((size_t) ((char *) map_address + ehdr.e64->e_shoff))		      & (__alignof__ (Elf64_Shdr) - 1)) == 0))	    /* We can directly access the memory.  */	    size = ((Elf64_Shdr *) ((char *) map_address + ehdr.e64->e_shoff				    + offset))->sh_size;	  else	    {	      if (likely (map_address != NULL))		/* gcc will optimize the memcpy to a simple memory		   access while taking care of alignment issues.  */		memcpy (&size, &((Elf64_Shdr *) ((char *) map_address						 + ehdr.e64->e_shoff						 + offset))->sh_size,			sizeof (Elf64_Xword));	      else		if (unlikely (pread_retry (fildes, &size, sizeof (Elf64_Xword),					   offset + ehdr.e64->e_shoff					   + offsetof (Elf64_Shdr, sh_size))			      != sizeof (Elf64_Xword)))		  return (size_t) -1l; 	      if (e_ident[EI_DATA] != MY_ELFDATA)		CONVERT (size);	    } 	  if (size > ~((GElf_Word) 0))	    /* Invalid value, it is too large.  */	    return (size_t) -1l; 	  result = size;	}       /* If the section headers were truncated, pretend none were there.  */      if (ehdr.e64->e_shoff > maxsize	  || maxsize - ehdr.e64->e_shoff < sizeof (Elf64_Shdr) * result)	result = 0;    }   return result;}  /* Create descriptor for ELF file in memory.  */static Elf *file_read_elf (int fildes, void *map_address, unsigned char *e_ident,	       off_t offset, size_t maxsize, Elf_Cmd cmd, Elf *parent){  /* Verify the binary is of the class we can handle.  */  if (unlikely ((e_ident[EI_CLASS] != ELFCLASS32		 && e_ident[EI_CLASS] != ELFCLASS64)		/* We also can only handle two encodings.  */		|| (e_ident[EI_DATA] != ELFDATA2LSB		    && e_ident[EI_DATA] != ELFDATA2MSB)))    {      /* Cannot handle this.  */      __libelf_seterrno (ELF_E_INVALID_FILE);      return NULL;    }   /* Determine the number of sections.  */  size_t scncnt = get_shnum (map_address, e_ident, fildes, offset, maxsize);  if (scncnt == (size_t) -1l)    /* Could not determine the number of sections.  */    return NULL;   /* Check for too many sections.  */  if (e_ident[EI_CLASS] == ELFCLASS32)    {      if (scncnt > SIZE_MAX / (sizeof (Elf_Scn) + sizeof (Elf32_Shdr)))	return NULL;    }  else if (scncnt > SIZE_MAX / (sizeof (Elf_Scn) + sizeof (Elf64_Shdr)))    return NULL;   /* We can now allocate the memory.  Even if there are no section headers,     we allocate space for a zeroth section in case we need it later.  */  const size_t scnmax = (scncnt ?: (cmd == ELF_C_RDWR || cmd == ELF_C_RDWR_MMAP)			 ? 1 : 0);  Elf *elf = allocate_elf (fildes, map_address, offset, maxsize, cmd, parent,			   ELF_K_ELF, scnmax * sizeof (Elf_Scn));  if (elf == NULL)    /* Not enough memory.  */    return NULL;   assert ((unsigned int) scncnt == scncnt);  assert (offsetof (struct Elf, state.elf32.scns)	  == offsetof (struct Elf, state.elf64.scns));  elf->state.elf32.scns.cnt = scncnt;  elf->state.elf32.scns.max = scnmax;   /* Some more or less arbitrary value.  */  elf->state.elf.scnincr = 10;   /* Make the class easily available.  */  elf->class = e_ident[EI_CLASS];   if (e_ident[EI_CLASS] == ELFCLASS32)    {      /* This pointer might not be directly usable if the alignment is	 not sufficient for the architecture.  */      Elf32_Ehdr *ehdr = (Elf32_Ehdr *) ((char *) map_address + offset);       /* This is a 32-bit binary.  */      if (map_address != NULL && e_ident[EI_DATA] == MY_ELFDATA	  && (ALLOW_UNALIGNED	      || (((uintptr_t) ehdr) & (__alignof__ (Elf32_Ehdr) - 1)) == 0))	{	  /* We can use the mmapped memory.  */	  elf->state.elf32.ehdr = ehdr;	}      else	{	  /* Copy the ELF header.  */	  elf->state.elf32.ehdr = memcpy (&elf->state.elf32.ehdr_mem, e_ident,					  sizeof (Elf32_Ehdr)); 	  if (e_ident[EI_DATA] != MY_ELFDATA)	    {	      CONVERT (elf->state.elf32.ehdr_mem.e_type);	      CONVERT (elf->state.elf32.ehdr_mem.e_machine);	      CONVERT (elf->state.elf32.ehdr_mem.e_version);	      CONVERT (elf->state.elf32.ehdr_mem.e_entry);	      CONVERT (elf->state.elf32.ehdr_mem.e_phoff);	      CONVERT (elf->state.elf32.ehdr_mem.e_shoff);	      CONVERT (elf->state.elf32.ehdr_mem.e_flags);	      CONVERT (elf->state.elf32.ehdr_mem.e_ehsize);	      CONVERT (elf->state.elf32.ehdr_mem.e_phentsize);	      CONVERT (elf->state.elf32.ehdr_mem.e_phnum);	      CONVERT (elf->state.elf32.ehdr_mem.e_shentsize);	      CONVERT (elf->state.elf32.ehdr_mem.e_shnum);	      CONVERT (elf->state.elf32.ehdr_mem.e_shstrndx);	    }	}       /* Don't precache the phdr pointer here.	 elf32_getphdr will validate it against the size when asked.  */       Elf32_Off e_shoff = elf->state.elf32.ehdr->e_shoff;      if (map_address != NULL && e_ident[EI_DATA] == MY_ELFDATA	  && cmd != ELF_C_READ_MMAP /* We need a copy to be able to write.  */	  && (ALLOW_UNALIGNED	      || (((uintptr_t) ((char *) ehdr + e_shoff)		   & (__alignof__ (Elf32_Shdr) - 1)) == 0)))	{	  if (unlikely (e_shoff >= maxsize)	      || unlikely (maxsize - e_shoff			   < scncnt * sizeof (Elf32_Shdr)))	    {	    free_and_out:	      free (elf);	      __libelf_seterrno (ELF_E_INVALID_FILE);	      return NULL;	    }	  elf->state.elf32.shdr	    = (Elf32_Shdr *) ((char *) ehdr + e_shoff); 	  for (size_t cnt = 0; cnt < scncnt; ++cnt)	    {	      elf->state.elf32.scns.data[cnt].index = cnt;	      elf->state.elf32.scns.data[cnt].elf = elf;	      elf->state.elf32.scns.data[cnt].shdr.e32 =		&elf->state.elf32.shdr[cnt];	      if (likely (elf->state.elf32.shdr[cnt].sh_offset < maxsize)		  && likely (elf->state.elf32.shdr[cnt].sh_size			     <= maxsize - elf->state.elf32.shdr[cnt].sh_offset))		elf->state.elf32.scns.data[cnt].rawdata_base =		  elf->state.elf32.scns.data[cnt].data_base =		  ((char *) map_address + offset		   + elf->state.elf32.shdr[cnt].sh_offset);	      elf->state.elf32.scns.data[cnt].list = &elf->state.elf32.scns; 	      /* If this is a section with an extended index add a		 reference in the section which uses the extended		 index.  */	      if (elf->state.elf32.shdr[cnt].sh_type == SHT_SYMTAB_SHNDX		  && elf->state.elf32.shdr[cnt].sh_link < scncnt)		elf->state.elf32.scns.data[elf->state.elf32.shdr[cnt].sh_link].shndx_index		  = cnt; 	      /* Set the own shndx_index field in case it has not yet		 been set.  */	      if (elf->state.elf32.scns.data[cnt].shndx_index == 0)		elf->state.elf32.scns.data[cnt].shndx_index = -1;	    }	}      else	{	  for (size_t cnt = 0; cnt < scncnt; ++cnt)	    {	      elf->state.elf32.scns.data[cnt].index = cnt;	      elf->state.elf32.scns.data[cnt].elf = elf;	      elf->state.elf32.scns.data[cnt].list = &elf->state.elf32.scns;	    }	}       /* So far only one block with sections.  */      elf->state.elf32.scns_last = &elf->state.elf32.scns;    }  else    {      /* This pointer might not be directly usable if the alignment is	 not sufficient for the architecture.  */      Elf64_Ehdr *ehdr = (Elf64_Ehdr *) ((char *) map_address + offset);       /* This is a 64-bit binary.  */      if (map_address != NULL && e_ident[EI_DATA] == MY_ELFDATA	  && (ALLOW_UNALIGNED	      || (((uintptr_t) ehdr) & (__alignof__ (Elf64_Ehdr) - 1)) == 0))	{	  /* We can use the mmapped memory.  */	  elf->state.elf64.ehdr = ehdr;	}      else	{	  /* Copy the ELF header.  */	  elf->state.elf64.ehdr = memcpy (&elf->state.elf64.ehdr_mem, e_ident,					  sizeof (Elf64_Ehdr)); 	  if (e_ident[EI_DATA] != MY_ELFDATA)	    {	      CONVERT (elf->state.elf64.ehdr_mem.e_type);	      CONVERT (elf->state.elf64.ehdr_mem.e_machine);	      CONVERT (elf->state.elf64.ehdr_mem.e_version);	      CONVERT (elf->state.elf64.ehdr_mem.e_entry);	      CONVERT (elf->state.elf64.ehdr_mem.e_phoff);	      CONVERT (elf->state.elf64.ehdr_mem.e_shoff);	      CONVERT (elf->state.elf64.ehdr_mem.e_flags);	      CONVERT (elf->state.elf64.ehdr_mem.e_ehsize);	      CONVERT (elf->state.elf64.ehdr_mem.e_phentsize);	      CONVERT (elf->state.elf64.ehdr_mem.e_phnum);	      CONVERT (elf->state.elf64.ehdr_mem.e_shentsize);	      CONVERT (elf->state.elf64.ehdr_mem.e_shnum);	      CONVERT (elf->state.elf64.ehdr_mem.e_shstrndx);	    }	}       /* Don't precache the phdr pointer here.	 elf64_getphdr will validate it against the size when asked.  */       Elf64_Off e_shoff = elf->state.elf64.ehdr->e_shoff;      if (map_address != NULL && e_ident[EI_DATA] == MY_ELFDATA	  && cmd != ELF_C_READ_MMAP /* We need a copy to be able to write.  */	  && (ALLOW_UNALIGNED	      || (((uintptr_t) ((char *) ehdr + e_shoff)		   & (__alignof__ (Elf64_Shdr) - 1)) == 0)))	{	  if (unlikely (e_shoff >= maxsize)	      || unlikely (maxsize - e_shoff			   < scncnt * sizeof (Elf64_Shdr)))	    goto free_and_out;	  elf->state.elf64.shdr	    = (Elf64_Shdr *) ((char *) ehdr + e_shoff); 	  for (size_t cnt = 0; cnt < scncnt; ++cnt)	    {	      elf->state.elf64.scns.data[cnt].index = cnt;	      elf->state.elf64.scns.data[cnt].elf = elf;	      elf->state.elf64.scns.data[cnt].shdr.e64 =		&elf->state.elf64.shdr[cnt];	      if (likely (elf->state.elf64.shdr[cnt].sh_offset < maxsize)		  && likely (elf->state.elf64.shdr[cnt].sh_size			     <= maxsize - elf->state.elf64.shdr[cnt].sh_offset))		elf->state.elf64.scns.data[cnt].rawdata_base =		  elf->state.elf64.scns.data[cnt].data_base =		  ((char *) map_address + offset		   + elf->state.elf64.shdr[cnt].sh_offset);	      elf->state.elf64.scns.data[cnt].list = &elf->state.elf64.scns; 	      /* If this is a section with an extended index add a		 reference in the section which uses the extended		 index.  */	      if (elf->state.elf64.shdr[cnt].sh_type == SHT_SYMTAB_SHNDX		  && elf->state.elf64.shdr[cnt].sh_link < scncnt)		elf->state.elf64.scns.data[elf->state.elf64.shdr[cnt].sh_link].shndx_index		  = cnt; 	      /* Set the own shndx_index field in case it has not yet		 been set.  */	      if (elf->state.elf64.scns.data[cnt].shndx_index == 0)		elf->state.elf64.scns.data[cnt].shndx_index = -1;	    }	}      else	{	  for (size_t cnt = 0; cnt < scncnt; ++cnt)	    {	      elf->state.elf64.scns.data[cnt].index = cnt;	      elf->state.elf64.scns.data[cnt].elf = elf;	      elf->state.elf64.scns.data[cnt].list = &elf->state.elf64.scns;	    }	}       /* So far only one block with sections.  */      elf->state.elf64.scns_last = &elf->state.elf64.scns;    }   return elf;}

Lines 1–500 of 1151.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t