elf-from-memory.c revision d8dcc9c17a866f18b342b3b0594c15d007b8b73b
1/* Reconstruct an ELF file by reading the segments out of remote memory. 2 Copyright (C) 2005, 2006 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 74Elf * 75elf_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 (elf32_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 switch (ehdr.e32.e_ident[EI_CLASS]) 217 { 218 inline void handle_segment (GElf_Addr vaddr, GElf_Off offset, 219 GElf_Xword filesz, GElf_Xword align) 220 { 221 GElf_Off segment_end = ((offset + filesz + align - 1) & -align); 222 223 if (segment_end > (GElf_Off) contents_size) 224 contents_size = segment_end; 225 226 if ((offset & -align) == 0 && loadbase == ehdr_vma) 227 loadbase = ehdr_vma - (vaddr & -align); 228 229 segments_end = offset + filesz; 230 } 231 232 case ELFCLASS32: 233 if (elf32_xlatetom (&xlateto, &xlatefrom, 234 ehdr.e32.e_ident[EI_DATA]) == NULL) 235 goto libelf_error; 236 for (uint_fast16_t i = 0; i < phnum; ++i) 237 if (phdrs.p32[i].p_type == PT_LOAD) 238 handle_segment (phdrs.p32[i].p_vaddr, phdrs.p32[i].p_offset, 239 phdrs.p32[i].p_filesz, phdrs.p32[i].p_align); 240 break; 241 242 case ELFCLASS64: 243 if (elf32_xlatetom (&xlateto, &xlatefrom, 244 ehdr.e32.e_ident[EI_DATA]) == NULL) 245 goto libelf_error; 246 for (uint_fast16_t i = 0; i < phnum; ++i) 247 if (phdrs.p32[i].p_type == PT_LOAD) 248 handle_segment (phdrs.p64[i].p_vaddr, phdrs.p64[i].p_offset, 249 phdrs.p64[i].p_filesz, phdrs.p64[i].p_align); 250 break; 251 252 default: 253 abort (); 254 break; 255 } 256 257 /* Trim the last segment so we don't bother with zeros in the last page 258 that are off the end of the file. However, if the extra bit in that 259 page includes the section headers, keep them. */ 260 if ((GElf_Off) contents_size > segments_end 261 && (GElf_Off) contents_size >= shdrs_end) 262 { 263 contents_size = segments_end; 264 if ((GElf_Off) contents_size < shdrs_end) 265 contents_size = shdrs_end; 266 } 267 else 268 contents_size = segments_end; 269 270 free (buffer); 271 272 /* Now we know the size of the whole image we want read in. */ 273 buffer = calloc (1, contents_size); 274 if (buffer == NULL) 275 goto no_memory; 276 277 switch (ehdr.e32.e_ident[EI_CLASS]) 278 { 279 inline bool handle_segment (GElf_Addr vaddr, GElf_Off offset, 280 GElf_Xword filesz, GElf_Xword align) 281 { 282 GElf_Off start = offset & -align; 283 GElf_Off end = (offset + filesz + align - 1) & -align; 284 if (end > (GElf_Off) contents_size) 285 end = contents_size; 286 nread = (*read_memory) (arg, buffer + start, 287 (loadbase + vaddr) & -align, 288 end - start, end - start); 289 return nread <= 0; 290 } 291 292 case ELFCLASS32: 293 for (uint_fast16_t i = 0; i < phnum; ++i) 294 if (phdrs.p32[i].p_type == PT_LOAD) 295 if (handle_segment (phdrs.p32[i].p_vaddr, phdrs.p32[i].p_offset, 296 phdrs.p32[i].p_filesz, phdrs.p32[i].p_align)) 297 goto read_error; 298 299 /* If the segments visible in memory didn't include the section 300 headers, then clear them from the file header. */ 301 if (contents_size < shdrs_end) 302 { 303 ehdr.e32.e_shoff = 0; 304 ehdr.e32.e_shnum = 0; 305 ehdr.e32.e_shstrndx = 0; 306 } 307 308 /* This will normally have been in the first PT_LOAD segment. But it 309 conceivably could be missing, and we might have just changed it. */ 310 xlatefrom.d_type = xlateto.d_type = ELF_T_EHDR; 311 xlatefrom.d_size = xlateto.d_size = sizeof ehdr.e32; 312 xlatefrom.d_buf = &ehdr.e32; 313 xlateto.d_buf = buffer; 314 if (elf32_xlatetof (&xlateto, &xlatefrom, 315 ehdr.e32.e_ident[EI_DATA]) == NULL) 316 goto libelf_error; 317 break; 318 319 case ELFCLASS64: 320 for (uint_fast16_t i = 0; i < phnum; ++i) 321 if (phdrs.p32[i].p_type == PT_LOAD) 322 if (handle_segment (phdrs.p64[i].p_vaddr, phdrs.p64[i].p_offset, 323 phdrs.p64[i].p_filesz, phdrs.p64[i].p_align)) 324 goto read_error; 325 326 /* If the segments visible in memory didn't include the section 327 headers, then clear them from the file header. */ 328 if (contents_size < shdrs_end) 329 { 330 ehdr.e64.e_shoff = 0; 331 ehdr.e64.e_shnum = 0; 332 ehdr.e64.e_shstrndx = 0; 333 } 334 335 /* This will normally have been in the first PT_LOAD segment. But it 336 conceivably could be missing, and we might have just changed it. */ 337 xlatefrom.d_type = xlateto.d_type = ELF_T_EHDR; 338 xlatefrom.d_size = xlateto.d_size = sizeof ehdr.e64; 339 xlatefrom.d_buf = &ehdr.e64; 340 xlateto.d_buf = buffer; 341 if (elf64_xlatetof (&xlateto, &xlatefrom, 342 ehdr.e64.e_ident[EI_DATA]) == NULL) 343 goto libelf_error; 344 break; 345 346 default: 347 abort (); 348 break; 349 } 350 351 /* Now we have the image. Open libelf on it. */ 352 353 Elf *elf = elf_memory ((char *) buffer, contents_size); 354 if (elf == NULL) 355 { 356 free (buffer); 357 goto libelf_error; 358 } 359 360 elf->flags |= ELF_F_MALLOCED; 361 if (loadbasep != NULL) 362 *loadbasep = loadbase; 363 return elf; 364} 365