Branch data Line data Source code
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 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 : : Elf *
54 : 2 : elf_from_remote_memory (GElf_Addr ehdr_vma,
55 : : GElf_Addr *loadbasep,
56 : : ssize_t (*read_memory) (void *arg, void *data,
57 : : GElf_Addr address,
58 : : size_t minread,
59 : : size_t maxread),
60 : : void *arg)
61 : : {
62 : : /* First read in the file header and check its sanity. */
63 : :
64 : 2 : const size_t initial_bufsize = 256;
65 : 2 : unsigned char *buffer = malloc (initial_bufsize);
66 [ - + ]: 2 : if (buffer == NULL)
67 : : {
68 : : no_memory:
69 : 0 : __libdwfl_seterrno (DWFL_E_NOMEM);
70 : : return NULL;
71 : : }
72 : :
73 : 2 : ssize_t nread = (*read_memory) (arg, buffer, ehdr_vma,
74 : : sizeof (Elf32_Ehdr), initial_bufsize);
75 [ - + ]: 2 : if (nread <= 0)
76 : : {
77 : : read_error:
78 : 0 : free (buffer);
79 [ # # ]: 0 : __libdwfl_seterrno (nread < 0 ? DWFL_E_ERRNO : DWFL_E_TRUNCATED);
80 : : return NULL;
81 : : }
82 : :
83 [ - + ]: 2 : if (memcmp (buffer, ELFMAG, SELFMAG) != 0)
84 : : {
85 : : bad_elf:
86 : 0 : __libdwfl_seterrno (DWFL_E_BADELF);
87 : : return NULL;
88 : : }
89 : :
90 : : /* Extract the information we need from the file header. */
91 : :
92 : : union
93 : : {
94 : : Elf32_Ehdr e32;
95 : : Elf64_Ehdr e64;
96 : : } ehdr;
97 : 2 : Elf_Data xlatefrom =
98 : : {
99 : : .d_type = ELF_T_EHDR,
100 : : .d_buf = buffer,
101 : : .d_version = EV_CURRENT,
102 : : };
103 : 2 : Elf_Data xlateto =
104 : : {
105 : : .d_type = ELF_T_EHDR,
106 : : .d_buf = &ehdr,
107 : : .d_size = sizeof ehdr,
108 : : .d_version = EV_CURRENT,
109 : : };
110 : :
111 : : GElf_Off phoff;
112 : : uint_fast16_t phnum;
113 : : uint_fast16_t phentsize;
114 : : GElf_Off shdrs_end;
115 : :
116 [ - - + ]: 2 : switch (buffer[EI_CLASS])
117 : : {
118 : : case ELFCLASS32:
119 : 0 : xlatefrom.d_size = sizeof (Elf32_Ehdr);
120 [ # # ]: 0 : if (elf32_xlatetom (&xlateto, &xlatefrom, buffer[EI_DATA]) == NULL)
121 : : {
122 : : libelf_error:
123 : 0 : __libdwfl_seterrno (DWFL_E_LIBELF);
124 : : return NULL;
125 : : }
126 : 0 : phoff = ehdr.e32.e_phoff;
127 : 0 : phnum = ehdr.e32.e_phnum;
128 : 0 : phentsize = ehdr.e32.e_phentsize;
129 [ # # ]: 0 : if (phentsize != sizeof (Elf32_Phdr) || phnum == 0)
130 : : goto bad_elf;
131 : 0 : shdrs_end = ehdr.e32.e_shoff + ehdr.e32.e_shnum * ehdr.e32.e_shentsize;
132 : 0 : break;
133 : :
134 : : case ELFCLASS64:
135 : 2 : xlatefrom.d_size = sizeof (Elf64_Ehdr);
136 [ - + ]: 2 : if (elf64_xlatetom (&xlateto, &xlatefrom, buffer[EI_DATA]) == NULL)
137 : : goto libelf_error;
138 : 2 : phoff = ehdr.e64.e_phoff;
139 : 2 : phnum = ehdr.e64.e_phnum;
140 : 2 : phentsize = ehdr.e64.e_phentsize;
141 [ - + ]: 2 : if (phentsize != sizeof (Elf64_Phdr) || phnum == 0)
142 : : goto bad_elf;
143 : 2 : shdrs_end = ehdr.e64.e_shoff + ehdr.e64.e_shnum * ehdr.e64.e_shentsize;
144 : 2 : break;
145 : :
146 : : default:
147 : : goto bad_elf;
148 : : }
149 : :
150 : :
151 : : /* The file header tells where to find the program headers.
152 : : These are what we use to actually choose what to read. */
153 : :
154 : 2 : xlatefrom.d_type = xlateto.d_type = ELF_T_PHDR;
155 : 2 : xlatefrom.d_size = phnum * phentsize;
156 : :
157 [ - + ]: 2 : if ((size_t) nread >= phoff + phnum * phentsize)
158 : : /* We already have all the phdrs from the initial read. */
159 : 0 : xlatefrom.d_buf = buffer + phoff;
160 : : else
161 : : {
162 : : /* Read in the program headers. */
163 : :
164 [ - + ]: 2 : if (initial_bufsize < phnum * phentsize)
165 : : {
166 : 0 : unsigned char *newbuf = realloc (buffer, phnum * phentsize);
167 [ # # ]: 0 : if (newbuf == NULL)
168 : : {
169 : 0 : free (buffer);
170 : 0 : goto no_memory;
171 : : }
172 : 0 : buffer = newbuf;
173 : : }
174 : 2 : nread = (*read_memory) (arg, buffer, ehdr_vma + phoff,
175 : : phnum * phentsize, phnum * phentsize);
176 [ - + ]: 2 : if (nread <= 0)
177 : : goto read_error;
178 : :
179 : 2 : xlatefrom.d_buf = buffer;
180 : : }
181 : :
182 : 4 : union
183 : : {
184 : 2 : Elf32_Phdr p32[phnum];
185 : 2 : Elf64_Phdr p64[phnum];
186 : 2 : } phdrs;
187 : :
188 : 2 : xlateto.d_buf = &phdrs;
189 : 2 : xlateto.d_size = sizeof phdrs;
190 : :
191 : : /* Scan for PT_LOAD segments to find the total size of the file image. */
192 : 2 : size_t contents_size = 0;
193 : 2 : GElf_Off segments_end = 0;
194 : 2 : GElf_Addr loadbase = ehdr_vma;
195 : 2 : bool found_base = false;
196 [ - + - ]: 2 : switch (ehdr.e32.e_ident[EI_CLASS])
197 : : {
198 : 2 : inline void handle_segment (GElf_Addr vaddr, GElf_Off offset,
199 : : GElf_Xword filesz, GElf_Xword align)
200 : : {
201 : 2 : GElf_Off segment_end = ((offset + filesz + align - 1) & -align);
202 : :
203 [ + - ]: 2 : if (segment_end > (GElf_Off) contents_size)
204 : 2 : contents_size = segment_end;
205 : :
206 [ + - ][ + - ]: 2 : if (!found_base && (offset & -align) == 0)
207 : : {
208 : 2 : loadbase = ehdr_vma - (vaddr & -align);
209 : 2 : found_base = true;
210 : : }
211 : :
212 : 2 : segments_end = offset + filesz;
213 : 2 : }
214 : :
215 : : case ELFCLASS32:
216 [ # # ]: 0 : if (elf32_xlatetom (&xlateto, &xlatefrom,
217 : 0 : ehdr.e32.e_ident[EI_DATA]) == NULL)
218 : : goto libelf_error;
219 [ # # ]: 0 : for (uint_fast16_t i = 0; i < phnum; ++i)
220 [ # # ]: 0 : if (phdrs.p32[i].p_type == PT_LOAD)
221 : 0 : handle_segment (phdrs.p32[i].p_vaddr, phdrs.p32[i].p_offset,
222 : 0 : phdrs.p32[i].p_filesz, phdrs.p32[i].p_align);
223 : : break;
224 : :
225 : : case ELFCLASS64:
226 [ + - ]: 2 : if (elf64_xlatetom (&xlateto, &xlatefrom,
227 : 2 : ehdr.e64.e_ident[EI_DATA]) == NULL)
228 : : goto libelf_error;
229 [ + + ]: 10 : for (uint_fast16_t i = 0; i < phnum; ++i)
230 [ + + ]: 8 : if (phdrs.p64[i].p_type == PT_LOAD)
231 : 2 : handle_segment (phdrs.p64[i].p_vaddr, phdrs.p64[i].p_offset,
232 : : phdrs.p64[i].p_filesz, phdrs.p64[i].p_align);
233 : : break;
234 : :
235 : : default:
236 : 0 : abort ();
237 : : break;
238 : : }
239 : :
240 : : /* Trim the last segment so we don't bother with zeros in the last page
241 : : that are off the end of the file. However, if the extra bit in that
242 : : page includes the section headers, keep them. */
243 [ + - ]: 2 : if ((GElf_Off) contents_size > segments_end
244 [ - + ]: 2 : && (GElf_Off) contents_size >= shdrs_end)
245 : : {
246 : 0 : contents_size = segments_end;
247 [ # # ]: 0 : if ((GElf_Off) contents_size < shdrs_end)
248 : 0 : contents_size = shdrs_end;
249 : : }
250 : : else
251 : 2 : contents_size = segments_end;
252 : :
253 : 2 : free (buffer);
254 : :
255 : : /* Now we know the size of the whole image we want read in. */
256 : 2 : buffer = calloc (1, contents_size);
257 [ + - ]: 2 : if (buffer == NULL)
258 : : goto no_memory;
259 : :
260 [ + - - ]: 2 : switch (ehdr.e32.e_ident[EI_CLASS])
261 : : {
262 : 2 : inline bool handle_segment (GElf_Addr vaddr, GElf_Off offset,
263 : : GElf_Xword filesz, GElf_Xword align)
264 : : {
265 : 2 : GElf_Off start = offset & -align;
266 : 2 : GElf_Off end = (offset + filesz + align - 1) & -align;
267 [ + - ]: 2 : if (end > (GElf_Off) contents_size)
268 : 2 : end = contents_size;
269 : 2 : nread = (*read_memory) (arg, buffer + start,
270 : 2 : (loadbase + vaddr) & -align,
271 : : end - start, end - start);
272 : 2 : return nread <= 0;
273 : : }
274 : :
275 : : case ELFCLASS32:
276 [ # # ]: 0 : for (uint_fast16_t i = 0; i < phnum; ++i)
277 [ # # ]: 0 : if (phdrs.p32[i].p_type == PT_LOAD)
278 [ # # ]: 0 : if (handle_segment (phdrs.p32[i].p_vaddr, phdrs.p32[i].p_offset,
279 : 0 : phdrs.p32[i].p_filesz, phdrs.p32[i].p_align))
280 : : goto read_error;
281 : :
282 : : /* If the segments visible in memory didn't include the section
283 : : headers, then clear them from the file header. */
284 [ # # ]: 0 : if (contents_size < shdrs_end)
285 : : {
286 : 0 : ehdr.e32.e_shoff = 0;
287 : 0 : ehdr.e32.e_shnum = 0;
288 : 0 : ehdr.e32.e_shstrndx = 0;
289 : : }
290 : :
291 : : /* This will normally have been in the first PT_LOAD segment. But it
292 : : conceivably could be missing, and we might have just changed it. */
293 : 0 : xlatefrom.d_type = xlateto.d_type = ELF_T_EHDR;
294 : 0 : xlatefrom.d_size = xlateto.d_size = sizeof ehdr.e32;
295 : 0 : xlatefrom.d_buf = &ehdr.e32;
296 : 0 : xlateto.d_buf = buffer;
297 [ # # ]: 0 : if (elf32_xlatetof (&xlateto, &xlatefrom,
298 : 0 : ehdr.e32.e_ident[EI_DATA]) == NULL)
299 : : goto libelf_error;
300 : : break;
301 : :
302 : : case ELFCLASS64:
303 [ + + ]: 10 : for (uint_fast16_t i = 0; i < phnum; ++i)
304 [ + + ]: 8 : if (phdrs.p32[i].p_type == PT_LOAD)
305 [ + - ]: 2 : if (handle_segment (phdrs.p64[i].p_vaddr, phdrs.p64[i].p_offset,
306 : : phdrs.p64[i].p_filesz, phdrs.p64[i].p_align))
307 : : goto read_error;
308 : :
309 : : /* If the segments visible in memory didn't include the section
310 : : headers, then clear them from the file header. */
311 [ + - ]: 2 : if (contents_size < shdrs_end)
312 : : {
313 : 2 : ehdr.e64.e_shoff = 0;
314 : 2 : ehdr.e64.e_shnum = 0;
315 : 2 : ehdr.e64.e_shstrndx = 0;
316 : : }
317 : :
318 : : /* This will normally have been in the first PT_LOAD segment. But it
319 : : conceivably could be missing, and we might have just changed it. */
320 : 2 : xlatefrom.d_type = xlateto.d_type = ELF_T_EHDR;
321 : 2 : xlatefrom.d_size = xlateto.d_size = sizeof ehdr.e64;
322 : 2 : xlatefrom.d_buf = &ehdr.e64;
323 : 2 : xlateto.d_buf = buffer;
324 [ + - ]: 2 : if (elf64_xlatetof (&xlateto, &xlatefrom,
325 : 2 : ehdr.e64.e_ident[EI_DATA]) == NULL)
326 : : goto libelf_error;
327 : : break;
328 : :
329 : : default:
330 : 0 : abort ();
331 : : break;
332 : : }
333 : :
334 : : /* Now we have the image. Open libelf on it. */
335 : :
336 : 2 : Elf *elf = elf_memory ((char *) buffer, contents_size);
337 [ - + ]: 2 : if (elf == NULL)
338 : : {
339 : 0 : free (buffer);
340 : : goto libelf_error;
341 : : }
342 : :
343 : 2 : elf->flags |= ELF_F_MALLOCED;
344 [ - + ]: 2 : if (loadbasep != NULL)
345 : 2 : *loadbasep = loadbase;
346 : : return elf;
347 : : }
|