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