LCOV - code coverage report
Current view: top level - libdwfl - elf-from-memory.c (source / functions) Hit Total Coverage
Test: elfutils-0.176 Lines: 129 161 80.1 %
Date: 2019-02-15 17:57:54 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           0 :     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           0 :     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           0 :     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           1 :     case ELFCLASS32:
     130           1 :       xlatefrom.d_size = sizeof (Elf32_Ehdr);
     131           1 :       if (elf32_xlatetom (&xlateto, &xlatefrom, buffer[EI_DATA]) == NULL)
     132             :         {
     133           0 :         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             :       /* NOTE if the number of sections is > 0xff00 then e_shnum
     143             :          is zero and the actual number would come from the section
     144             :          zero sh_size field. We ignore this here because getting shdrs
     145             :          is just a nice bonus (see below where we trim the last phdrs
     146             :          PT_LOAD segment).  */
     147           1 :       shdrs_end = ehdr.e32.e_shoff + ehdr.e32.e_shnum * ehdr.e32.e_shentsize;
     148           1 :       break;
     149             : 
     150           4 :     case ELFCLASS64:
     151           4 :       xlatefrom.d_size = sizeof (Elf64_Ehdr);
     152           4 :       if (elf64_xlatetom (&xlateto, &xlatefrom, buffer[EI_DATA]) == NULL)
     153             :         goto libelf_error;
     154           4 :       phoff = ehdr.e64.e_phoff;
     155           4 :       phnum = ehdr.e64.e_phnum;
     156           4 :       phentsize = ehdr.e64.e_phentsize;
     157           4 :       if (phentsize != sizeof (Elf64_Phdr) || phnum == 0)
     158             :         goto bad_elf;
     159             :       /* See the NOTE above for shdrs_end and ehdr.e32.e_shnum.  */
     160           4 :       shdrs_end = ehdr.e64.e_shoff + ehdr.e64.e_shnum * ehdr.e64.e_shentsize;
     161           4 :       break;
     162             : 
     163             :     default:
     164             :       goto bad_elf;
     165             :     }
     166             : 
     167             : 
     168             :   /* The file header tells where to find the program headers.
     169             :      These are what we use to actually choose what to read.  */
     170             : 
     171           5 :   xlatefrom.d_type = xlateto.d_type = ELF_T_PHDR;
     172           5 :   xlatefrom.d_size = phnum * phentsize;
     173             : 
     174           5 :   if ((size_t) nread >= phoff + phnum * phentsize)
     175             :     /* We already have all the phdrs from the initial read.  */
     176           1 :     xlatefrom.d_buf = buffer + phoff;
     177             :   else
     178             :     {
     179             :       /* Read in the program headers.  */
     180             : 
     181           4 :       if (initial_bufsize < (size_t)phnum * phentsize)
     182             :         {
     183           1 :           unsigned char *newbuf = realloc (buffer, phnum * phentsize);
     184           1 :           if (newbuf == NULL)
     185             :             {
     186           0 :               free (buffer);
     187             :               free (phdrsp);
     188           0 :               goto no_memory;
     189             :             }
     190           1 :           buffer = newbuf;
     191             :         }
     192           4 :       nread = (*read_memory) (arg, buffer, ehdr_vma + phoff,
     193             :                               phnum * phentsize, phnum * phentsize);
     194           4 :       if (nread <= 0)
     195             :         goto read_error;
     196             : 
     197           4 :       xlatefrom.d_buf = buffer;
     198             :     }
     199             : 
     200           5 :   bool class32 = ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32;
     201           5 :   size_t phdr_size = class32 ? sizeof (Elf32_Phdr) : sizeof (Elf64_Phdr);
     202             :   if (unlikely (phnum > SIZE_MAX / phdr_size))
     203             :     {
     204             :       free (buffer);
     205             :       goto no_memory;
     206             :     }
     207           5 :   const size_t phdrsp_bytes = phnum * phdr_size;
     208           5 :   phdrsp = malloc (phdrsp_bytes);
     209           5 :   if (unlikely (phdrsp == NULL))
     210             :     {
     211           0 :       free (buffer);
     212           0 :       goto no_memory;
     213             :     }
     214             : 
     215           5 :   xlateto.d_buf = phdrsp;
     216           5 :   xlateto.d_size = phdrsp_bytes;
     217             : 
     218             :   /* Scan for PT_LOAD segments to find the total size of the file image.  */
     219           5 :   size_t contents_size = 0;
     220           5 :   GElf_Off segments_end = 0;
     221           5 :   GElf_Off segments_end_mem = 0;
     222           5 :   GElf_Addr loadbase = ehdr_vma;
     223           5 :   bool found_base = false;
     224           5 :   Elf32_Phdr (*p32)[phnum] = phdrsp;
     225           5 :   Elf64_Phdr (*p64)[phnum] = phdrsp;
     226           5 :   switch (ehdr.e32.e_ident[EI_CLASS])
     227             :     {
     228             :       /* Sanity checks segments and calculates segment_end,
     229             :          segments_end, segments_end_mem and loadbase (if not
     230             :          found_base yet).  Returns true if sanity checking failed,
     231             :          false otherwise.  */
     232           8 :       inline bool handle_segment (GElf_Addr vaddr, GElf_Off offset,
     233             :                                   GElf_Xword filesz, GElf_Xword memsz)
     234             :         {
     235             :           /* Sanity check the segment load aligns with the pagesize.  */
     236           8 :           if (((vaddr - offset) & (pagesize - 1)) != 0)
     237             :             return true;
     238             : 
     239          16 :           GElf_Off segment_end = ((offset + filesz + pagesize - 1)
     240           8 :                                   & -pagesize);
     241             : 
     242           8 :           if (segment_end > (GElf_Off) contents_size)
     243           8 :             contents_size = segment_end;
     244             : 
     245           8 :           if (!found_base && (offset & -pagesize) == 0)
     246             :             {
     247           5 :               loadbase = ehdr_vma - (vaddr & -pagesize);
     248           5 :               found_base = true;
     249             :             }
     250             : 
     251           8 :           segments_end = offset + filesz;
     252           8 :           segments_end_mem = offset + memsz;
     253           8 :           return false;
     254             :         }
     255             : 
     256           1 :     case ELFCLASS32:
     257           1 :       if (elf32_xlatetom (&xlateto, &xlatefrom,
     258           1 :                           ehdr.e32.e_ident[EI_DATA]) == NULL)
     259             :         goto libelf_error;
     260           4 :       for (uint_fast16_t i = 0; i < phnum; ++i)
     261           4 :         if ((*p32)[i].p_type == PT_LOAD)
     262           2 :           if (handle_segment ((*p32)[i].p_vaddr, (*p32)[i].p_offset,
     263           2 :                               (*p32)[i].p_filesz, (*p32)[i].p_memsz))
     264             :             goto bad_elf;
     265             :       break;
     266             : 
     267           4 :     case ELFCLASS64:
     268           4 :       if (elf64_xlatetom (&xlateto, &xlatefrom,
     269           4 :                           ehdr.e64.e_ident[EI_DATA]) == NULL)
     270             :         goto libelf_error;
     271          21 :       for (uint_fast16_t i = 0; i < phnum; ++i)
     272          21 :         if ((*p64)[i].p_type == PT_LOAD)
     273           7 :           if (handle_segment ((*p64)[i].p_vaddr, (*p64)[i].p_offset,
     274             :                               (*p64)[i].p_filesz, (*p64)[i].p_memsz))
     275             :             goto bad_elf;
     276             :       break;
     277             : 
     278           0 :     default:
     279           0 :       abort ();
     280             :       break;
     281             :     }
     282             : 
     283             :   /* Trim the last segment so we don't bother with zeros in the last page
     284             :      that are off the end of the file.  However, if the extra bit in that
     285             :      page includes the section headers and the memory isn't extended (which
     286             :      might indicate it will have been reused otherwise), keep them.  */
     287           5 :   if ((GElf_Off) contents_size > segments_end
     288           5 :       && (GElf_Off) contents_size >= shdrs_end
     289           4 :       && segments_end == segments_end_mem)
     290             :     {
     291           4 :       contents_size = segments_end;
     292           4 :       if ((GElf_Off) contents_size < shdrs_end)
     293           4 :         contents_size = shdrs_end;
     294             :     }
     295             :   else
     296           1 :     contents_size = segments_end;
     297             : 
     298           5 :   free (buffer);
     299             : 
     300             :   /* Now we know the size of the whole image we want read in.  */
     301           5 :   buffer = calloc (1, contents_size);
     302           5 :   if (buffer == NULL)
     303             :     {
     304           0 :       free (phdrsp);
     305           0 :       goto no_memory;
     306             :     }
     307             : 
     308           5 :   switch (ehdr.e32.e_ident[EI_CLASS])
     309             :     {
     310             :       /* Reads the given segment.  Returns true if reading fails,
     311             :          false otherwise.  */
     312           8 :       inline bool handle_segment (GElf_Addr vaddr, GElf_Off offset,
     313             :                                   GElf_Xword filesz)
     314             :         {
     315           8 :           GElf_Off start = offset & -pagesize;
     316           8 :           GElf_Off end = (offset + filesz + pagesize - 1) & -pagesize;
     317           8 :           if (end > (GElf_Off) contents_size)
     318           5 :             end = contents_size;
     319          16 :           nread = (*read_memory) (arg, buffer + start,
     320           8 :                                   (loadbase + vaddr) & -pagesize,
     321             :                                   end - start, end - start);
     322           8 :           return nread <= 0;
     323             :         }
     324             : 
     325             :     case ELFCLASS32:
     326           4 :       for (uint_fast16_t i = 0; i < phnum; ++i)
     327           4 :         if ((*p32)[i].p_type == PT_LOAD)
     328           1 :           if (handle_segment ((*p32)[i].p_vaddr, (*p32)[i].p_offset,
     329           1 :                               (*p32)[i].p_filesz))
     330             :             goto read_error;
     331             : 
     332             :       /* If the segments visible in memory didn't include the section
     333             :          headers, then clear them from the file header.  */
     334           1 :       if (contents_size < shdrs_end)
     335             :         {
     336           0 :           ehdr.e32.e_shoff = 0;
     337           0 :           ehdr.e32.e_shnum = 0;
     338           0 :           ehdr.e32.e_shstrndx = 0;
     339             :         }
     340             : 
     341             :       /* This will normally have been in the first PT_LOAD segment.  But it
     342             :          conceivably could be missing, and we might have just changed it.  */
     343           1 :       xlatefrom.d_type = xlateto.d_type = ELF_T_EHDR;
     344           1 :       xlatefrom.d_size = xlateto.d_size = sizeof ehdr.e32;
     345           1 :       xlatefrom.d_buf = &ehdr.e32;
     346           1 :       xlateto.d_buf = buffer;
     347           1 :       if (elf32_xlatetof (&xlateto, &xlatefrom,
     348           1 :                           ehdr.e32.e_ident[EI_DATA]) == NULL)
     349             :         goto libelf_error;
     350             :       break;
     351             : 
     352             :     case ELFCLASS64:
     353          21 :       for (uint_fast16_t i = 0; i < phnum; ++i)
     354          21 :         if ((*p64)[i].p_type == PT_LOAD)
     355           7 :           if (handle_segment ((*p64)[i].p_vaddr, (*p64)[i].p_offset,
     356             :                               (*p64)[i].p_filesz))
     357             :             goto read_error;
     358             : 
     359             :       /* If the segments visible in memory didn't include the section
     360             :          headers, then clear them from the file header.  */
     361           4 :       if (contents_size < shdrs_end)
     362             :         {
     363           1 :           ehdr.e64.e_shoff = 0;
     364           1 :           ehdr.e64.e_shnum = 0;
     365           1 :           ehdr.e64.e_shstrndx = 0;
     366             :         }
     367             : 
     368             :       /* This will normally have been in the first PT_LOAD segment.  But it
     369             :          conceivably could be missing, and we might have just changed it.  */
     370           4 :       xlatefrom.d_type = xlateto.d_type = ELF_T_EHDR;
     371           4 :       xlatefrom.d_size = xlateto.d_size = sizeof ehdr.e64;
     372           4 :       xlatefrom.d_buf = &ehdr.e64;
     373           4 :       xlateto.d_buf = buffer;
     374           4 :       if (elf64_xlatetof (&xlateto, &xlatefrom,
     375           4 :                           ehdr.e64.e_ident[EI_DATA]) == NULL)
     376             :         goto libelf_error;
     377             :       break;
     378             : 
     379           0 :     default:
     380           0 :       abort ();
     381             :       break;
     382             :     }
     383             : 
     384           5 :   free (phdrsp);
     385           5 :   phdrsp = NULL;
     386             : 
     387             :   /* Now we have the image.  Open libelf on it.  */
     388             : 
     389           5 :   Elf *elf = elf_memory ((char *) buffer, contents_size);
     390           5 :   if (elf == NULL)
     391             :     {
     392           0 :       free (buffer);
     393           0 :       goto libelf_error;
     394             :     }
     395             : 
     396           5 :   elf->flags |= ELF_F_MALLOCED;
     397           5 :   if (loadbasep != NULL)
     398           0 :     *loadbasep = loadbase;
     399             :   return elf;
     400             : }

Generated by: LCOV version 1.13