/src/elfutils/libdwfl/elf-from-memory.c
Line | Count | Source (jump to first uncovered line) |
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 * |
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 | 0 | { |
65 | | /* We might have to reserve some memory for the phdrs. Set to NULL |
66 | | here so we can always safely free it. */ |
67 | 0 | void *phdrsp = NULL; |
68 | | |
69 | | /* First read in the file header and check its sanity. */ |
70 | |
|
71 | 0 | const size_t initial_bufsize = 256; |
72 | 0 | unsigned char *buffer = malloc (initial_bufsize); |
73 | 0 | if (unlikely (buffer == NULL)) |
74 | 0 | { |
75 | 0 | no_memory: |
76 | 0 | __libdwfl_seterrno (DWFL_E_NOMEM); |
77 | 0 | return NULL; |
78 | 0 | } |
79 | | |
80 | 0 | ssize_t nread = (*read_memory) (arg, buffer, ehdr_vma, |
81 | 0 | sizeof (Elf32_Ehdr), initial_bufsize); |
82 | 0 | if (nread <= 0) |
83 | 0 | { |
84 | 0 | read_error: |
85 | 0 | free (buffer); |
86 | 0 | free (phdrsp); |
87 | 0 | __libdwfl_seterrno (nread < 0 ? DWFL_E_ERRNO : DWFL_E_TRUNCATED); |
88 | 0 | return NULL; |
89 | 0 | } |
90 | | |
91 | 0 | if (memcmp (buffer, ELFMAG, SELFMAG) != 0) |
92 | 0 | { |
93 | 0 | bad_elf: |
94 | 0 | free (buffer); |
95 | 0 | free (phdrsp); |
96 | 0 | __libdwfl_seterrno (DWFL_E_BADELF); |
97 | 0 | return NULL; |
98 | 0 | } |
99 | | |
100 | | /* Extract the information we need from the file header. */ |
101 | | |
102 | 0 | union |
103 | 0 | { |
104 | 0 | Elf32_Ehdr e32; |
105 | 0 | Elf64_Ehdr e64; |
106 | 0 | } ehdr; |
107 | 0 | Elf_Data xlatefrom = |
108 | 0 | { |
109 | 0 | .d_type = ELF_T_EHDR, |
110 | 0 | .d_buf = buffer, |
111 | 0 | .d_version = EV_CURRENT, |
112 | 0 | }; |
113 | 0 | Elf_Data xlateto = |
114 | 0 | { |
115 | 0 | .d_type = ELF_T_EHDR, |
116 | 0 | .d_buf = &ehdr, |
117 | 0 | .d_size = sizeof ehdr, |
118 | 0 | .d_version = EV_CURRENT, |
119 | 0 | }; |
120 | |
|
121 | 0 | GElf_Off phoff; |
122 | 0 | uint_fast16_t phnum; |
123 | 0 | uint_fast16_t phentsize; |
124 | 0 | GElf_Off shdrs_end; |
125 | |
|
126 | 0 | switch (buffer[EI_CLASS]) |
127 | 0 | { |
128 | 0 | case ELFCLASS32: |
129 | 0 | xlatefrom.d_size = sizeof (Elf32_Ehdr); |
130 | 0 | if (elf32_xlatetom (&xlateto, &xlatefrom, buffer[EI_DATA]) == NULL) |
131 | 0 | { |
132 | 0 | libelf_error: |
133 | 0 | __libdwfl_seterrno (DWFL_E_LIBELF); |
134 | 0 | return NULL; |
135 | 0 | } |
136 | 0 | phoff = ehdr.e32.e_phoff; |
137 | 0 | phnum = ehdr.e32.e_phnum; |
138 | 0 | phentsize = ehdr.e32.e_phentsize; |
139 | 0 | if (phentsize != sizeof (Elf32_Phdr) || phnum == 0) |
140 | 0 | 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 | 0 | shdrs_end = ehdr.e32.e_shoff + ehdr.e32.e_shnum * ehdr.e32.e_shentsize; |
147 | 0 | break; |
148 | | |
149 | 0 | case ELFCLASS64: |
150 | 0 | xlatefrom.d_size = sizeof (Elf64_Ehdr); |
151 | 0 | if (elf64_xlatetom (&xlateto, &xlatefrom, buffer[EI_DATA]) == NULL) |
152 | 0 | goto libelf_error; |
153 | 0 | phoff = ehdr.e64.e_phoff; |
154 | 0 | phnum = ehdr.e64.e_phnum; |
155 | 0 | phentsize = ehdr.e64.e_phentsize; |
156 | 0 | if (phentsize != sizeof (Elf64_Phdr) || phnum == 0) |
157 | 0 | goto bad_elf; |
158 | | /* See the NOTE above for shdrs_end and ehdr.e32.e_shnum. */ |
159 | 0 | shdrs_end = ehdr.e64.e_shoff + ehdr.e64.e_shnum * ehdr.e64.e_shentsize; |
160 | 0 | break; |
161 | | |
162 | 0 | default: |
163 | 0 | goto bad_elf; |
164 | 0 | } |
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 | 0 | xlatefrom.d_type = xlateto.d_type = ELF_T_PHDR; |
171 | 0 | xlatefrom.d_size = phnum * phentsize; |
172 | |
|
173 | 0 | if ((size_t) nread >= phoff + phnum * phentsize) |
174 | | /* We already have all the phdrs from the initial read. */ |
175 | 0 | xlatefrom.d_buf = buffer + phoff; |
176 | 0 | else |
177 | 0 | { |
178 | | /* Read in the program headers. */ |
179 | |
|
180 | 0 | if (initial_bufsize < (size_t)phnum * phentsize) |
181 | 0 | { |
182 | 0 | unsigned char *newbuf = realloc (buffer, phnum * phentsize); |
183 | 0 | if (newbuf == NULL) |
184 | 0 | { |
185 | 0 | free (buffer); |
186 | 0 | free (phdrsp); |
187 | 0 | goto no_memory; |
188 | 0 | } |
189 | 0 | buffer = newbuf; |
190 | 0 | } |
191 | 0 | nread = (*read_memory) (arg, buffer, ehdr_vma + phoff, |
192 | 0 | phnum * phentsize, phnum * phentsize); |
193 | 0 | if (nread <= 0) |
194 | 0 | goto read_error; |
195 | | |
196 | 0 | xlatefrom.d_buf = buffer; |
197 | 0 | } |
198 | | |
199 | 0 | bool class32 = ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32; |
200 | 0 | size_t phdr_size = class32 ? sizeof (Elf32_Phdr) : sizeof (Elf64_Phdr); |
201 | 0 | if (unlikely (phnum > SIZE_MAX / phdr_size)) |
202 | 0 | { |
203 | 0 | free (buffer); |
204 | 0 | goto no_memory; |
205 | 0 | } |
206 | 0 | const size_t phdrsp_bytes = phnum * phdr_size; |
207 | 0 | phdrsp = malloc (phdrsp_bytes); |
208 | 0 | if (unlikely (phdrsp == NULL)) |
209 | 0 | { |
210 | 0 | free (buffer); |
211 | 0 | goto no_memory; |
212 | 0 | } |
213 | | |
214 | 0 | xlateto.d_buf = phdrsp; |
215 | 0 | xlateto.d_size = phdrsp_bytes; |
216 | | |
217 | | /* Scan for PT_LOAD segments to find the total size of the file image. */ |
218 | 0 | size_t contents_size = 0; |
219 | 0 | GElf_Off segments_end = 0; |
220 | 0 | GElf_Off segments_end_mem = 0; |
221 | 0 | GElf_Addr loadbase = ehdr_vma; |
222 | 0 | bool found_base = false; |
223 | 0 | Elf32_Phdr (*p32)[phnum] = phdrsp; |
224 | 0 | Elf64_Phdr (*p64)[phnum] = phdrsp; |
225 | |
|
226 | 0 | if (class32) |
227 | 0 | { |
228 | 0 | if (! elf32_xlatetom (&xlateto, &xlatefrom, ehdr.e32.e_ident[EI_DATA])) |
229 | 0 | goto libelf_error; |
230 | 0 | } |
231 | 0 | else |
232 | 0 | { |
233 | 0 | if (! elf64_xlatetom (&xlateto, &xlatefrom, ehdr.e64.e_ident[EI_DATA])) |
234 | 0 | goto libelf_error; |
235 | 0 | } |
236 | | |
237 | 0 | for (uint_fast16_t i = 0; i < phnum; ++i) |
238 | 0 | { |
239 | 0 | GElf_Word type = class32 ? (*p32)[i].p_type : (*p64)[i].p_type; |
240 | |
|
241 | 0 | if (type != PT_LOAD) |
242 | 0 | continue; |
243 | | |
244 | 0 | GElf_Addr vaddr = class32 ? (*p32)[i].p_vaddr : (*p64)[i].p_vaddr; |
245 | 0 | GElf_Xword memsz = class32 ? (*p32)[i].p_memsz : (*p64)[i].p_memsz; |
246 | 0 | GElf_Off offset = class32 ? (*p32)[i].p_offset : (*p64)[i].p_offset; |
247 | 0 | GElf_Xword filesz = class32 ? (*p32)[i].p_filesz : (*p64)[i].p_filesz; |
248 | | |
249 | | /* Sanity check the segment load aligns with the pagesize. */ |
250 | 0 | if (((vaddr - offset) & (pagesize - 1)) != 0) |
251 | 0 | goto bad_elf; |
252 | | |
253 | 0 | GElf_Off segment_end = ((offset + filesz + pagesize - 1) |
254 | 0 | & -pagesize); |
255 | |
|
256 | 0 | if (segment_end > (GElf_Off) contents_size) |
257 | 0 | contents_size = segment_end; |
258 | |
|
259 | 0 | if (!found_base && (offset & -pagesize) == 0) |
260 | 0 | { |
261 | 0 | loadbase = ehdr_vma - (vaddr & -pagesize); |
262 | 0 | found_base = true; |
263 | 0 | } |
264 | |
|
265 | 0 | segments_end = offset + filesz; |
266 | 0 | segments_end_mem = offset + memsz; |
267 | 0 | } |
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 | 0 | if ((GElf_Off) contents_size > segments_end |
274 | 0 | && (GElf_Off) contents_size >= shdrs_end |
275 | 0 | && segments_end == segments_end_mem) |
276 | 0 | { |
277 | 0 | contents_size = segments_end; |
278 | 0 | if ((GElf_Off) contents_size < shdrs_end) |
279 | 0 | contents_size = shdrs_end; |
280 | 0 | } |
281 | 0 | else |
282 | 0 | contents_size = segments_end; |
283 | |
|
284 | 0 | free (buffer); |
285 | | |
286 | | /* Now we know the size of the whole image we want read in. */ |
287 | 0 | buffer = calloc (1, contents_size); |
288 | 0 | if (buffer == NULL) |
289 | 0 | { |
290 | 0 | free (phdrsp); |
291 | 0 | goto no_memory; |
292 | 0 | } |
293 | | |
294 | 0 | for (uint_fast16_t i = 0; i < phnum; ++i) |
295 | 0 | { |
296 | 0 | GElf_Word type = class32 ? (*p32)[i].p_type : (*p64)[i].p_type; |
297 | |
|
298 | 0 | if (type != PT_LOAD) |
299 | 0 | continue; |
300 | | |
301 | 0 | GElf_Addr vaddr = class32 ? (*p32)[i].p_vaddr : (*p64)[i].p_vaddr; |
302 | 0 | GElf_Off offset = class32 ? (*p32)[i].p_offset : (*p64)[i].p_offset; |
303 | 0 | GElf_Xword filesz = class32 ? (*p32)[i].p_filesz : (*p64)[i].p_filesz; |
304 | |
|
305 | 0 | GElf_Off start = offset & -pagesize; |
306 | 0 | GElf_Off end = (offset + filesz + pagesize - 1) & -pagesize; |
307 | 0 | if (end > (GElf_Off) contents_size) |
308 | 0 | end = contents_size; |
309 | 0 | nread = (*read_memory) (arg, buffer + start, |
310 | 0 | (loadbase + vaddr) & -pagesize, |
311 | 0 | end - start, end - start); |
312 | 0 | if (nread <= 0) |
313 | 0 | goto read_error; |
314 | 0 | } |
315 | | |
316 | | /* If the segments visible in memory didn't include the section |
317 | | headers, then clear them from the file header. */ |
318 | 0 | if (contents_size < shdrs_end) |
319 | 0 | { |
320 | 0 | if (class32) |
321 | 0 | { |
322 | 0 | ehdr.e32.e_shoff = 0; |
323 | 0 | ehdr.e32.e_shnum = 0; |
324 | 0 | ehdr.e32.e_shstrndx = 0; |
325 | 0 | } |
326 | 0 | else |
327 | 0 | { |
328 | 0 | ehdr.e64.e_shoff = 0; |
329 | 0 | ehdr.e64.e_shnum = 0; |
330 | 0 | ehdr.e64.e_shstrndx = 0; |
331 | 0 | } |
332 | 0 | } |
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 | 0 | xlatefrom.d_type = xlateto.d_type = ELF_T_EHDR; |
337 | 0 | xlateto.d_buf = buffer; |
338 | 0 | if (class32) |
339 | 0 | { |
340 | 0 | xlatefrom.d_size = xlateto.d_size = sizeof ehdr.e32; |
341 | 0 | xlatefrom.d_buf = &ehdr.e32; |
342 | 0 | if (elf32_xlatetof (&xlateto, &xlatefrom, |
343 | 0 | ehdr.e32.e_ident[EI_DATA]) == NULL) |
344 | 0 | goto libelf_error; |
345 | 0 | } |
346 | 0 | else |
347 | 0 | { |
348 | 0 | xlatefrom.d_size = xlateto.d_size = sizeof ehdr.e64; |
349 | 0 | xlatefrom.d_buf = &ehdr.e64; |
350 | 0 | if (elf64_xlatetof (&xlateto, &xlatefrom, |
351 | 0 | ehdr.e64.e_ident[EI_DATA]) == NULL) |
352 | 0 | goto libelf_error; |
353 | 0 | } |
354 | | |
355 | 0 | free (phdrsp); |
356 | 0 | phdrsp = NULL; |
357 | | |
358 | | /* Now we have the image. Open libelf on it. */ |
359 | |
|
360 | 0 | Elf *elf = elf_memory ((char *) buffer, contents_size); |
361 | 0 | if (elf == NULL) |
362 | 0 | { |
363 | 0 | free (buffer); |
364 | 0 | goto libelf_error; |
365 | 0 | } |
366 | | |
367 | 0 | elf->flags |= ELF_F_MALLOCED; |
368 | 0 | if (loadbasep != NULL) |
369 | 0 | *loadbasep = loadbase; |
370 | 0 | return elf; |
371 | 0 | } |