LCOV - code coverage report
Current view: top level - libdwfl - elf-from-memory.c (source / functions) Hit Total Coverage
Test: lcov.out Lines: 125 154 81.2 %
Date: 2017-01-05 09:15:16 Functions: 3 3 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* Reconstruct an ELF file by reading the segments out of remote memory.
       2             :    Copyright (C) 2005-2011, 2014, 2015 Red Hat, Inc.
       3             :    This file is part of elfutils.
       4             : 
       5             :    This file is free software; you can redistribute it and/or modify
       6             :    it under the terms of either
       7             : 
       8             :      * the GNU Lesser General Public License as published by the Free
       9             :        Software Foundation; either version 3 of the License, or (at
      10             :        your option) any later version
      11             : 
      12             :    or
      13             : 
      14             :      * the GNU General Public License as published by the Free
      15             :        Software Foundation; either version 2 of the License, or (at
      16             :        your option) any later version
      17             : 
      18             :    or both in parallel, as here.
      19             : 
      20             :    elfutils is distributed in the hope that it will be useful, but
      21             :    WITHOUT ANY WARRANTY; without even the implied warranty of
      22             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      23             :    General Public License for more details.
      24             : 
      25             :    You should have received copies of the GNU General Public License and
      26             :    the GNU Lesser General Public License along with this program.  If
      27             :    not, see <http://www.gnu.org/licenses/>.  */
      28             : 
      29             : #include <config.h>
      30             : #include "../libelf/libelfP.h"
      31             : #undef _
      32             : 
      33             : #include "libdwflP.h"
      34             : 
      35             : #include <gelf.h>
      36             : #include <sys/types.h>
      37             : #include <stdbool.h>
      38             : #include <stdlib.h>
      39             : #include <string.h>
      40             : 
      41             : /* Reconstruct an ELF file by reading the segments out of remote memory
      42             :    based on the ELF file header at EHDR_VMA and the ELF program headers it
      43             :    points to.  If not null, *LOADBASEP is filled in with the difference
      44             :    between the addresses from which the segments were read, and the
      45             :    addresses the file headers put them at.
      46             : 
      47             :    The function READ_MEMORY is called to copy at least MINREAD and at most
      48             :    MAXREAD bytes from the remote memory at target address ADDRESS into the
      49             :    local buffer at DATA; it should return -1 for errors (with code in
      50             :    `errno'), 0 if it failed to read at least MINREAD bytes due to EOF, or
      51             :    the number of bytes read if >= MINREAD.  ARG is passed through.
      52             : 
      53             :    PAGESIZE is the minimum page size and alignment used for the PT_LOAD
      54             :    segments.  */
      55             : 
      56             : Elf *
      57           5 : elf_from_remote_memory (GElf_Addr ehdr_vma,
      58             :                         GElf_Xword pagesize,
      59             :                         GElf_Addr *loadbasep,
      60             :                         ssize_t (*read_memory) (void *arg, void *data,
      61             :                                                 GElf_Addr address,
      62             :                                                 size_t minread,
      63             :                                                 size_t maxread),
      64             :                         void *arg)
      65             : {
      66             :   /* We might have to reserve some memory for the phdrs.  Set to NULL
      67             :      here so we can always safely free it.  */
      68           5 :   void *phdrsp = NULL;
      69             : 
      70             :   /* First read in the file header and check its sanity.  */
      71             : 
      72           5 :   const size_t initial_bufsize = 256;
      73           5 :   unsigned char *buffer = malloc (initial_bufsize);
      74           5 :   if (unlikely (buffer == NULL))
      75             :     {
      76             :     no_memory:
      77           0 :       __libdwfl_seterrno (DWFL_E_NOMEM);
      78           0 :       return NULL;
      79             :     }
      80             : 
      81           5 :   ssize_t nread = (*read_memory) (arg, buffer, ehdr_vma,
      82             :                                   sizeof (Elf32_Ehdr), initial_bufsize);
      83           5 :   if (nread <= 0)
      84             :     {
      85             :     read_error:
      86           0 :       free (buffer);
      87           0 :       free (phdrsp);
      88           0 :       __libdwfl_seterrno (nread < 0 ? DWFL_E_ERRNO : DWFL_E_TRUNCATED);
      89           0 :       return NULL;
      90             :     }
      91             : 
      92           5 :   if (memcmp (buffer, ELFMAG, SELFMAG) != 0)
      93             :     {
      94             :     bad_elf:
      95           0 :       free (buffer);
      96           0 :       free (phdrsp);
      97           0 :       __libdwfl_seterrno (DWFL_E_BADELF);
      98           0 :       return NULL;
      99             :     }
     100             : 
     101             :   /* Extract the information we need from the file header.  */
     102             : 
     103             :   union
     104             :   {
     105             :     Elf32_Ehdr e32;
     106             :     Elf64_Ehdr e64;
     107             :   } ehdr;
     108           5 :   Elf_Data xlatefrom =
     109             :     {
     110             :       .d_type = ELF_T_EHDR,
     111             :       .d_buf = buffer,
     112             :       .d_version = EV_CURRENT,
     113             :     };
     114           5 :   Elf_Data xlateto =
     115             :     {
     116             :       .d_type = ELF_T_EHDR,
     117             :       .d_buf = &ehdr,
     118             :       .d_size = sizeof ehdr,
     119             :       .d_version = EV_CURRENT,
     120             :     };
     121             : 
     122             :   GElf_Off phoff;
     123             :   uint_fast16_t phnum;
     124             :   uint_fast16_t phentsize;
     125             :   GElf_Off shdrs_end;
     126             : 
     127           5 :   switch (buffer[EI_CLASS])
     128             :     {
     129             :     case ELFCLASS32:
     130           1 :       xlatefrom.d_size = sizeof (Elf32_Ehdr);
     131           1 :       if (elf32_xlatetom (&xlateto, &xlatefrom, buffer[EI_DATA]) == NULL)
     132             :         {
     133             :         libelf_error:
     134           0 :           __libdwfl_seterrno (DWFL_E_LIBELF);
     135           0 :           return NULL;
     136             :         }
     137           1 :       phoff = ehdr.e32.e_phoff;
     138           1 :       phnum = ehdr.e32.e_phnum;
     139           1 :       phentsize = ehdr.e32.e_phentsize;
     140           1 :       if (phentsize != sizeof (Elf32_Phdr) || phnum == 0)
     141             :         goto bad_elf;
     142           1 :       shdrs_end = ehdr.e32.e_shoff + ehdr.e32.e_shnum * ehdr.e32.e_shentsize;
     143           1 :       break;
     144             : 
     145             :     case ELFCLASS64:
     146           4 :       xlatefrom.d_size = sizeof (Elf64_Ehdr);
     147           4 :       if (elf64_xlatetom (&xlateto, &xlatefrom, buffer[EI_DATA]) == NULL)
     148             :         goto libelf_error;
     149           4 :       phoff = ehdr.e64.e_phoff;
     150           4 :       phnum = ehdr.e64.e_phnum;
     151           4 :       phentsize = ehdr.e64.e_phentsize;
     152           4 :       if (phentsize != sizeof (Elf64_Phdr) || phnum == 0)
     153             :         goto bad_elf;
     154           4 :       shdrs_end = ehdr.e64.e_shoff + ehdr.e64.e_shnum * ehdr.e64.e_shentsize;
     155           4 :       break;
     156             : 
     157             :     default:
     158             :       goto bad_elf;
     159             :     }
     160             : 
     161             : 
     162             :   /* The file header tells where to find the program headers.
     163             :      These are what we use to actually choose what to read.  */
     164             : 
     165           5 :   xlatefrom.d_type = xlateto.d_type = ELF_T_PHDR;
     166           5 :   xlatefrom.d_size = phnum * phentsize;
     167             : 
     168           5 :   if ((size_t) nread >= phoff + phnum * phentsize)
     169             :     /* We already have all the phdrs from the initial read.  */
     170           1 :     xlatefrom.d_buf = buffer + phoff;
     171             :   else
     172             :     {
     173             :       /* Read in the program headers.  */
     174             : 
     175           4 :       if (initial_bufsize < phnum * phentsize)
     176             :         {
     177           1 :           unsigned char *newbuf = realloc (buffer, phnum * phentsize);
     178           1 :           if (newbuf == NULL)
     179             :             {
     180           0 :               free (buffer);
     181             :               free (phdrsp);
     182           0 :               goto no_memory;
     183             :             }
     184           1 :           buffer = newbuf;
     185             :         }
     186           4 :       nread = (*read_memory) (arg, buffer, ehdr_vma + phoff,
     187             :                               phnum * phentsize, phnum * phentsize);
     188           4 :       if (nread <= 0)
     189             :         goto read_error;
     190             : 
     191           4 :       xlatefrom.d_buf = buffer;
     192             :     }
     193             : 
     194           5 :   bool class32 = ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32;
     195           5 :   size_t phdr_size = class32 ? sizeof (Elf32_Phdr) : sizeof (Elf64_Phdr);
     196           5 :   if (unlikely (phnum > SIZE_MAX / phdr_size))
     197             :     {
     198           0 :       free (buffer);
     199           0 :       goto no_memory;
     200             :     }
     201           5 :   const size_t phdrsp_bytes = phnum * phdr_size;
     202           5 :   phdrsp = malloc (phdrsp_bytes);
     203           5 :   if (unlikely (phdrsp == NULL))
     204             :     {
     205           0 :       free (buffer);
     206           0 :       goto no_memory;
     207             :     }
     208             : 
     209           5 :   xlateto.d_buf = phdrsp;
     210           5 :   xlateto.d_size = phdrsp_bytes;
     211             : 
     212             :   /* Scan for PT_LOAD segments to find the total size of the file image.  */
     213           5 :   size_t contents_size = 0;
     214           5 :   GElf_Off segments_end = 0;
     215           5 :   GElf_Off segments_end_mem = 0;
     216           5 :   GElf_Addr loadbase = ehdr_vma;
     217           5 :   bool found_base = false;
     218           5 :   Elf32_Phdr (*p32)[phnum] = phdrsp;
     219           5 :   Elf64_Phdr (*p64)[phnum] = phdrsp;
     220           5 :   switch (ehdr.e32.e_ident[EI_CLASS])
     221             :     {
     222             :       /* Sanity checks segments and calculates segment_end,
     223             :          segments_end, segments_end_mem and loadbase (if not
     224             :          found_base yet).  Returns true if sanity checking failed,
     225             :          false otherwise.  */
     226           6 :       inline bool handle_segment (GElf_Addr vaddr, GElf_Off offset,
     227             :                                   GElf_Xword filesz, GElf_Xword memsz)
     228             :         {
     229             :           /* Sanity check the segment load aligns with the pagesize.  */
     230           6 :           if (((vaddr - offset) & (pagesize - 1)) != 0)
     231             :             return true;
     232             : 
     233          12 :           GElf_Off segment_end = ((offset + filesz + pagesize - 1)
     234           6 :                                   & -pagesize);
     235             : 
     236           6 :           if (segment_end > (GElf_Off) contents_size)
     237           6 :             contents_size = segment_end;
     238             : 
     239           6 :           if (!found_base && (offset & -pagesize) == 0)
     240             :             {
     241           5 :               loadbase = ehdr_vma - (vaddr & -pagesize);
     242           5 :               found_base = true;
     243             :             }
     244             : 
     245           6 :           segments_end = offset + filesz;
     246           6 :           segments_end_mem = offset + memsz;
     247           6 :           return false;
     248             :         }
     249             : 
     250             :     case ELFCLASS32:
     251           1 :       if (elf32_xlatetom (&xlateto, &xlatefrom,
     252           1 :                           ehdr.e32.e_ident[EI_DATA]) == NULL)
     253             :         goto libelf_error;
     254           4 :       for (uint_fast16_t i = 0; i < phnum; ++i)
     255           4 :         if ((*p32)[i].p_type == PT_LOAD)
     256           2 :           if (handle_segment ((*p32)[i].p_vaddr, (*p32)[i].p_offset,
     257           2 :                               (*p32)[i].p_filesz, (*p32)[i].p_memsz))
     258             :             goto bad_elf;
     259             :       break;
     260             : 
     261             :     case ELFCLASS64:
     262           4 :       if (elf64_xlatetom (&xlateto, &xlatefrom,
     263           4 :                           ehdr.e64.e_ident[EI_DATA]) == NULL)
     264             :         goto libelf_error;
     265          19 :       for (uint_fast16_t i = 0; i < phnum; ++i)
     266          19 :         if ((*p64)[i].p_type == PT_LOAD)
     267           5 :           if (handle_segment ((*p64)[i].p_vaddr, (*p64)[i].p_offset,
     268             :                               (*p64)[i].p_filesz, (*p64)[i].p_memsz))
     269             :             goto bad_elf;
     270             :       break;
     271             : 
     272             :     default:
     273           0 :       abort ();
     274             :       break;
     275             :     }
     276             : 
     277             :   /* Trim the last segment so we don't bother with zeros in the last page
     278             :      that are off the end of the file.  However, if the extra bit in that
     279             :      page includes the section headers and the memory isn't extended (which
     280             :      might indicate it will have been reused otherwise), keep them.  */
     281           5 :   if ((GElf_Off) contents_size > segments_end
     282           5 :       && (GElf_Off) contents_size >= shdrs_end
     283           0 :       && segments_end == segments_end_mem)
     284             :     {
     285           0 :       contents_size = segments_end;
     286           0 :       if ((GElf_Off) contents_size < shdrs_end)
     287           0 :         contents_size = shdrs_end;
     288             :     }
     289             :   else
     290           5 :     contents_size = segments_end;
     291             : 
     292           5 :   free (buffer);
     293             : 
     294             :   /* Now we know the size of the whole image we want read in.  */
     295           5 :   buffer = calloc (1, contents_size);
     296           5 :   if (buffer == NULL)
     297             :     {
     298           0 :       free (phdrsp);
     299           0 :       goto no_memory;
     300             :     }
     301             : 
     302           5 :   switch (ehdr.e32.e_ident[EI_CLASS])
     303             :     {
     304             :       /* Reads the given segment.  Returns true if reading fails,
     305             :          false otherwise.  */
     306           6 :       inline bool handle_segment (GElf_Addr vaddr, GElf_Off offset,
     307             :                                   GElf_Xword filesz)
     308             :         {
     309           6 :           GElf_Off start = offset & -pagesize;
     310           6 :           GElf_Off end = (offset + filesz + pagesize - 1) & -pagesize;
     311           6 :           if (end > (GElf_Off) contents_size)
     312           5 :             end = contents_size;
     313          12 :           nread = (*read_memory) (arg, buffer + start,
     314           6 :                                   (loadbase + vaddr) & -pagesize,
     315             :                                   end - start, end - start);
     316           6 :           return nread <= 0;
     317             :         }
     318             : 
     319             :     case ELFCLASS32:
     320           4 :       for (uint_fast16_t i = 0; i < phnum; ++i)
     321           4 :         if ((*p32)[i].p_type == PT_LOAD)
     322           1 :           if (handle_segment ((*p32)[i].p_vaddr, (*p32)[i].p_offset,
     323           1 :                               (*p32)[i].p_filesz))
     324             :             goto read_error;
     325             : 
     326             :       /* If the segments visible in memory didn't include the section
     327             :          headers, then clear them from the file header.  */
     328           1 :       if (contents_size < shdrs_end)
     329             :         {
     330           1 :           ehdr.e32.e_shoff = 0;
     331           1 :           ehdr.e32.e_shnum = 0;
     332           1 :           ehdr.e32.e_shstrndx = 0;
     333             :         }
     334             : 
     335             :       /* This will normally have been in the first PT_LOAD segment.  But it
     336             :          conceivably could be missing, and we might have just changed it.  */
     337           1 :       xlatefrom.d_type = xlateto.d_type = ELF_T_EHDR;
     338           1 :       xlatefrom.d_size = xlateto.d_size = sizeof ehdr.e32;
     339           1 :       xlatefrom.d_buf = &ehdr.e32;
     340           1 :       xlateto.d_buf = buffer;
     341           1 :       if (elf32_xlatetof (&xlateto, &xlatefrom,
     342           1 :                           ehdr.e32.e_ident[EI_DATA]) == NULL)
     343             :         goto libelf_error;
     344             :       break;
     345             : 
     346             :     case ELFCLASS64:
     347          19 :       for (uint_fast16_t i = 0; i < phnum; ++i)
     348          19 :         if ((*p64)[i].p_type == PT_LOAD)
     349           5 :           if (handle_segment ((*p64)[i].p_vaddr, (*p64)[i].p_offset,
     350             :                               (*p64)[i].p_filesz))
     351             :             goto read_error;
     352             : 
     353             :       /* If the segments visible in memory didn't include the section
     354             :          headers, then clear them from the file header.  */
     355           4 :       if (contents_size < shdrs_end)
     356             :         {
     357           4 :           ehdr.e64.e_shoff = 0;
     358           4 :           ehdr.e64.e_shnum = 0;
     359           4 :           ehdr.e64.e_shstrndx = 0;
     360             :         }
     361             : 
     362             :       /* This will normally have been in the first PT_LOAD segment.  But it
     363             :          conceivably could be missing, and we might have just changed it.  */
     364           4 :       xlatefrom.d_type = xlateto.d_type = ELF_T_EHDR;
     365           4 :       xlatefrom.d_size = xlateto.d_size = sizeof ehdr.e64;
     366           4 :       xlatefrom.d_buf = &ehdr.e64;
     367           4 :       xlateto.d_buf = buffer;
     368           4 :       if (elf64_xlatetof (&xlateto, &xlatefrom,
     369           4 :                           ehdr.e64.e_ident[EI_DATA]) == NULL)
     370             :         goto libelf_error;
     371             :       break;
     372             : 
     373             :     default:
     374           0 :       abort ();
     375             :       break;
     376             :     }
     377             : 
     378           5 :   free (phdrsp);
     379           5 :   phdrsp = NULL;
     380             : 
     381             :   /* Now we have the image.  Open libelf on it.  */
     382             : 
     383           5 :   Elf *elf = elf_memory ((char *) buffer, contents_size);
     384           5 :   if (elf == NULL)
     385             :     {
     386           0 :       free (buffer);
     387           0 :       goto libelf_error;
     388             :     }
     389             : 
     390           5 :   elf->flags |= ELF_F_MALLOCED;
     391           5 :   if (loadbasep != NULL)
     392           0 :     *loadbasep = loadbase;
     393             :   return elf;
     394             : }

Generated by: LCOV version 1.12