Home | History | Annotate | Download | only in libdwfl
      1 /* Reconstruct an ELF file by reading the segments out of remote memory.
      2    Copyright (C) 2005, 2006, 2007 Red Hat, Inc.
      3    This file is part of Red Hat elfutils.
      4 
      5    Red Hat elfutils is free software; you can redistribute it and/or modify
      6    it under the terms of the GNU General Public License as published by the
      7    Free Software Foundation; version 2 of the License.
      8 
      9    Red Hat elfutils is distributed in the hope that it will be useful, but
     10    WITHOUT ANY WARRANTY; without even the implied warranty of
     11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12    General Public License for more details.
     13 
     14    You should have received a copy of the GNU General Public License along
     15    with Red Hat elfutils; if not, write to the Free Software Foundation,
     16    Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
     17 
     18    In addition, as a special exception, Red Hat, Inc. gives You the
     19    additional right to link the code of Red Hat elfutils with code licensed
     20    under any Open Source Initiative certified open source license
     21    (http://www.opensource.org/licenses/index.php) which requires the
     22    distribution of source code with any binary distribution and to
     23    distribute linked combinations of the two.  Non-GPL Code permitted under
     24    this exception must only link to the code of Red Hat elfutils through
     25    those well defined interfaces identified in the file named EXCEPTION
     26    found in the source code files (the "Approved Interfaces").  The files
     27    of Non-GPL Code may instantiate templates or use macros or inline
     28    functions from the Approved Interfaces without causing the resulting
     29    work to be covered by the GNU General Public License.  Only Red Hat,
     30    Inc. may make changes or additions to the list of Approved Interfaces.
     31    Red Hat's grant of this exception is conditioned upon your not adding
     32    any new exceptions.  If you wish to add a new Approved Interface or
     33    exception, please contact Red Hat.  You must obey the GNU General Public
     34    License in all respects for all of the Red Hat elfutils code and other
     35    code used in conjunction with Red Hat elfutils except the Non-GPL Code
     36    covered by this exception.  If you modify this file, you may extend this
     37    exception to your version of the file, but you are not obligated to do
     38    so.  If you do not wish to provide this exception without modification,
     39    you must delete this exception statement from your version and license
     40    this file solely under the GPL without exception.
     41 
     42    Red Hat elfutils is an included package of the Open Invention Network.
     43    An included package of the Open Invention Network is a package for which
     44    Open Invention Network licensees cross-license their patents.  No patent
     45    license is granted, either expressly or impliedly, by designation as an
     46    included package.  Should you wish to participate in the Open Invention
     47    Network licensing program, please visit www.openinventionnetwork.com
     48    <http://www.openinventionnetwork.com>.  */
     49 
     50 #include <config.h>
     51 #include "../libelf/libelfP.h"
     52 #undef _
     53 
     54 #include "libdwflP.h"
     55 
     56 #include <gelf.h>
     57 #include <sys/types.h>
     58 #include <stdbool.h>
     59 #include <stdlib.h>
     60 #include <string.h>
     61 
     62 /* Reconstruct an ELF file by reading the segments out of remote memory
     63    based on the ELF file header at EHDR_VMA and the ELF program headers it
     64    points to.  If not null, *LOADBASEP is filled in with the difference
     65    between the addresses from which the segments were read, and the
     66    addresses the file headers put them at.
     67 
     68    The function READ_MEMORY is called to copy at least MINREAD and at most
     69    MAXREAD bytes from the remote memory at target address ADDRESS into the
     70    local buffer at DATA; it should return -1 for errors (with code in
     71    `errno'), 0 if it failed to read at least MINREAD bytes due to EOF, or
     72    the number of bytes read if >= MINREAD.  ARG is passed through.  */
     73 
     74 Elf *
     75 elf_from_remote_memory (GElf_Addr ehdr_vma,
     76 			GElf_Addr *loadbasep,
     77 			ssize_t (*read_memory) (void *arg, void *data,
     78 						GElf_Addr address,
     79 						size_t minread,
     80 						size_t maxread),
     81 			void *arg)
     82 {
     83   /* First read in the file header and check its sanity.  */
     84 
     85   const size_t initial_bufsize = 256;
     86   unsigned char *buffer = malloc (initial_bufsize);
     87   if (buffer == NULL)
     88     {
     89     no_memory:
     90       __libdwfl_seterrno (DWFL_E_NOMEM);
     91       return NULL;
     92     }
     93 
     94   ssize_t nread = (*read_memory) (arg, buffer, ehdr_vma,
     95 				  sizeof (Elf32_Ehdr), initial_bufsize);
     96   if (nread <= 0)
     97     {
     98     read_error:
     99       free (buffer);
    100       __libdwfl_seterrno (nread < 0 ? DWFL_E_ERRNO : DWFL_E_TRUNCATED);
    101       return NULL;
    102     }
    103 
    104   if (memcmp (buffer, ELFMAG, SELFMAG) != 0)
    105     {
    106     bad_elf:
    107       __libdwfl_seterrno (DWFL_E_BADELF);
    108       return NULL;
    109     }
    110 
    111   /* Extract the information we need from the file header.  */
    112 
    113   union
    114   {
    115     Elf32_Ehdr e32;
    116     Elf64_Ehdr e64;
    117   } ehdr;
    118   Elf_Data xlatefrom =
    119     {
    120       .d_type = ELF_T_EHDR,
    121       .d_buf = buffer,
    122       .d_version = EV_CURRENT,
    123     };
    124   Elf_Data xlateto =
    125     {
    126       .d_type = ELF_T_EHDR,
    127       .d_buf = &ehdr,
    128       .d_size = sizeof ehdr,
    129       .d_version = EV_CURRENT,
    130     };
    131 
    132   GElf_Off phoff;
    133   uint_fast16_t phnum;
    134   uint_fast16_t phentsize;
    135   GElf_Off shdrs_end;
    136 
    137   switch (buffer[EI_CLASS])
    138     {
    139     case ELFCLASS32:
    140       xlatefrom.d_size = sizeof (Elf32_Ehdr);
    141       if (elf32_xlatetom (&xlateto, &xlatefrom, buffer[EI_DATA]) == NULL)
    142 	{
    143 	libelf_error:
    144 	  __libdwfl_seterrno (DWFL_E_LIBELF);
    145 	  return NULL;
    146 	}
    147       phoff = ehdr.e32.e_phoff;
    148       phnum = ehdr.e32.e_phnum;
    149       phentsize = ehdr.e32.e_phentsize;
    150       if (phentsize != sizeof (Elf32_Phdr) || phnum == 0)
    151 	goto bad_elf;
    152       shdrs_end = ehdr.e32.e_shoff + ehdr.e32.e_shnum * ehdr.e32.e_shentsize;
    153       break;
    154 
    155     case ELFCLASS64:
    156       xlatefrom.d_size = sizeof (Elf64_Ehdr);
    157       if (elf64_xlatetom (&xlateto, &xlatefrom, buffer[EI_DATA]) == NULL)
    158 	goto libelf_error;
    159       phoff = ehdr.e64.e_phoff;
    160       phnum = ehdr.e64.e_phnum;
    161       phentsize = ehdr.e64.e_phentsize;
    162       if (phentsize != sizeof (Elf64_Phdr) || phnum == 0)
    163 	goto bad_elf;
    164       shdrs_end = ehdr.e64.e_shoff + ehdr.e64.e_shnum * ehdr.e64.e_shentsize;
    165       break;
    166 
    167     default:
    168       goto bad_elf;
    169     }
    170 
    171 
    172   /* The file header tells where to find the program headers.
    173      These are what we use to actually choose what to read.  */
    174 
    175   xlatefrom.d_type = xlateto.d_type = ELF_T_PHDR;
    176   xlatefrom.d_size = phnum * phentsize;
    177 
    178   if ((size_t) nread >= phoff + phnum * phentsize)
    179     /* We already have all the phdrs from the initial read.  */
    180     xlatefrom.d_buf = buffer + phoff;
    181   else
    182     {
    183       /* Read in the program headers.  */
    184 
    185       if (initial_bufsize < phnum * phentsize)
    186 	{
    187 	  unsigned char *newbuf = realloc (buffer, phnum * phentsize);
    188 	  if (newbuf == NULL)
    189 	    {
    190 	      free (buffer);
    191 	      goto no_memory;
    192 	    }
    193 	  buffer = newbuf;
    194 	}
    195       nread = (*read_memory) (arg, buffer, ehdr_vma + phoff,
    196 			      phnum * phentsize, phnum * phentsize);
    197       if (nread <= 0)
    198 	goto read_error;
    199 
    200       xlatefrom.d_buf = buffer;
    201     }
    202 
    203   union
    204   {
    205     Elf32_Phdr p32[phnum];
    206     Elf64_Phdr p64[phnum];
    207   } phdrs;
    208 
    209   xlateto.d_buf = &phdrs;
    210   xlateto.d_size = sizeof phdrs;
    211 
    212   /* Scan for PT_LOAD segments to find the total size of the file image.  */
    213   size_t contents_size = 0;
    214   GElf_Off segments_end = 0;
    215   GElf_Addr loadbase = ehdr_vma;
    216   bool found_base = false;
    217   switch (ehdr.e32.e_ident[EI_CLASS])
    218     {
    219       inline void handle_segment (GElf_Addr vaddr, GElf_Off offset,
    220 				  GElf_Xword filesz, GElf_Xword align)
    221 	{
    222 	  GElf_Off segment_end = ((offset + filesz + align - 1) & -align);
    223 
    224 	  if (segment_end > (GElf_Off) contents_size)
    225 	    contents_size = segment_end;
    226 
    227 	  if (!found_base && (offset & -align) == 0)
    228 	    {
    229 	      loadbase = ehdr_vma - (vaddr & -align);
    230 	      found_base = true;
    231 	    }
    232 
    233 	  segments_end = offset + filesz;
    234 	}
    235 
    236     case ELFCLASS32:
    237       if (elf32_xlatetom (&xlateto, &xlatefrom,
    238 			  ehdr.e32.e_ident[EI_DATA]) == NULL)
    239 	goto libelf_error;
    240       for (uint_fast16_t i = 0; i < phnum; ++i)
    241 	if (phdrs.p32[i].p_type == PT_LOAD)
    242 	  handle_segment (phdrs.p32[i].p_vaddr, phdrs.p32[i].p_offset,
    243 			  phdrs.p32[i].p_filesz, phdrs.p32[i].p_align);
    244       break;
    245 
    246     case ELFCLASS64:
    247       if (elf32_xlatetom (&xlateto, &xlatefrom,
    248 			  ehdr.e32.e_ident[EI_DATA]) == NULL)
    249 	goto libelf_error;
    250       for (uint_fast16_t i = 0; i < phnum; ++i)
    251 	if (phdrs.p32[i].p_type == PT_LOAD)
    252 	  handle_segment (phdrs.p64[i].p_vaddr, phdrs.p64[i].p_offset,
    253 			  phdrs.p64[i].p_filesz, phdrs.p64[i].p_align);
    254       break;
    255 
    256     default:
    257       abort ();
    258       break;
    259     }
    260 
    261   /* Trim the last segment so we don't bother with zeros in the last page
    262      that are off the end of the file.  However, if the extra bit in that
    263      page includes the section headers, keep them.  */
    264   if ((GElf_Off) contents_size > segments_end
    265       && (GElf_Off) contents_size >= shdrs_end)
    266     {
    267       contents_size = segments_end;
    268       if ((GElf_Off) contents_size < shdrs_end)
    269 	contents_size = shdrs_end;
    270     }
    271   else
    272     contents_size = segments_end;
    273 
    274   free (buffer);
    275 
    276   /* Now we know the size of the whole image we want read in.  */
    277   buffer = calloc (1, contents_size);
    278   if (buffer == NULL)
    279     goto no_memory;
    280 
    281   switch (ehdr.e32.e_ident[EI_CLASS])
    282     {
    283       inline bool handle_segment (GElf_Addr vaddr, GElf_Off offset,
    284 				  GElf_Xword filesz, GElf_Xword align)
    285 	{
    286 	  GElf_Off start = offset & -align;
    287 	  GElf_Off end = (offset + filesz + align - 1) & -align;
    288 	  if (end > (GElf_Off) contents_size)
    289 	    end = contents_size;
    290 	  nread = (*read_memory) (arg, buffer + start,
    291 				  (loadbase + vaddr) & -align,
    292 				  end - start, end - start);
    293 	  return nread <= 0;
    294 	}
    295 
    296     case ELFCLASS32:
    297       for (uint_fast16_t i = 0; i < phnum; ++i)
    298 	if (phdrs.p32[i].p_type == PT_LOAD)
    299 	  if (handle_segment (phdrs.p32[i].p_vaddr, phdrs.p32[i].p_offset,
    300 			      phdrs.p32[i].p_filesz, phdrs.p32[i].p_align))
    301 	    goto read_error;
    302 
    303       /* If the segments visible in memory didn't include the section
    304 	 headers, then clear them from the file header.  */
    305       if (contents_size < shdrs_end)
    306 	{
    307 	  ehdr.e32.e_shoff = 0;
    308 	  ehdr.e32.e_shnum = 0;
    309 	  ehdr.e32.e_shstrndx = 0;
    310 	}
    311 
    312       /* This will normally have been in the first PT_LOAD segment.  But it
    313 	 conceivably could be missing, and we might have just changed it.  */
    314       xlatefrom.d_type = xlateto.d_type = ELF_T_EHDR;
    315       xlatefrom.d_size = xlateto.d_size = sizeof ehdr.e32;
    316       xlatefrom.d_buf = &ehdr.e32;
    317       xlateto.d_buf = buffer;
    318       if (elf32_xlatetof (&xlateto, &xlatefrom,
    319 			  ehdr.e32.e_ident[EI_DATA]) == NULL)
    320 	goto libelf_error;
    321       break;
    322 
    323     case ELFCLASS64:
    324       for (uint_fast16_t i = 0; i < phnum; ++i)
    325 	if (phdrs.p32[i].p_type == PT_LOAD)
    326 	  if (handle_segment (phdrs.p64[i].p_vaddr, phdrs.p64[i].p_offset,
    327 			      phdrs.p64[i].p_filesz, phdrs.p64[i].p_align))
    328 	    goto read_error;
    329 
    330       /* If the segments visible in memory didn't include the section
    331 	 headers, then clear them from the file header.  */
    332       if (contents_size < shdrs_end)
    333 	{
    334 	  ehdr.e64.e_shoff = 0;
    335 	  ehdr.e64.e_shnum = 0;
    336 	  ehdr.e64.e_shstrndx = 0;
    337 	}
    338 
    339       /* This will normally have been in the first PT_LOAD segment.  But it
    340 	 conceivably could be missing, and we might have just changed it.  */
    341       xlatefrom.d_type = xlateto.d_type = ELF_T_EHDR;
    342       xlatefrom.d_size = xlateto.d_size = sizeof ehdr.e64;
    343       xlatefrom.d_buf = &ehdr.e64;
    344       xlateto.d_buf = buffer;
    345       if (elf64_xlatetof (&xlateto, &xlatefrom,
    346 			  ehdr.e64.e_ident[EI_DATA]) == NULL)
    347 	goto libelf_error;
    348       break;
    349 
    350     default:
    351       abort ();
    352       break;
    353     }
    354 
    355   /* Now we have the image.  Open libelf on it.  */
    356 
    357   Elf *elf = elf_memory ((char *) buffer, contents_size);
    358   if (elf == NULL)
    359     {
    360       free (buffer);
    361       goto libelf_error;
    362     }
    363 
    364   elf->flags |= ELF_F_MALLOCED;
    365   if (loadbasep != NULL)
    366     *loadbasep = loadbase;
    367   return elf;
    368 }
    369