• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Reconstruct an ELF file by reading the segments out of remote memory.
2    Copyright (C) 2005-2011 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 *
elf_from_remote_memory(GElf_Addr ehdr_vma,GElf_Addr * loadbasep,ssize_t (* read_memory)(void * arg,void * data,GElf_Addr address,size_t minread,size_t maxread),void * arg)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 (elf64_xlatetom (&xlateto, &xlatefrom,
248 			  ehdr.e64.e_ident[EI_DATA]) == NULL)
249 	goto libelf_error;
250       for (uint_fast16_t i = 0; i < phnum; ++i)
251 	if (phdrs.p64[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