1 : /*
2 : * Copyright (c) 2011 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can be
4 : * found in the LICENSE file.
5 : */
6 :
7 : /*
8 : * NaCl helper functions to deal with elf images
9 : */
10 :
11 : #include "native_client/src/include/portability.h"
12 :
13 : #include <stdio.h>
14 :
15 : #include <stdlib.h>
16 : #include <string.h>
17 :
18 : #define NACL_LOG_MODULE_NAME "elf_util"
19 :
20 : #include "native_client/src/include/elf_constants.h"
21 : #include "native_client/src/include/elf.h"
22 : #include "native_client/src/include/nacl_macros.h"
23 : #include "native_client/src/include/nacl_platform.h"
24 :
25 : #include "native_client/src/shared/gio/gio.h"
26 : #include "native_client/src/shared/platform/nacl_log.h"
27 :
28 : #include "native_client/src/trusted/service_runtime/elf_util.h"
29 : #include "native_client/src/trusted/service_runtime/include/bits/mman.h"
30 : #include "native_client/src/trusted/service_runtime/nacl_config.h"
31 : #include "native_client/src/trusted/service_runtime/nacl_syscall_common.h"
32 : #include "native_client/src/trusted/service_runtime/nacl_text.h"
33 : #include "native_client/src/trusted/service_runtime/nacl_valgrind_hooks.h"
34 : #include "native_client/src/trusted/service_runtime/sel_memory.h"
35 :
36 : /* private */
37 : struct NaClElfImage {
38 : Elf_Ehdr ehdr;
39 : Elf_Phdr phdrs[NACL_MAX_PROGRAM_HEADERS];
40 : int loadable[NACL_MAX_PROGRAM_HEADERS];
41 : };
42 :
43 :
44 : enum NaClPhdrCheckAction {
45 : PCA_NONE,
46 : PCA_TEXT_CHECK,
47 : PCA_RODATA,
48 : PCA_DATA,
49 : PCA_IGNORE /* ignore this segment. */
50 : };
51 :
52 :
53 : struct NaClPhdrChecks {
54 : Elf_Word p_type;
55 : Elf_Word p_flags; /* rwx */
56 : enum NaClPhdrCheckAction action;
57 : int required; /* only for text for now */
58 : Elf_Addr p_vaddr; /* if non-zero, vaddr must be this */
59 : };
60 :
61 : /*
62 : * Other than empty segments, these are the only ones that are allowed.
63 : */
64 : static const struct NaClPhdrChecks nacl_phdr_check_data[] = {
65 : /* phdr */
66 : { PT_PHDR, PF_R, PCA_IGNORE, 0, 0, },
67 : /* text */
68 : { PT_LOAD, PF_R|PF_X, PCA_TEXT_CHECK, 1, NACL_TRAMPOLINE_END, },
69 : /* rodata */
70 : { PT_LOAD, PF_R, PCA_RODATA, 0, 0, },
71 : /* data/bss */
72 : { PT_LOAD, PF_R|PF_W, PCA_DATA, 0, 0, },
73 : /* tls */
74 : { PT_TLS, PF_R, PCA_IGNORE, 0, 0},
75 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_arm
76 : /* arm exception handling unwind info (for c++)*/
77 : /* TODO(robertm): for some reason this does NOT end up in ro maybe because
78 : * it is relocatable. Try hacking the linker script to move it.
79 : */
80 : { PT_ARM_EXIDX, PF_R, PCA_IGNORE, 0, 0, },
81 : #endif
82 : /*
83 : * allow optional GNU stack permission marker, but require that the
84 : * stack is non-executable.
85 : */
86 : { PT_GNU_STACK, PF_R|PF_W, PCA_NONE, 0, 0, },
87 : /* ignored segments */
88 : { PT_DYNAMIC, PF_R, PCA_IGNORE, 0, 0},
89 : { PT_INTERP, PF_R, PCA_IGNORE, 0, 0},
90 : { PT_NOTE, PF_R, PCA_IGNORE, 0, 0},
91 : { PT_GNU_EH_FRAME, PF_R, PCA_IGNORE, 0, 0},
92 : { PT_GNU_RELRO, PF_R, PCA_IGNORE, 0, 0},
93 : { PT_NULL, PF_R, PCA_IGNORE, 0, 0},
94 : };
95 :
96 :
97 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86
98 : # if NACL_BUILD_SUBARCH == 32
99 : # define EM_EXPECTED_BY_NACL EM_386
100 : # elif NACL_BUILD_SUBARCH == 64
101 : # define EM_EXPECTED_BY_NACL EM_X86_64
102 : # else
103 : # error "No NACL_BUILD_SUBARCH for x86 -- are we on x86-128?"
104 : # endif
105 : #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_arm
106 : # define EM_EXPECTED_BY_NACL EM_ARM
107 : #else
108 : # error "Unknown platform!"
109 : #endif
110 :
111 :
112 11 : static void NaClDumpElfHeader(int loglevel, Elf_Ehdr *elf_hdr) {
113 :
114 : #define DUMP(m,f) do { NaClLog(loglevel, \
115 : #m " = %" f "\n", \
116 : elf_hdr->m); } while (0)
117 :
118 11 : NaClLog(loglevel, "=================================================\n");
119 11 : NaClLog(loglevel, "Elf header\n");
120 11 : NaClLog(loglevel, "==================================================\n");
121 :
122 11 : DUMP(e_ident+1, ".3s");
123 11 : DUMP(e_type, "#x");
124 11 : DUMP(e_machine, "#x");
125 11 : DUMP(e_version, "#x");
126 11 : DUMP(e_entry, "#"NACL_PRIxElf_Addr);
127 11 : DUMP(e_phoff, "#"NACL_PRIxElf_Off);
128 11 : DUMP(e_shoff, "#"NACL_PRIxElf_Off);
129 11 : DUMP(e_flags, "#"NACL_PRIxElf_Word);
130 11 : DUMP(e_ehsize, "#"NACL_PRIxElf_Half);
131 11 : DUMP(e_phentsize, "#"NACL_PRIxElf_Half);
132 11 : DUMP(e_phnum, "#"NACL_PRIxElf_Half);
133 11 : DUMP(e_shentsize, "#"NACL_PRIxElf_Half);
134 11 : DUMP(e_shnum, "#"NACL_PRIxElf_Half);
135 11 : DUMP(e_shstrndx, "#"NACL_PRIxElf_Half);
136 : #undef DUMP
137 11 : NaClLog(loglevel, "sizeof(Elf32_Ehdr) = 0x%x\n", (int) sizeof *elf_hdr);
138 11 : }
139 :
140 :
141 : static void NaClDumpElfProgramHeader(int loglevel,
142 43 : Elf_Phdr *phdr) {
143 : #define DUMP(mem, f) do { \
144 : NaClLog(loglevel, "%s: %" f "\n", #mem, phdr->mem); \
145 : } while (0)
146 :
147 43 : DUMP(p_type, NACL_PRIxElf_Word);
148 43 : DUMP(p_offset, NACL_PRIxElf_Off);
149 43 : DUMP(p_vaddr, NACL_PRIxElf_Addr);
150 43 : DUMP(p_paddr, NACL_PRIxElf_Addr);
151 43 : DUMP(p_filesz, NACL_PRIxElf_Xword);
152 43 : DUMP(p_memsz, NACL_PRIxElf_Xword);
153 43 : DUMP(p_flags, NACL_PRIxElf_Word);
154 43 : NaClLog(2, " (%s %s %s)\n",
155 : (phdr->p_flags & PF_R) ? "PF_R" : "",
156 : (phdr->p_flags & PF_W) ? "PF_W" : "",
157 : (phdr->p_flags & PF_X) ? "PF_X" : "");
158 43 : DUMP(p_align, NACL_PRIxElf_Xword);
159 : #undef DUMP
160 43 : NaClLog(loglevel, "\n");
161 43 : }
162 :
163 :
164 11 : NaClErrorCode NaClElfImageValidateElfHeader(struct NaClElfImage *image) {
165 11 : const Elf_Ehdr *hdr = &image->ehdr;
166 :
167 11 : if (memcmp(hdr->e_ident, ELFMAG, SELFMAG)) {
168 0 : NaClLog(LOG_ERROR, "bad elf magic\n");
169 0 : return LOAD_BAD_ELF_MAGIC;
170 : }
171 :
172 11 : if (ELFCLASS32 != hdr->e_ident[EI_CLASS]) {
173 0 : NaClLog(LOG_ERROR, "bad elf class\n");
174 0 : return LOAD_NOT_32_BIT;
175 : }
176 :
177 11 : if (ET_EXEC != hdr->e_type) {
178 0 : NaClLog(LOG_ERROR, "non executable\n");
179 0 : return LOAD_NOT_EXEC;
180 : }
181 :
182 11 : if (EM_EXPECTED_BY_NACL != hdr->e_machine) {
183 0 : NaClLog(LOG_ERROR, "bad machine: %"NACL_PRIxElf_Half"\n", hdr->e_machine);
184 0 : return LOAD_BAD_MACHINE;
185 : }
186 :
187 11 : if (EV_CURRENT != hdr->e_version) {
188 0 : NaClLog(LOG_ERROR, "bad elf version: %"NACL_PRIxElf_Word"\n",
189 : hdr->e_version);
190 0 : return LOAD_BAD_ELF_VERS;
191 : }
192 :
193 11 : return LOAD_OK;
194 : }
195 :
196 : /* TODO(robertm): decouple validation from computation of
197 : static_text_end and max_vaddr */
198 : NaClErrorCode NaClElfImageValidateProgramHeaders(
199 : struct NaClElfImage *image,
200 : uint8_t addr_bits,
201 : uintptr_t *static_text_end,
202 : uintptr_t *rodata_start,
203 : uintptr_t *rodata_end,
204 : uintptr_t *data_start,
205 : uintptr_t *data_end,
206 11 : uintptr_t *max_vaddr) {
207 : /*
208 : * Scan phdrs and do sanity checks in-line. Verify that the load
209 : * address is NACL_TRAMPOLINE_END, that we have a single text
210 : * segment. Data and TLS segments are not required, though it is
211 : * hard to avoid with standard tools, but in any case there should
212 : * be at most one each. Ensure that no segment's vaddr is outside
213 : * of the address space. Ensure that PT_GNU_STACK is present, and
214 : * that x is off.
215 : */
216 11 : const Elf_Ehdr *hdr = &image->ehdr;
217 11 : int seen_seg[NACL_ARRAY_SIZE(nacl_phdr_check_data)];
218 :
219 : int segnum;
220 : const Elf_Phdr *php;
221 : size_t j;
222 :
223 11 : *max_vaddr = NACL_TRAMPOLINE_END;
224 :
225 : /*
226 : * nacl_phdr_check_data is small, so O(|check_data| * nap->elf_hdr.e_phum)
227 : * is okay.
228 : */
229 11 : memset(seen_seg, 0, sizeof seen_seg);
230 45 : for (segnum = 0; segnum < hdr->e_phnum; ++segnum) {
231 37 : php = &image->phdrs[segnum];
232 37 : NaClLog(3, "Looking at segment %d, type 0x%x, p_flags 0x%x\n",
233 : segnum, php->p_type, php->p_flags);
234 37 : if (0 == php->p_memsz) {
235 : /*
236 : * We will not load this segment.
237 : */
238 0 : NaClLog(3, "Ignoring empty segment\n");
239 0 : continue;
240 : }
241 :
242 86 : for (j = 0; j < NACL_ARRAY_SIZE(nacl_phdr_check_data); ++j) {
243 86 : if (php->p_type == nacl_phdr_check_data[j].p_type
244 : && php->p_flags == nacl_phdr_check_data[j].p_flags)
245 37 : break;
246 : }
247 37 : if (j == NACL_ARRAY_SIZE(nacl_phdr_check_data)) {
248 : /* segment not in nacl_phdr_check_data */
249 0 : NaClLog(2,
250 : "Segment %d is of unexpected type 0x%x, flag 0x%x\n",
251 : segnum,
252 : php->p_type,
253 : php->p_flags);
254 0 : return LOAD_BAD_SEGMENT;
255 : }
256 :
257 37 : NaClLog(2, "Matched nacl_phdr_check_data[%"NACL_PRIdS"]\n", j);
258 37 : if (seen_seg[j]) {
259 0 : NaClLog(2, "Segment %d is a type that has been seen\n", segnum);
260 0 : return LOAD_DUP_SEGMENT;
261 : }
262 37 : seen_seg[j] = 1;
263 :
264 37 : if (PCA_IGNORE == nacl_phdr_check_data[j].action) {
265 11 : NaClLog(3, "Ignoring\n");
266 11 : continue;
267 : }
268 :
269 : /*
270 : * We will load this segment later. Do the sanity checks.
271 : */
272 26 : if (0 != nacl_phdr_check_data[j].p_vaddr
273 : && (nacl_phdr_check_data[j].p_vaddr != php->p_vaddr)) {
274 1 : NaClLog(2,
275 : ("Segment %d: bad virtual address: 0x%08"
276 : NACL_PRIxElf_Addr","
277 : " expected 0x%08"NACL_PRIxElf_Addr"\n"),
278 : segnum,
279 : php->p_vaddr,
280 : nacl_phdr_check_data[j].p_vaddr);
281 1 : return LOAD_SEGMENT_BAD_LOC;
282 : }
283 25 : if (php->p_vaddr < NACL_TRAMPOLINE_END) {
284 0 : NaClLog(2,
285 : ("Segment %d: virtual address (0x%08"NACL_PRIxElf_Addr
286 : ") too low\n"),
287 : segnum,
288 : php->p_vaddr);
289 0 : return LOAD_SEGMENT_OUTSIDE_ADDRSPACE;
290 : }
291 25 : if (php->p_vaddr >= ((uint64_t) 1U << addr_bits) ||
292 : ((uint64_t) 1U << addr_bits) - php->p_vaddr < php->p_memsz) {
293 2 : if (php->p_vaddr + php->p_memsz < php->p_vaddr) {
294 0 : NaClLog(2,
295 : "Segment %d: p_memsz caused integer overflow\n",
296 : segnum);
297 : } else {
298 2 : NaClLog(2,
299 : "Segment %d: too large, ends at 0x%08"NACL_PRIxElf_Addr"\n",
300 : segnum,
301 : php->p_vaddr + php->p_memsz);
302 : }
303 2 : return LOAD_SEGMENT_OUTSIDE_ADDRSPACE;
304 : }
305 23 : if (php->p_filesz > php->p_memsz) {
306 0 : NaClLog(2,
307 : ("Segment %d: file size 0x%08"NACL_PRIxElf_Xword" larger"
308 : " than memory size 0x%08"NACL_PRIxElf_Xword"\n"),
309 : segnum,
310 : php->p_filesz,
311 : php->p_memsz);
312 0 : return LOAD_SEGMENT_BAD_PARAM;
313 : }
314 :
315 23 : image->loadable[segnum] = 1;
316 : /* record our decision that we will load this segment */
317 :
318 : /*
319 : * NACL_TRAMPOLINE_END <= p_vaddr
320 : * <= p_vaddr + p_memsz
321 : * < ((uintptr_t) 1U << nap->addr_bits)
322 : */
323 23 : if (*max_vaddr < php->p_vaddr + php->p_memsz) {
324 23 : *max_vaddr = php->p_vaddr + php->p_memsz;
325 : }
326 :
327 23 : switch (nacl_phdr_check_data[j].action) {
328 : case PCA_NONE:
329 0 : break;
330 : case PCA_TEXT_CHECK:
331 8 : if (0 == php->p_memsz) {
332 0 : return LOAD_BAD_ELF_TEXT;
333 : }
334 8 : *static_text_end = NACL_TRAMPOLINE_END + php->p_filesz;
335 8 : break;
336 : case PCA_RODATA:
337 7 : *rodata_start = php->p_vaddr;
338 7 : *rodata_end = php->p_vaddr + php->p_memsz;
339 7 : break;
340 : case PCA_DATA:
341 8 : *data_start = php->p_vaddr;
342 8 : *data_end = php->p_vaddr + php->p_memsz;
343 : break;
344 : case PCA_IGNORE:
345 : break;
346 : }
347 : }
348 104 : for (j = 0; j < NACL_ARRAY_SIZE(nacl_phdr_check_data); ++j) {
349 96 : if (nacl_phdr_check_data[j].required && !seen_seg[j]) {
350 0 : return LOAD_REQUIRED_SEG_MISSING;
351 : }
352 : }
353 :
354 : /*
355 : * Memory allocation will use NaClRoundPage(nap->break_addr), but
356 : * the system notion of break is always an exact address. Even
357 : * though we must allocate and make accessible multiples of pages,
358 : * the linux-style brk system call (which returns current break on
359 : * failure) permits an arbitrarily aligned address as argument.
360 : */
361 :
362 8 : return LOAD_OK;
363 : }
364 :
365 :
366 : struct NaClElfImage *NaClElfImageNew(struct Gio *gp,
367 11 : NaClErrorCode *err_code) {
368 : struct NaClElfImage *result;
369 : struct NaClElfImage image;
370 : union {
371 : Elf32_Ehdr ehdr32;
372 : #if NACL_TARGET_SUBARCH == 64
373 : Elf64_Ehdr ehdr64;
374 : #endif
375 : } ehdr;
376 : int cur_ph;
377 :
378 11 : memset(image.loadable, 0, sizeof image.loadable);
379 11 : if (-1 == (*gp->vtbl->Seek)(gp, 0, 0)) {
380 0 : NaClLog(2, "could not seek to beginning of Gio object containing nexe\n");
381 0 : if (NULL != err_code) {
382 0 : *err_code = LOAD_READ_ERROR;
383 : }
384 0 : return 0;
385 : }
386 :
387 : /*
388 : * We read the larger size of an ELFCLASS64 header even if it turns out
389 : * we're reading an ELFCLASS32 file. No usable ELFCLASS32 binary could
390 : * be so small that it's not larger than Elf64_Ehdr anyway.
391 : */
392 11 : if ((*gp->vtbl->Read)(gp,
393 : &ehdr,
394 : sizeof ehdr)
395 : != sizeof ehdr) {
396 0 : if (NULL != err_code) {
397 0 : *err_code = LOAD_READ_ERROR;
398 : }
399 0 : NaClLog(2, "could not load elf headers\n");
400 0 : return 0;
401 : }
402 :
403 : #if NACL_TARGET_SUBARCH == 64
404 : if (ELFCLASS64 == ehdr.ehdr64.e_ident[EI_CLASS]) {
405 : /*
406 : * Convert ELFCLASS64 format to ELFCLASS32 format.
407 : * The initial four fields are the same in both classes.
408 : */
409 : memcpy(image.ehdr.e_ident, ehdr.ehdr64.e_ident, EI_NIDENT);
410 : image.ehdr.e_ident[EI_CLASS] = ELFCLASS32;
411 : image.ehdr.e_type = ehdr.ehdr64.e_type;
412 : image.ehdr.e_machine = ehdr.ehdr64.e_machine;
413 : image.ehdr.e_version = ehdr.ehdr64.e_version;
414 : if (ehdr.ehdr64.e_entry > 0xffffffffU ||
415 : ehdr.ehdr64.e_phoff > 0xffffffffU ||
416 : ehdr.ehdr64.e_shoff > 0xffffffffU) {
417 : if (NULL != err_code) {
418 : *err_code = LOAD_EHDR_OVERFLOW;
419 : }
420 : NaClLog(2, "ELFCLASS64 file header fields overflow 32 bits\n");
421 : return 0;
422 : }
423 : image.ehdr.e_entry = (Elf32_Addr) ehdr.ehdr64.e_entry;
424 : image.ehdr.e_phoff = (Elf32_Off) ehdr.ehdr64.e_phoff;
425 : image.ehdr.e_shoff = (Elf32_Off) ehdr.ehdr64.e_shoff;
426 : image.ehdr.e_flags = ehdr.ehdr64.e_flags;
427 : if (ehdr.ehdr64.e_ehsize != sizeof(ehdr.ehdr64)) {
428 : if (NULL != err_code) {
429 : *err_code = LOAD_BAD_EHSIZE;
430 : }
431 : NaClLog(2, "ELFCLASS64 file e_ehsize != %d\n", (int) sizeof(ehdr.ehdr64));
432 : return 0;
433 : }
434 : image.ehdr.e_ehsize = sizeof(image.ehdr);
435 : image.ehdr.e_phentsize = sizeof(image.phdrs[0]);
436 : image.ehdr.e_phnum = ehdr.ehdr64.e_phnum;
437 : image.ehdr.e_shentsize = ehdr.ehdr64.e_shentsize;
438 : image.ehdr.e_shnum = ehdr.ehdr64.e_shnum;
439 : image.ehdr.e_shstrndx = ehdr.ehdr64.e_shstrndx;
440 : } else
441 : #endif
442 : {
443 11 : image.ehdr = ehdr.ehdr32;
444 : }
445 :
446 11 : NaClDumpElfHeader(2, &image.ehdr);
447 :
448 : /* read program headers */
449 11 : if (image.ehdr.e_phnum > NACL_MAX_PROGRAM_HEADERS) {
450 0 : if (NULL != err_code)
451 0 : *err_code = LOAD_TOO_MANY_PROG_HDRS;
452 0 : NaClLog(2, "too many prog headers\n");
453 0 : return 0;
454 : }
455 :
456 11 : if ((*gp->vtbl->Seek)(gp,
457 : (off_t) image.ehdr.e_phoff,
458 : SEEK_SET) == (off_t) -1) {
459 0 : if (NULL != err_code) {
460 0 : *err_code = LOAD_READ_ERROR;
461 : }
462 0 : NaClLog(2, "cannot seek tp prog headers\n");
463 0 : return 0;
464 : }
465 :
466 : #if NACL_TARGET_SUBARCH == 64
467 : if (ELFCLASS64 == ehdr.ehdr64.e_ident[EI_CLASS]) {
468 : /*
469 : * We'll load the 64-bit phdrs and convert them to 32-bit format.
470 : */
471 : Elf64_Phdr phdr64[NACL_MAX_PROGRAM_HEADERS];
472 :
473 : if (ehdr.ehdr64.e_phentsize != sizeof(Elf64_Phdr)) {
474 : if (NULL != err_code) {
475 : *err_code = LOAD_BAD_PHENTSIZE;
476 : }
477 : NaClLog(2, "bad prog headers size\n");
478 : NaClLog(2, " ehdr64.e_phentsize = 0x%"NACL_PRIxElf_Half"\n",
479 : ehdr.ehdr64.e_phentsize);
480 : NaClLog(2, " sizeof(Elf64_Phdr) = 0x%"NACL_PRIxS"\n",
481 : sizeof(Elf64_Phdr));
482 : return 0;
483 : }
484 :
485 : /*
486 : * We know the multiplication won't overflow since we rejected
487 : * e_phnum values larger than the small constant NACL_MAX_PROGRAM_HEADERS.
488 : */
489 : if ((size_t) (*gp->vtbl->Read)(gp,
490 : &phdr64[0],
491 : image.ehdr.e_phnum * sizeof phdr64[0])
492 : != (image.ehdr.e_phnum * sizeof phdr64[0])) {
493 : if (NULL != err_code) {
494 : *err_code = LOAD_READ_ERROR;
495 : }
496 : NaClLog(2, "cannot load tp prog headers\n");
497 : return 0;
498 : }
499 :
500 : for (cur_ph = 0; cur_ph < image.ehdr.e_phnum; ++cur_ph) {
501 : if (phdr64[cur_ph].p_offset > 0xffffffffU ||
502 : phdr64[cur_ph].p_vaddr > 0xffffffffU ||
503 : phdr64[cur_ph].p_paddr > 0xffffffffU ||
504 : phdr64[cur_ph].p_filesz > 0xffffffffU ||
505 : phdr64[cur_ph].p_memsz > 0xffffffffU ||
506 : phdr64[cur_ph].p_align > 0xffffffffU) {
507 : if (NULL != err_code) {
508 : *err_code = LOAD_PHDR_OVERFLOW;
509 : }
510 : NaClLog(2, "ELFCLASS64 program header fields overflow 32 bits\n");
511 : return 0;
512 : }
513 : image.phdrs[cur_ph].p_type = phdr64[cur_ph].p_type;
514 : image.phdrs[cur_ph].p_offset = (Elf32_Off) phdr64[cur_ph].p_offset;
515 : image.phdrs[cur_ph].p_vaddr = (Elf32_Addr) phdr64[cur_ph].p_vaddr;
516 : image.phdrs[cur_ph].p_paddr = (Elf32_Addr) phdr64[cur_ph].p_paddr;
517 : image.phdrs[cur_ph].p_filesz = (Elf32_Word) phdr64[cur_ph].p_filesz;
518 : image.phdrs[cur_ph].p_memsz = (Elf32_Word) phdr64[cur_ph].p_memsz;
519 : image.phdrs[cur_ph].p_flags = phdr64[cur_ph].p_flags;
520 : image.phdrs[cur_ph].p_align = (Elf32_Word) phdr64[cur_ph].p_align;
521 : }
522 : } else
523 : #endif
524 : {
525 11 : if (image.ehdr.e_phentsize != sizeof image.phdrs[0]) {
526 0 : if (NULL != err_code) {
527 0 : *err_code = LOAD_BAD_PHENTSIZE;
528 : }
529 0 : NaClLog(2, "bad prog headers size\n");
530 0 : NaClLog(2, " image.ehdr.e_phentsize = 0x%"NACL_PRIxElf_Half"\n",
531 : image.ehdr.e_phentsize);
532 0 : NaClLog(2, " sizeof image.phdrs[0] = 0x%"NACL_PRIxS"\n",
533 : sizeof image.phdrs[0]);
534 0 : return 0;
535 : }
536 :
537 11 : if ((size_t) (*gp->vtbl->Read)(gp,
538 : &image.phdrs[0],
539 : image.ehdr.e_phnum * sizeof image.phdrs[0])
540 : != (image.ehdr.e_phnum * sizeof image.phdrs[0])) {
541 0 : if (NULL != err_code) {
542 0 : *err_code = LOAD_READ_ERROR;
543 : }
544 0 : NaClLog(2, "cannot load tp prog headers\n");
545 0 : return 0;
546 : }
547 : }
548 :
549 11 : NaClLog(2, "=================================================\n");
550 11 : NaClLog(2, "Elf Program headers\n");
551 11 : NaClLog(2, "==================================================\n");
552 54 : for (cur_ph = 0; cur_ph < image.ehdr.e_phnum; ++cur_ph) {
553 43 : NaClDumpElfProgramHeader(2, &image.phdrs[cur_ph]);
554 : }
555 :
556 : /* we delay allocating till the end to avoid cleanup code */
557 11 : result = malloc(sizeof image);
558 11 : if (result == 0) {
559 0 : if (NULL != err_code) {
560 0 : *err_code = LOAD_NO_MEMORY;
561 : }
562 0 : NaClLog(LOG_FATAL, "no enough memory for image meta data\n");
563 0 : return 0;
564 : }
565 11 : memcpy(result, &image, sizeof image);
566 11 : return result;
567 : }
568 :
569 :
570 : NaClErrorCode NaClElfImageLoad(struct NaClElfImage *image,
571 : struct Gio *gp,
572 : uint8_t addr_bits,
573 3 : uintptr_t mem_start) {
574 : int segnum;
575 : uintptr_t paddr;
576 : uintptr_t end_vaddr;
577 :
578 15 : for (segnum = 0; segnum < image->ehdr.e_phnum; ++segnum) {
579 12 : const Elf_Phdr *php = &image->phdrs[segnum];
580 :
581 : /* did we decide that we will load this segment earlier? */
582 12 : if (!image->loadable[segnum]) {
583 3 : continue;
584 : }
585 :
586 9 : NaClLog(2, "loading segment %d\n", segnum);
587 :
588 9 : if (0 == php->p_filesz) {
589 0 : NaClLog(4, "zero-sized segment. ignoring...\n");
590 0 : continue;
591 : }
592 :
593 9 : end_vaddr = php->p_vaddr + php->p_filesz;
594 : /* integer overflow? */
595 9 : if (end_vaddr < php->p_vaddr) {
596 0 : NaClLog(LOG_FATAL, "parameter error should have been detected already\n");
597 : }
598 : /*
599 : * is the end virtual address within the NaCl application's
600 : * address space? if it is, it implies that the start virtual
601 : * address is also.
602 : */
603 9 : if (end_vaddr >= ((uintptr_t) 1U << addr_bits)) {
604 0 : NaClLog(LOG_FATAL, "parameter error should have been detected already\n");
605 : }
606 :
607 9 : paddr = mem_start + php->p_vaddr;
608 :
609 9 : NaClLog(4,
610 : "Seek to position %"NACL_PRIdElf_Off" (0x%"NACL_PRIxElf_Off").\n",
611 : php->p_offset,
612 : php->p_offset);
613 :
614 : /*
615 : * NB: php->p_offset may not be a valid off_t on 64-bit systems, but
616 : * in that case Seek() will error out.
617 : */
618 9 : if ((*gp->vtbl->Seek)(gp, (off_t) php->p_offset, SEEK_SET) == (off_t) -1) {
619 0 : NaClLog(LOG_ERROR, "seek failure segment %d", segnum);
620 0 : return LOAD_SEGMENT_BAD_PARAM;
621 : }
622 9 : NaClLog(4,
623 : "Reading %"NACL_PRIdElf_Xword" (0x%"NACL_PRIxElf_Xword") bytes to"
624 : " address 0x%"NACL_PRIxPTR"\n",
625 : php->p_filesz,
626 : php->p_filesz,
627 : paddr);
628 :
629 : /*
630 : * Tell valgrind that this memory is accessible and undefined. For more
631 : * details see
632 : * http://code.google.com/p/nativeclient/wiki/ValgrindMemcheck#Implementation_details
633 : */
634 : NACL_MAKE_MEM_UNDEFINED((void *) paddr, php->p_filesz);
635 :
636 9 : if ((Elf_Word) (*gp->vtbl->Read)(gp, (void *) paddr, php->p_filesz)
637 : != php->p_filesz) {
638 0 : NaClLog(LOG_ERROR, "load failure segment %d", segnum);
639 0 : return LOAD_SEGMENT_BAD_PARAM;
640 : }
641 : /* region from p_filesz to p_memsz should already be zero filled */
642 :
643 : /* Tell Valgrind that we've mapped a segment of nacl_file. */
644 9 : NaClFileMappingForValgrind(paddr, php->p_filesz, php->p_offset);
645 : }
646 :
647 3 : return LOAD_OK;
648 : }
649 :
650 :
651 : NaClErrorCode NaClElfImageLoadDynamically(struct NaClElfImage *image,
652 : struct NaClApp *nap,
653 0 : struct Gio *gfile) {
654 : int segnum;
655 0 : for (segnum = 0; segnum < image->ehdr.e_phnum; ++segnum) {
656 0 : const Elf_Phdr *php = &image->phdrs[segnum];
657 : int32_t result;
658 :
659 : /*
660 : * We check for PT_LOAD directly rather than using the "loadable"
661 : * array because we are not using NaClElfImageValidateProgramHeaders()
662 : * to fill out the "loadable" array for this ELF object. This ELF
663 : * object does not have to fit such strict constraints (such as
664 : * having code at 0x20000), and safety checks are applied by
665 : * NaClTextDyncodeCreate() and NaClCommonSysMmapIntern().
666 : */
667 0 : if (PT_LOAD != php->p_type) {
668 0 : continue;
669 : }
670 :
671 : /*
672 : * Ideally, Gio would have a Pread() method which we would use
673 : * instead of Seek(). In practice, though, there is no
674 : * Seek()/Read() race condition here because both
675 : * GioMemoryFileSnapshot and NaClGioShm use a seek position that
676 : * is local and not shared between processes.
677 : */
678 0 : if ((*gfile->vtbl->Seek)(gfile, (off_t) php->p_offset,
679 : SEEK_SET) == (off_t) -1) {
680 0 : NaClLog(1, "NaClElfImageLoadDynamically: seek failed\n");
681 0 : return LOAD_READ_ERROR;
682 : }
683 :
684 0 : if (0 != (php->p_flags & PF_X)) {
685 : /* Load code segment. */
686 : /*
687 : * We make a copy of the code. This is not ideal given that
688 : * GioMemoryFileSnapshot and NaClGioShm already have a copy of
689 : * the file in memory or mmapped.
690 : * TODO(mseaborn): Reduce the amount of copying here.
691 : */
692 0 : char *code_copy = malloc(php->p_filesz);
693 0 : if (NULL == code_copy) {
694 0 : NaClLog(1, "NaClElfImageLoadDynamically: malloc failed\n");
695 0 : return LOAD_NO_MEMORY;
696 : }
697 0 : if ((Elf_Word) (*gfile->vtbl->Read)(gfile, code_copy, php->p_filesz)
698 : != php->p_filesz) {
699 0 : free(code_copy);
700 0 : NaClLog(1, "NaClElfImageLoadDynamically: "
701 : "failed to read code segment\n");
702 0 : return LOAD_READ_ERROR;
703 : }
704 0 : result = NaClTextDyncodeCreate(nap, (uint32_t) php->p_vaddr,
705 : code_copy, (uint32_t) php->p_filesz);
706 0 : free(code_copy);
707 0 : if (0 != result) {
708 0 : NaClLog(1, "NaClElfImageLoadDynamically: "
709 : "failed to load code segment\n");
710 0 : return LOAD_UNLOADABLE;
711 : }
712 : } else {
713 : /* Load data segment. */
714 0 : void *paddr = (void *) NaClUserToSys(nap, php->p_vaddr);
715 0 : size_t mapping_size = NaClRoundAllocPage(php->p_memsz);
716 : /*
717 : * Note that we do not used NACL_ABI_MAP_FIXED because we do not
718 : * want to silently overwrite any existing mappings, such as the
719 : * user app's data segment or the stack. We detect overmapping
720 : * when mmap chooses not to use the preferred address we supply.
721 : * (Ideally mmap would provide a MAP_EXCL option for this
722 : * instead.)
723 : */
724 0 : result = NaClCommonSysMmapIntern(
725 : nap, (void *) (uintptr_t) php->p_vaddr, mapping_size,
726 : NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
727 : NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE,
728 : -1, 0);
729 0 : if ((int32_t) php->p_vaddr != result) {
730 0 : NaClLog(1, "NaClElfImageLoadDynamically: failed to map data segment\n");
731 0 : return LOAD_UNLOADABLE;
732 : }
733 0 : if ((Elf_Word) (*gfile->vtbl->Read)(gfile, paddr, php->p_filesz)
734 : != php->p_filesz) {
735 0 : NaClLog(1, "NaClElfImageLoadDynamically: "
736 : "failed to read data segment\n");
737 0 : return LOAD_READ_ERROR;
738 : }
739 : /*
740 : * Note that we do not need to zero the BSS (the region from
741 : * p_filesz to p_memsz) because it should already be zero
742 : * filled. This would not be the case if we were mapping the
743 : * data segment from the file.
744 : */
745 :
746 0 : if (0 == (php->p_flags & PF_W)) {
747 : /* Handle read-only data segment. */
748 0 : int rc = NaCl_mprotect(paddr, mapping_size, NACL_ABI_PROT_READ);
749 0 : if (0 != rc) {
750 0 : NaClLog(1, "NaClElfImageLoadDynamically: "
751 : "failed to mprotect read-only data segment\n");
752 0 : return LOAD_MPROTECT_FAIL;
753 : }
754 :
755 0 : NaClVmmapUpdate(&nap->mem_map,
756 : php->p_vaddr >> NACL_PAGESHIFT,
757 : mapping_size >> NACL_PAGESHIFT,
758 : PROT_READ,
759 : NULL,
760 : 0 /* remove: false */);
761 : }
762 : }
763 : }
764 0 : return LOAD_OK;
765 : }
766 :
767 :
768 11 : void NaClElfImageDelete(struct NaClElfImage *image) {
769 11 : free(image);
770 11 : }
771 :
772 :
773 8 : uintptr_t NaClElfImageGetEntryPoint(struct NaClElfImage *image) {
774 8 : return image->ehdr.e_entry;
775 : }
|