1 : /*
2 : * Copyright (c) 2012 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_check.h"
27 : #include "native_client/src/shared/platform/nacl_host_desc.h"
28 : #include "native_client/src/shared/platform/nacl_log.h"
29 :
30 : #include "native_client/src/trusted/desc/nacl_desc_effector_trusted_mem.h"
31 : #include "native_client/src/trusted/fault_injection/fault_injection.h"
32 : #include "native_client/src/trusted/perf_counter/nacl_perf_counter.h"
33 : #include "native_client/src/trusted/service_runtime/elf_util.h"
34 : #include "native_client/src/trusted/service_runtime/include/bits/mman.h"
35 : #include "native_client/src/trusted/service_runtime/nacl_config.h"
36 : #include "native_client/src/trusted/service_runtime/nacl_text.h"
37 : #include "native_client/src/trusted/service_runtime/nacl_valgrind_hooks.h"
38 : #include "native_client/src/trusted/service_runtime/sel_memory.h"
39 : #include "native_client/src/trusted/service_runtime/sys_memory.h"
40 : #include "native_client/src/trusted/validator/validation_metadata.h"
41 :
42 : /* private */
43 : struct NaClElfImage {
44 : Elf_Ehdr ehdr;
45 : Elf_Phdr phdrs[NACL_MAX_PROGRAM_HEADERS];
46 : int loadable[NACL_MAX_PROGRAM_HEADERS];
47 : };
48 :
49 :
50 : enum NaClPhdrCheckAction {
51 : PCA_NONE,
52 : PCA_TEXT_CHECK,
53 : PCA_RODATA,
54 : PCA_DATA,
55 : PCA_IGNORE /* ignore this segment. */
56 : };
57 :
58 :
59 : struct NaClPhdrChecks {
60 : Elf_Word p_type;
61 : Elf_Word p_flags; /* rwx */
62 : enum NaClPhdrCheckAction action;
63 : int required; /* only for text for now */
64 : Elf_Addr p_vaddr; /* if non-zero, vaddr must be this */
65 : };
66 :
67 : /*
68 : * Other than empty segments, these are the only ones that are allowed.
69 : */
70 : static const struct NaClPhdrChecks nacl_phdr_check_data[] = {
71 : /* phdr */
72 : { PT_PHDR, PF_R, PCA_IGNORE, 0, 0, },
73 : /* text */
74 : { PT_LOAD, PF_R|PF_X, PCA_TEXT_CHECK, 1, NACL_TRAMPOLINE_END, },
75 : /* rodata */
76 : { PT_LOAD, PF_R, PCA_RODATA, 0, 0, },
77 : /* data/bss */
78 : { PT_LOAD, PF_R|PF_W, PCA_DATA, 0, 0, },
79 : /* tls */
80 : { PT_TLS, PF_R, PCA_IGNORE, 0, 0},
81 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_arm
82 : /* arm exception handling unwind info (for c++)*/
83 : /* TODO(robertm): for some reason this does NOT end up in ro maybe because
84 : * it is relocatable. Try hacking the linker script to move it.
85 : */
86 : { PT_ARM_EXIDX, PF_R, PCA_IGNORE, 0, 0, },
87 : #endif
88 : /*
89 : * allow optional GNU stack permission marker, but require that the
90 : * stack is non-executable.
91 : */
92 : { PT_GNU_STACK, PF_R|PF_W, PCA_NONE, 0, 0, },
93 : /* ignored segments */
94 : { PT_DYNAMIC, PF_R|PF_W, PCA_IGNORE, 0, 0},
95 : /*
96 : * PT_DYNAMIC with PF_R doesn't occur in practice, but leaving it here just
97 : * in case it has been used.
98 : */
99 : { PT_DYNAMIC, PF_R, PCA_IGNORE, 0, 0},
100 : { PT_INTERP, PF_R, PCA_IGNORE, 0, 0},
101 : { PT_NOTE, PF_R, PCA_IGNORE, 0, 0},
102 : { PT_GNU_EH_FRAME, PF_R, PCA_IGNORE, 0, 0},
103 : { PT_GNU_RELRO, PF_R, PCA_IGNORE, 0, 0},
104 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_mips
105 : { PT_MIPS_REGINFO, PF_R, PCA_IGNORE, 0, 0},
106 : #endif
107 : { PT_NULL, PF_R, PCA_IGNORE, 0, 0},
108 : };
109 :
110 :
111 278 : static void NaClDumpElfHeader(int loglevel, Elf_Ehdr *elf_hdr) {
112 :
113 : #define DUMP(m,f) do { NaClLog(loglevel, \
114 : #m " = %" f "\n", \
115 : elf_hdr->m); } while (0)
116 :
117 556 : NaClLog(loglevel, "=================================================\n");
118 556 : NaClLog(loglevel, "Elf header\n");
119 556 : NaClLog(loglevel, "==================================================\n");
120 :
121 1112 : DUMP(e_ident+1, ".3s");
122 1112 : DUMP(e_type, "#x");
123 1112 : DUMP(e_machine, "#x");
124 1112 : DUMP(e_version, "#x");
125 1112 : DUMP(e_entry, "#"NACL_PRIxElf_Addr);
126 1112 : DUMP(e_phoff, "#"NACL_PRIxElf_Off);
127 1112 : DUMP(e_shoff, "#"NACL_PRIxElf_Off);
128 1112 : DUMP(e_flags, "#"NACL_PRIxElf_Word);
129 1112 : DUMP(e_ehsize, "#"NACL_PRIxElf_Half);
130 1112 : DUMP(e_phentsize, "#"NACL_PRIxElf_Half);
131 1112 : DUMP(e_phnum, "#"NACL_PRIxElf_Half);
132 1112 : DUMP(e_shentsize, "#"NACL_PRIxElf_Half);
133 1112 : DUMP(e_shnum, "#"NACL_PRIxElf_Half);
134 1112 : DUMP(e_shstrndx, "#"NACL_PRIxElf_Half);
135 : #undef DUMP
136 556 : NaClLog(loglevel, "sizeof(Elf32_Ehdr) = 0x%x\n", (int) sizeof *elf_hdr);
137 278 : }
138 :
139 :
140 1825 : static void NaClDumpElfProgramHeader(int loglevel,
141 1825 : Elf_Phdr *phdr) {
142 : #define DUMP(mem, f) do { \
143 : NaClLog(loglevel, "%s: %" f "\n", #mem, phdr->mem); \
144 : } while (0)
145 :
146 7300 : DUMP(p_type, NACL_PRIxElf_Word);
147 7300 : DUMP(p_offset, NACL_PRIxElf_Off);
148 7300 : DUMP(p_vaddr, NACL_PRIxElf_Addr);
149 7300 : DUMP(p_paddr, NACL_PRIxElf_Addr);
150 7300 : DUMP(p_filesz, NACL_PRIxElf_Xword);
151 7300 : DUMP(p_memsz, NACL_PRIxElf_Xword);
152 7300 : DUMP(p_flags, NACL_PRIxElf_Word);
153 3650 : NaClLog(2, " (%s %s %s)\n",
154 : (phdr->p_flags & PF_R) ? "PF_R" : "",
155 : (phdr->p_flags & PF_W) ? "PF_W" : "",
156 : (phdr->p_flags & PF_X) ? "PF_X" : "");
157 7300 : DUMP(p_align, NACL_PRIxElf_Xword);
158 : #undef DUMP
159 3650 : NaClLog(loglevel, "\n");
160 1825 : }
161 :
162 :
163 278 : NaClErrorCode NaClElfImageValidateElfHeader(struct NaClElfImage *image) {
164 278 : const Elf_Ehdr *hdr = &image->ehdr;
165 :
166 278 : if (memcmp(hdr->e_ident, ELFMAG, SELFMAG)) {
167 0 : NaClLog(LOG_ERROR, "bad elf magic\n");
168 0 : return LOAD_BAD_ELF_MAGIC;
169 : }
170 :
171 278 : if (ELFCLASS32 != hdr->e_ident[EI_CLASS]) {
172 0 : NaClLog(LOG_ERROR, "bad elf class\n");
173 0 : return LOAD_NOT_32_BIT;
174 : }
175 :
176 278 : if (ET_EXEC != hdr->e_type) {
177 0 : NaClLog(LOG_ERROR, "non executable\n");
178 0 : return LOAD_NOT_EXEC;
179 : }
180 :
181 278 : if (NACL_ELF_E_MACHINE != hdr->e_machine) {
182 0 : NaClLog(LOG_ERROR, "bad machine: %"NACL_PRIxElf_Half"\n", hdr->e_machine);
183 0 : return LOAD_BAD_MACHINE;
184 : }
185 :
186 278 : if (EV_CURRENT != hdr->e_version) {
187 0 : NaClLog(LOG_ERROR, "bad elf version: %"NACL_PRIxElf_Word"\n",
188 : hdr->e_version);
189 0 : return LOAD_BAD_ELF_VERS;
190 : }
191 :
192 278 : return LOAD_OK;
193 278 : }
194 :
195 : /* TODO(robertm): decouple validation from computation of
196 : static_text_end and max_vaddr */
197 : NaClErrorCode NaClElfImageValidateProgramHeaders(
198 271 : struct NaClElfImage *image,
199 271 : uint8_t addr_bits,
200 271 : struct NaClElfImageInfo *info) {
201 : /*
202 : * Scan phdrs and do sanity checks in-line. Verify that the load
203 : * address is NACL_TRAMPOLINE_END, that we have a single text
204 : * segment. Data and TLS segments are not required, though it is
205 : * hard to avoid with standard tools, but in any case there should
206 : * be at most one each. Ensure that no segment's vaddr is outside
207 : * of the address space. Ensure that PT_GNU_STACK is present, and
208 : * that x is off.
209 : */
210 271 : const Elf_Ehdr *hdr = &image->ehdr;
211 271 : int seen_seg[NACL_ARRAY_SIZE(nacl_phdr_check_data)];
212 :
213 271 : int segnum;
214 271 : const Elf_Phdr *php;
215 271 : size_t j;
216 :
217 813 : memset(info, 0, sizeof(*info));
218 :
219 271 : info->max_vaddr = NACL_TRAMPOLINE_END;
220 :
221 : /*
222 : * nacl_phdr_check_data is small, so O(|check_data| * nap->elf_hdr.e_phum)
223 : * is okay.
224 : */
225 271 : memset(seen_seg, 0, sizeof seen_seg);
226 4130 : for (segnum = 0; segnum < hdr->e_phnum; ++segnum) {
227 1794 : php = &image->phdrs[segnum];
228 3588 : NaClLog(3, "Looking at segment %d, type 0x%x, p_flags 0x%x\n",
229 : segnum, php->p_type, php->p_flags);
230 1794 : if (0 == php->p_memsz) {
231 : /*
232 : * We will not load this segment.
233 : */
234 504 : NaClLog(3, "Ignoring empty segment\n");
235 252 : continue;
236 : }
237 :
238 17728 : for (j = 0; j < NACL_ARRAY_SIZE(nacl_phdr_check_data); ++j) {
239 11183 : if (php->p_type == nacl_phdr_check_data[j].p_type
240 : && php->p_flags == nacl_phdr_check_data[j].p_flags)
241 1542 : break;
242 7322 : }
243 1542 : if (j == NACL_ARRAY_SIZE(nacl_phdr_check_data)) {
244 : /* segment not in nacl_phdr_check_data */
245 0 : NaClLog(2,
246 : "Segment %d is of unexpected type 0x%x, flag 0x%x\n",
247 : segnum,
248 : php->p_type,
249 : php->p_flags);
250 0 : return LOAD_BAD_SEGMENT;
251 : }
252 :
253 3084 : NaClLog(2, "Matched nacl_phdr_check_data[%"NACL_PRIuS"]\n", j);
254 1542 : if (seen_seg[j]) {
255 0 : NaClLog(2, "Segment %d is a type that has been seen\n", segnum);
256 0 : return LOAD_DUP_SEGMENT;
257 : }
258 1542 : seen_seg[j] = 1;
259 :
260 1542 : if (PCA_IGNORE == nacl_phdr_check_data[j].action) {
261 1498 : NaClLog(3, "Ignoring\n");
262 749 : continue;
263 : }
264 :
265 : /*
266 : * We will load this segment later. Do the sanity checks.
267 : */
268 1064 : if (0 != nacl_phdr_check_data[j].p_vaddr
269 : && (nacl_phdr_check_data[j].p_vaddr != php->p_vaddr)) {
270 0 : NaClLog(2,
271 : ("Segment %d: bad virtual address: 0x%08"
272 : NACL_PRIxElf_Addr","
273 : " expected 0x%08"NACL_PRIxElf_Addr"\n"),
274 : segnum,
275 : php->p_vaddr,
276 : nacl_phdr_check_data[j].p_vaddr);
277 0 : return LOAD_SEGMENT_BAD_LOC;
278 : }
279 793 : if (php->p_vaddr < NACL_TRAMPOLINE_END) {
280 0 : NaClLog(2,
281 : ("Segment %d: virtual address (0x%08"NACL_PRIxElf_Addr
282 : ") too low\n"),
283 : segnum,
284 : php->p_vaddr);
285 0 : return LOAD_SEGMENT_OUTSIDE_ADDRSPACE;
286 : }
287 1586 : if (php->p_vaddr >= ((uint64_t) 1U << addr_bits) ||
288 : ((uint64_t) 1U << addr_bits) - php->p_vaddr < php->p_memsz) {
289 0 : if (php->p_vaddr + php->p_memsz < php->p_vaddr) {
290 0 : NaClLog(2,
291 : "Segment %d: p_memsz caused integer overflow\n",
292 : segnum);
293 0 : } else {
294 0 : NaClLog(2,
295 : "Segment %d: too large, ends at 0x%08"NACL_PRIxElf_Addr"\n",
296 : segnum,
297 : php->p_vaddr + php->p_memsz);
298 : }
299 0 : return LOAD_SEGMENT_OUTSIDE_ADDRSPACE;
300 : }
301 793 : if (php->p_filesz > php->p_memsz) {
302 0 : NaClLog(2,
303 : ("Segment %d: file size 0x%08"NACL_PRIxElf_Xword" larger"
304 : " than memory size 0x%08"NACL_PRIxElf_Xword"\n"),
305 : segnum,
306 : php->p_filesz,
307 : php->p_memsz);
308 0 : return LOAD_SEGMENT_BAD_PARAM;
309 : }
310 :
311 793 : image->loadable[segnum] = 1;
312 : /* record our decision that we will load this segment */
313 :
314 : /*
315 : * NACL_TRAMPOLINE_END <= p_vaddr
316 : * <= p_vaddr + p_memsz
317 : * < ((uintptr_t) 1U << nap->addr_bits)
318 : */
319 793 : if (info->max_vaddr < php->p_vaddr + php->p_memsz) {
320 791 : info->max_vaddr = php->p_vaddr + php->p_memsz;
321 791 : }
322 :
323 1586 : switch (nacl_phdr_check_data[j].action) {
324 : case PCA_NONE:
325 0 : break;
326 : case PCA_TEXT_CHECK:
327 271 : if (0 == php->p_memsz) {
328 0 : return LOAD_BAD_ELF_TEXT;
329 : }
330 271 : info->static_text_end = NACL_TRAMPOLINE_END + php->p_filesz;
331 271 : break;
332 : case PCA_RODATA:
333 267 : info->rodata_start = php->p_vaddr;
334 267 : info->rodata_end = php->p_vaddr + php->p_memsz;
335 267 : break;
336 : case PCA_DATA:
337 255 : info->data_start = php->p_vaddr;
338 255 : info->data_end = php->p_vaddr + php->p_memsz;
339 255 : break;
340 : case PCA_IGNORE:
341 0 : break;
342 : }
343 793 : }
344 7588 : for (j = 0; j < NACL_ARRAY_SIZE(nacl_phdr_check_data); ++j) {
345 3794 : if (nacl_phdr_check_data[j].required && !seen_seg[j]) {
346 0 : return LOAD_REQUIRED_SEG_MISSING;
347 : }
348 3523 : }
349 :
350 271 : return LOAD_OK;
351 271 : }
352 :
353 :
354 :
355 278 : struct NaClElfImage *NaClElfImageNew(struct NaClDesc *ndp,
356 278 : NaClErrorCode *err_code) {
357 278 : ssize_t read_ret;
358 278 : struct NaClElfImage *result;
359 278 : struct NaClElfImage image;
360 : union {
361 : Elf32_Ehdr ehdr32;
362 : #if NACL_TARGET_SUBARCH == 64
363 : Elf64_Ehdr ehdr64;
364 : #endif
365 278 : } ehdr;
366 278 : int cur_ph;
367 :
368 278 : memset(image.loadable, 0, sizeof image.loadable);
369 :
370 : /*
371 : * We read the larger size of an ELFCLASS64 header even if it turns out
372 : * we're reading an ELFCLASS32 file. No usable ELFCLASS32 binary could
373 : * be so small that it's not larger than Elf64_Ehdr anyway.
374 : */
375 278 : read_ret = (*NACL_VTBL(NaClDesc, ndp)->PRead)(ndp, &ehdr, sizeof ehdr, 0);
376 556 : if (NaClSSizeIsNegErrno(&read_ret) || (size_t) read_ret != sizeof ehdr) {
377 0 : *err_code = LOAD_READ_ERROR;
378 0 : NaClLog(2, "could not load elf headers\n");
379 0 : return 0;
380 : }
381 :
382 : #if NACL_TARGET_SUBARCH == 64
383 278 : if (ELFCLASS64 == ehdr.ehdr64.e_ident[EI_CLASS]) {
384 : /*
385 : * Convert ELFCLASS64 format to ELFCLASS32 format.
386 : * The initial four fields are the same in both classes.
387 : */
388 274 : memcpy(image.ehdr.e_ident, ehdr.ehdr64.e_ident, EI_NIDENT);
389 274 : image.ehdr.e_ident[EI_CLASS] = ELFCLASS32;
390 274 : image.ehdr.e_type = ehdr.ehdr64.e_type;
391 274 : image.ehdr.e_machine = ehdr.ehdr64.e_machine;
392 274 : image.ehdr.e_version = ehdr.ehdr64.e_version;
393 822 : if (ehdr.ehdr64.e_entry > 0xffffffffU ||
394 : ehdr.ehdr64.e_phoff > 0xffffffffU ||
395 : ehdr.ehdr64.e_shoff > 0xffffffffU) {
396 0 : *err_code = LOAD_EHDR_OVERFLOW;
397 0 : NaClLog(2, "ELFCLASS64 file header fields overflow 32 bits\n");
398 0 : return 0;
399 : }
400 274 : image.ehdr.e_entry = (Elf32_Addr) ehdr.ehdr64.e_entry;
401 274 : image.ehdr.e_phoff = (Elf32_Off) ehdr.ehdr64.e_phoff;
402 274 : image.ehdr.e_shoff = (Elf32_Off) ehdr.ehdr64.e_shoff;
403 274 : image.ehdr.e_flags = ehdr.ehdr64.e_flags;
404 274 : if (ehdr.ehdr64.e_ehsize != sizeof(ehdr.ehdr64)) {
405 0 : *err_code = LOAD_BAD_EHSIZE;
406 0 : NaClLog(2, "ELFCLASS64 file e_ehsize != %d\n", (int) sizeof(ehdr.ehdr64));
407 0 : return 0;
408 : }
409 274 : image.ehdr.e_ehsize = sizeof(image.ehdr);
410 274 : image.ehdr.e_phentsize = sizeof(image.phdrs[0]);
411 274 : image.ehdr.e_phnum = ehdr.ehdr64.e_phnum;
412 274 : image.ehdr.e_shentsize = ehdr.ehdr64.e_shentsize;
413 274 : image.ehdr.e_shnum = ehdr.ehdr64.e_shnum;
414 274 : image.ehdr.e_shstrndx = ehdr.ehdr64.e_shstrndx;
415 274 : } else
416 : #endif
417 : {
418 4 : image.ehdr = ehdr.ehdr32;
419 : }
420 :
421 278 : NaClDumpElfHeader(2, &image.ehdr);
422 :
423 278 : *err_code = NaClElfImageValidateElfHeader(&image);
424 278 : if (LOAD_OK != *err_code) {
425 0 : return 0;
426 : }
427 :
428 : /* read program headers */
429 278 : if (image.ehdr.e_phnum > NACL_MAX_PROGRAM_HEADERS) {
430 0 : *err_code = LOAD_TOO_MANY_PROG_HDRS;
431 0 : NaClLog(2, "too many prog headers\n");
432 0 : return 0;
433 : }
434 :
435 : #if NACL_TARGET_SUBARCH == 64
436 278 : if (ELFCLASS64 == ehdr.ehdr64.e_ident[EI_CLASS]) {
437 : /*
438 : * We'll load the 64-bit phdrs and convert them to 32-bit format.
439 : */
440 274 : Elf64_Phdr phdr64[NACL_MAX_PROGRAM_HEADERS];
441 :
442 274 : if (ehdr.ehdr64.e_phentsize != sizeof(Elf64_Phdr)) {
443 0 : *err_code = LOAD_BAD_PHENTSIZE;
444 0 : NaClLog(2, "bad prog headers size\n");
445 0 : NaClLog(2, " ehdr64.e_phentsize = 0x%"NACL_PRIxElf_Half"\n",
446 : ehdr.ehdr64.e_phentsize);
447 0 : NaClLog(2, " sizeof(Elf64_Phdr) = 0x%"NACL_PRIxS"\n",
448 : sizeof(Elf64_Phdr));
449 0 : return 0;
450 : }
451 :
452 : /*
453 : * We know the multiplication won't overflow since we rejected
454 : * e_phnum values larger than the small constant NACL_MAX_PROGRAM_HEADERS.
455 : */
456 274 : read_ret = (*NACL_VTBL(NaClDesc, ndp)->
457 : PRead)(ndp,
458 : &phdr64[0],
459 : image.ehdr.e_phnum * sizeof phdr64[0],
460 : (nacl_off64_t) image.ehdr.e_phoff);
461 548 : if (NaClSSizeIsNegErrno(&read_ret) ||
462 : (size_t) read_ret != image.ehdr.e_phnum * sizeof phdr64[0]) {
463 0 : *err_code = LOAD_READ_ERROR;
464 0 : NaClLog(2, "cannot load tp prog headers\n");
465 0 : return 0;
466 : }
467 :
468 4180 : for (cur_ph = 0; cur_ph < image.ehdr.e_phnum; ++cur_ph) {
469 10906 : if (phdr64[cur_ph].p_offset > 0xffffffffU ||
470 : phdr64[cur_ph].p_vaddr > 0xffffffffU ||
471 : phdr64[cur_ph].p_paddr > 0xffffffffU ||
472 : phdr64[cur_ph].p_filesz > 0xffffffffU ||
473 : phdr64[cur_ph].p_memsz > 0xffffffffU ||
474 : phdr64[cur_ph].p_align > 0xffffffffU) {
475 2 : *err_code = LOAD_PHDR_OVERFLOW;
476 4 : NaClLog(2, "ELFCLASS64 program header fields overflow 32 bits\n");
477 2 : return 0;
478 : }
479 1816 : image.phdrs[cur_ph].p_type = phdr64[cur_ph].p_type;
480 1816 : image.phdrs[cur_ph].p_offset = (Elf32_Off) phdr64[cur_ph].p_offset;
481 1816 : image.phdrs[cur_ph].p_vaddr = (Elf32_Addr) phdr64[cur_ph].p_vaddr;
482 1816 : image.phdrs[cur_ph].p_paddr = (Elf32_Addr) phdr64[cur_ph].p_paddr;
483 1816 : image.phdrs[cur_ph].p_filesz = (Elf32_Word) phdr64[cur_ph].p_filesz;
484 1816 : image.phdrs[cur_ph].p_memsz = (Elf32_Word) phdr64[cur_ph].p_memsz;
485 1816 : image.phdrs[cur_ph].p_flags = phdr64[cur_ph].p_flags;
486 1816 : image.phdrs[cur_ph].p_align = (Elf32_Word) phdr64[cur_ph].p_align;
487 1816 : }
488 272 : } else
489 : #endif
490 : {
491 4 : if (image.ehdr.e_phentsize != sizeof image.phdrs[0]) {
492 0 : *err_code = LOAD_BAD_PHENTSIZE;
493 0 : NaClLog(2, "bad prog headers size\n");
494 0 : NaClLog(2, " image.ehdr.e_phentsize = 0x%"NACL_PRIxElf_Half"\n",
495 : image.ehdr.e_phentsize);
496 0 : NaClLog(2, " sizeof image.phdrs[0] = 0x%"NACL_PRIxS"\n",
497 : sizeof image.phdrs[0]);
498 0 : return 0;
499 : }
500 :
501 4 : read_ret = (*NACL_VTBL(NaClDesc, ndp)->
502 : PRead)(ndp,
503 : &image.phdrs[0],
504 : image.ehdr.e_phnum * sizeof image.phdrs[0],
505 : (nacl_off64_t) image.ehdr.e_phoff);
506 8 : if (NaClSSizeIsNegErrno(&read_ret) ||
507 : (size_t) read_ret != image.ehdr.e_phnum * sizeof image.phdrs[0]) {
508 0 : *err_code = LOAD_READ_ERROR;
509 0 : NaClLog(2, "cannot load tp prog headers\n");
510 0 : return 0;
511 : }
512 : }
513 :
514 552 : NaClLog(2, "=================================================\n");
515 552 : NaClLog(2, "Elf Program headers\n");
516 552 : NaClLog(2, "==================================================\n");
517 4202 : for (cur_ph = 0; cur_ph < image.ehdr.e_phnum; ++cur_ph) {
518 1825 : NaClDumpElfProgramHeader(2, &image.phdrs[cur_ph]);
519 1825 : }
520 :
521 : /* we delay allocating till the end to avoid cleanup code */
522 276 : result = malloc(sizeof image);
523 276 : if (result == 0) {
524 0 : *err_code = LOAD_NO_MEMORY;
525 0 : NaClLog(LOG_FATAL, "no enough memory for image meta data\n");
526 0 : return 0;
527 : }
528 828 : memcpy(result, &image, sizeof image);
529 276 : *err_code = LOAD_OK;
530 276 : return result;
531 278 : }
532 :
533 : /*
534 : * Attempt to map into the NaClApp object nap from the NaCl descriptor
535 : * ndp an ELF segment of type p_flags that start at file_offset for
536 : * segment_size bytes, to memory starting at paddr (system address).
537 : * If it is a code segment, make a scratch mapping and check
538 : * validation in readonly_text mode -- if it succeeds, we map into the
539 : * target address; if it fails, we return failure so that pread-based
540 : * loading can proceed. For rodata and data segments, less checking
541 : * is needed. In the text and data case, the end of the segment may
542 : * not land on a NACL_MAP_PAGESIZE boundary; when this occurs, we will
543 : * map in all whole NACL_MAP_PAGESIZE chunks, and pread in the tail
544 : * partial chunk.
545 : *
546 : * Returns: LOAD_OK, LOAD_STATUS_UNKNOWN, other error codes.
547 : *
548 : * LOAD_OK -- if the segment has been fully handled
549 : * LOAD_STATUS_UNKNOWN -- if pread-based fallback is required
550 : * other error codes -- if a fatal error occurs, and the caller
551 : * should propagate up
552 : *
553 : * See NaClSysMmapIntern in nacl_syscall_common.c for corresponding
554 : * mmap syscall where PROT_EXEC allows shared libraries to be mapped
555 : * into dynamic code space.
556 : */
557 9 : static NaClErrorCode NaClElfFileMapSegment(struct NaClApp *nap,
558 9 : struct NaClDesc *ndp,
559 9 : Elf_Word p_flags,
560 9 : Elf_Off file_offset,
561 9 : Elf_Off segment_size,
562 9 : uintptr_t vaddr,
563 9 : uintptr_t paddr) {
564 9 : size_t rounded_filesz; /* 64k rounded */
565 9 : int mmap_prot = 0;
566 9 : uintptr_t image_sys_addr;
567 9 : NaClValidationStatus validator_status = NaClValidationFailed;
568 9 : struct NaClValidationMetadata metadata;
569 9 : int read_last_page_if_partial_allocation_page = 1;
570 9 : ssize_t read_ret;
571 9 : struct NaClPerfCounter time_mmap_segment;
572 9 : NaClPerfCounterCtor(&time_mmap_segment, "NaClElfFileMapSegment");
573 :
574 9 : rounded_filesz = NaClRoundAllocPage(segment_size);
575 :
576 18 : NaClLog(4,
577 : "NaClElfFileMapSegment: checking segment flags 0x%x"
578 : " to determine map checks\n",
579 : p_flags);
580 : /*
581 : * Is this the text segment? If so, map into scratch memory and
582 : * run validation (possibly cached result) with !stubout_mode,
583 : * readonly_text. If validator says it's okay, map directly into
584 : * target location with NACL_ABI_PROT_READ|_EXEC. If anything
585 : * failed, fall back to PRead. NB: the assumption is that there
586 : * is only one PT_LOAD with PF_R|PF_X segment; this assumption is
587 : * enforced by phdr seen_seg checks above in
588 : * NaClElfImageValidateProgramHeaders.
589 : *
590 : * After this function returns, we will be setting memory protection
591 : * in NaClMemoryProtection, so the actual memory protection used is
592 : * immaterial.
593 : *
594 : * For rodata and data/bss, we mmap with NACL_ABI_PROT_READ or
595 : * NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE as appropriate,
596 : * without doing validation. There is no fallback to PRead, since
597 : * we don't validate the contents.
598 : */
599 9 : switch (p_flags) {
600 : case PF_R | PF_X:
601 6 : NaClLog(4,
602 : "NaClElfFileMapSegment: text segment and"
603 : " file is safe for mmap\n");
604 3 : if (NACL_VTBL(NaClDesc, ndp)->typeTag != NACL_DESC_HOST_IO) {
605 0 : NaClLog(4, "NaClElfFileMapSegment: not supported type, got %d\n",
606 : NACL_VTBL(NaClDesc, ndp)->typeTag);
607 0 : return LOAD_STATUS_UNKNOWN;
608 : }
609 : /*
610 : * Unlike the mmap case, we do not re-run validation to
611 : * allow patching here; instead, we handle validation
612 : * failure by going to the pread_fallback case. In the
613 : * future, we should consider doing an in-place mapping and
614 : * allowing HLT patch validation, which should be cheaper
615 : * since those pages that do not require patching (hopefully
616 : * majority) will remain file-backed and not require swap
617 : * space, even if we had to fault in every page.
618 : */
619 6 : NaClLog(1, "NaClElfFileMapSegment: mapping for validation\n");
620 3 : NaClPerfCounterMark(&time_mmap_segment, "PreMap");
621 3 : NaClPerfCounterIntervalLast(&time_mmap_segment);
622 6 : image_sys_addr = (*NACL_VTBL(NaClDesc, ndp)->
623 : Map)(ndp,
624 3 : NaClDescEffectorTrustedMem(),
625 : (void *) NULL,
626 : rounded_filesz,
627 : NACL_ABI_PROT_READ,
628 : NACL_ABI_MAP_PRIVATE,
629 : file_offset);
630 3 : NaClPerfCounterMark(&time_mmap_segment, "MapForValidate");
631 3 : NaClPerfCounterIntervalLast(&time_mmap_segment);
632 3 : if (NaClPtrIsNegErrno(&image_sys_addr)) {
633 0 : NaClLog(LOG_INFO,
634 : "NaClElfFileMapSegment: Could not make scratch mapping,"
635 : " falling back to reading\n");
636 0 : return LOAD_STATUS_UNKNOWN;
637 : }
638 : /* ask validator / validation cache */
639 3 : NaClMetadataFromNaClDescCtor(&metadata, ndp);
640 9 : CHECK(segment_size == nap->static_text_end - NACL_TRAMPOLINE_END);
641 9 : validator_status = NACL_FI_VAL(
642 : "ELF_LOAD_FORCE_VALIDATION_STATUS",
643 : enum NaClValidationStatus,
644 : (*nap->validator->
645 : Validate)(vaddr,
646 : (uint8_t *) image_sys_addr,
647 : segment_size, /* actual size */
648 : 0, /* stubout_mode: no */
649 : 1, /* readonly_text: yes */
650 : nap->cpu_features,
651 : &metadata,
652 : nap->validation_cache));
653 3 : NaClPerfCounterMark(&time_mmap_segment, "ValidateMapped");
654 3 : NaClPerfCounterIntervalLast(&time_mmap_segment);
655 6 : NaClLog(3, "NaClElfFileMapSegment: validator_status %d\n",
656 : validator_status);
657 3 : NaClMetadataDtor(&metadata);
658 : /*
659 : * Remove scratch mapping, then map directly into untrusted
660 : * address space or pread.
661 : */
662 3 : NaClDescUnmapUnsafe(ndp, (void *) image_sys_addr,
663 : rounded_filesz);
664 : NACL_MAKE_MEM_UNDEFINED((void *) paddr, rounded_filesz);
665 :
666 3 : if (NaClValidationSucceeded != validator_status) {
667 0 : NaClLog(3,
668 : ("NaClElfFileMapSegment: readonly_text validation for mmap"
669 : " failed. Will retry validation allowing HALT stubbing out"
670 : " of unsupported instruction extensions.\n"));
671 0 : return LOAD_STATUS_UNKNOWN;
672 : }
673 :
674 6 : NaClLog(1, "NaClElfFileMapSegment: mapping into code space\n");
675 : /*
676 : * Windows appears to not allow RWX mappings. This interferes
677 : * with HALT_SLED and having to HALT pad the last page. We
678 : * allow partial code pages, so
679 : * read_last_page_if_partial_allocation_page will ensure that
680 : * the last page is writable, so we will be able to write HALT
681 : * instructions as needed.
682 : */
683 3 : mmap_prot = NACL_ABI_PROT_READ | NACL_ABI_PROT_EXEC;
684 : /*
685 : * NB: the log string is used by tests/mmap_main_nexe/nacl.scons
686 : * and must be logged at a level that is less than or equal to
687 : * the requested verbosity level there.
688 : */
689 6 : NaClLog(1, "NaClElfFileMapSegment: EXERCISING MMAP LOAD PATH\n");
690 3 : nap->main_exe_prevalidated = 1;
691 3 : break;
692 :
693 : case PF_R | PF_W:
694 : /* read-write (initialized data) */
695 3 : mmap_prot = NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE;
696 : /*
697 : * NB: the partial page processing will result in zeros
698 : * following the initialized data, so that the BSS will be zero.
699 : * On a typical system, this page is mapped in and the BSS
700 : * region is memset to zero, which means that this partial page
701 : * is faulted in. Rather than saving a syscall (pread) and
702 : * faulting it in, we just use the same code path as for code,
703 : * which is (slightly) simpler.
704 : */
705 3 : break;
706 :
707 : case PF_R:
708 : /* read-only */
709 3 : mmap_prot = NACL_ABI_PROT_READ;
710 : /*
711 : * For rodata, we allow mapping in "garbage" past a partial
712 : * page; this potentially eliminates a disk I/O operation
713 : * (if data section has no partial page), possibly delaying
714 : * disk spin-up if the code was in the validation cache.
715 : * And it saves another 64kB of swap.
716 : */
717 3 : read_last_page_if_partial_allocation_page = 0;
718 3 : break;
719 :
720 : default:
721 0 : NaClLog(LOG_FATAL, "NaClElfFileMapSegment: unexpected p_flags %d\n",
722 : p_flags);
723 0 : }
724 15 : if (rounded_filesz != segment_size &&
725 : read_last_page_if_partial_allocation_page) {
726 3 : uintptr_t tail_offset = rounded_filesz - NACL_MAP_PAGESIZE;
727 3 : size_t tail_size = segment_size - tail_offset;
728 6 : NaClLog(4, "NaClElfFileMapSegment: pread tail\n");
729 3 : read_ret = (*NACL_VTBL(NaClDesc, ndp)->
730 : PRead)(ndp,
731 : (void *) (paddr + tail_offset),
732 : tail_size,
733 : (nacl_off64_t) (file_offset + tail_offset));
734 3 : NaClPerfCounterMark(&time_mmap_segment, "PRead tail");
735 3 : NaClPerfCounterIntervalLast(&time_mmap_segment);
736 6 : if (NaClSSizeIsNegErrno(&read_ret) || (size_t) read_ret != tail_size) {
737 0 : NaClLog(LOG_ERROR,
738 : "NaClElfFileMapSegment: pread load of page tail failed\n");
739 0 : return LOAD_SEGMENT_BAD_PARAM;
740 : }
741 3 : rounded_filesz -= NACL_MAP_PAGESIZE;
742 3 : }
743 : /* mmap in */
744 9 : if (rounded_filesz == 0) {
745 6 : NaClLog(4,
746 : "NaClElfFileMapSegment: no pages to map, probably because"
747 : " the segment was a partial page, so it was processed by"
748 : " reading.\n");
749 3 : } else {
750 12 : NaClLog(4,
751 : "NaClElfFileMapSegment: mapping %"NACL_PRIuS" (0x%"
752 : NACL_PRIxS") bytes to"
753 : " address 0x%"NACL_PRIxPTR", position %"
754 : NACL_PRIdElf_Off" (0x%"NACL_PRIxElf_Off")\n",
755 : rounded_filesz, rounded_filesz,
756 : paddr,
757 : file_offset, file_offset);
758 6 : image_sys_addr = (*NACL_VTBL(NaClDesc, ndp)->
759 : Map)(ndp,
760 : nap->effp,
761 : (void *) paddr,
762 : rounded_filesz,
763 : mmap_prot,
764 : NACL_ABI_MAP_PRIVATE | NACL_ABI_MAP_FIXED,
765 : file_offset);
766 6 : NaClPerfCounterMark(&time_mmap_segment, "MapFinal");
767 6 : NaClPerfCounterIntervalLast(&time_mmap_segment);
768 6 : if (image_sys_addr != paddr) {
769 0 : NaClLog(LOG_FATAL,
770 : ("NaClElfFileMapSegment: map to 0x%"NACL_PRIxPTR" (prot %x) "
771 : "failed: got 0x%"NACL_PRIxPTR"\n"),
772 : paddr, mmap_prot, image_sys_addr);
773 0 : }
774 : /* Tell Valgrind that we've mapped a segment of nacl_file. */
775 6 : NaClFileMappingForValgrind(paddr, rounded_filesz, file_offset);
776 : }
777 9 : return LOAD_OK;
778 9 : }
779 :
780 268 : NaClErrorCode NaClElfImageLoad(struct NaClElfImage *image,
781 268 : struct NaClDesc *ndp,
782 268 : struct NaClApp *nap) {
783 268 : int segnum;
784 268 : uintptr_t vaddr;
785 268 : uintptr_t paddr;
786 268 : uintptr_t end_vaddr;
787 268 : ssize_t read_ret;
788 268 : int safe_for_mmap;
789 :
790 4100 : for (segnum = 0; segnum < image->ehdr.e_phnum; ++segnum) {
791 1782 : const Elf_Phdr *php = &image->phdrs[segnum];
792 1782 : Elf_Off offset = (Elf_Off) NaClTruncAllocPage(php->p_offset);
793 1782 : Elf_Off filesz = php->p_offset + php->p_filesz - offset;
794 :
795 : /* did we decide that we will load this segment earlier? */
796 1782 : if (!image->loadable[segnum]) {
797 998 : continue;
798 : }
799 :
800 1568 : NaClLog(2, "loading segment %d\n", segnum);
801 :
802 784 : if (0 == php->p_filesz) {
803 2 : NaClLog(4, "zero-sized segment. ignoring...\n");
804 1 : continue;
805 : }
806 :
807 783 : end_vaddr = php->p_vaddr + php->p_filesz;
808 : /* integer overflow? */
809 783 : if (end_vaddr < php->p_vaddr) {
810 0 : NaClLog(LOG_FATAL, "parameter error should have been detected already\n");
811 0 : }
812 : /*
813 : * is the end virtual address within the NaCl application's
814 : * address space? if it is, it implies that the start virtual
815 : * address is also.
816 : */
817 783 : if (end_vaddr >= ((uintptr_t) 1U << nap->addr_bits)) {
818 0 : NaClLog(LOG_FATAL, "parameter error should have been detected already\n");
819 0 : }
820 :
821 783 : vaddr = NaClTruncAllocPage(php->p_vaddr);
822 783 : paddr = NaClUserToSysAddr(nap, vaddr);
823 2349 : CHECK(kNaClBadAddress != paddr);
824 :
825 : /*
826 : * Check NaClDescIsSafeForMmap(ndp) to see if it might be okay to
827 : * mmap.
828 : */
829 1566 : NaClLog(4, "NaClElfImageLoad: checking descriptor mmap safety\n");
830 783 : safe_for_mmap = NaClDescIsSafeForMmap(ndp);
831 783 : if (safe_for_mmap) {
832 12 : NaClLog(4, "NaClElfImageLoad: safe-for-mmap\n");
833 6 : }
834 :
835 783 : if (!safe_for_mmap &&
836 1554 : NACL_FI("ELF_LOAD_BYPASS_DESCRIPTOR_SAFETY_CHECK", 0, 1)) {
837 6 : NaClLog(LOG_WARNING, "WARNING: BYPASSING DESCRIPTOR SAFETY CHECK\n");
838 3 : safe_for_mmap = 1;
839 3 : }
840 783 : if (safe_for_mmap) {
841 9 : NaClErrorCode map_status;
842 18 : NaClLog(4, "NaClElfImageLoad: safe-for-mmap\n");
843 9 : map_status = NaClElfFileMapSegment(nap, ndp, php->p_flags,
844 : offset, filesz, vaddr, paddr);
845 : /*
846 : * NB: -Werror=switch-enum forces us to not use a switch.
847 : */
848 9 : if (LOAD_OK == map_status) {
849 : /* Segment has been handled -- proceed to next segment */
850 9 : continue;
851 0 : } else if (LOAD_STATUS_UNKNOWN != map_status) {
852 : /*
853 : * A real error! Return it so that this can be reported to
854 : * the embedding code (via start_module status).
855 : */
856 0 : return map_status;
857 : }
858 : /* Fall through: pread-based fallback requested */
859 0 : }
860 1548 : NaClLog(4,
861 : "PReading %"NACL_PRIdElf_Xword" (0x%"NACL_PRIxElf_Xword") bytes to"
862 : " address 0x%"NACL_PRIxPTR", position %"
863 : NACL_PRIdElf_Off" (0x%"NACL_PRIxElf_Off")\n",
864 : filesz, filesz,
865 : paddr,
866 : offset, offset);
867 :
868 : /*
869 : * Tell valgrind that this memory is accessible and undefined. For more
870 : * details see
871 : * http://code.google.com/p/nativeclient/wiki/ValgrindMemcheck#Implementation_details
872 : */
873 : NACL_MAKE_MEM_UNDEFINED((void *) paddr, filesz);
874 :
875 774 : read_ret = (*NACL_VTBL(NaClDesc, ndp)->
876 : PRead)(ndp, (void *) paddr, filesz, (nacl_off64_t) offset);
877 1548 : if (NaClSSizeIsNegErrno(&read_ret) || (size_t) read_ret != filesz) {
878 0 : NaClLog(LOG_ERROR, "load failure segment %d", segnum);
879 0 : return LOAD_SEGMENT_BAD_PARAM;
880 : }
881 : /* region from p_filesz to p_memsz should already be zero filled */
882 :
883 : /* Tell Valgrind that we've mapped a segment of nacl_file. */
884 774 : NaClFileMappingForValgrind(paddr, filesz, offset);
885 774 : }
886 :
887 268 : return LOAD_OK;
888 268 : }
889 :
890 :
891 : NaClErrorCode NaClElfImageLoadDynamically(
892 5 : struct NaClElfImage *image,
893 5 : struct NaClApp *nap,
894 5 : struct NaClDesc *ndp,
895 5 : struct NaClValidationMetadata *metadata) {
896 5 : ssize_t read_ret;
897 5 : int segnum;
898 72 : for (segnum = 0; segnum < image->ehdr.e_phnum; ++segnum) {
899 31 : const Elf_Phdr *php = &image->phdrs[segnum];
900 31 : Elf_Addr vaddr = php->p_vaddr & ~(NACL_MAP_PAGESIZE - 1);
901 31 : Elf_Off offset = php->p_offset & ~(NACL_MAP_PAGESIZE - 1);
902 31 : Elf_Off filesz = php->p_offset + php->p_filesz - offset;
903 31 : Elf_Off memsz = php->p_offset + php->p_memsz - offset;
904 31 : int32_t result;
905 :
906 : /*
907 : * We check for PT_LOAD directly rather than using the "loadable"
908 : * array because we are not using NaClElfImageValidateProgramHeaders()
909 : * to fill out the "loadable" array for this ELF object. This ELF
910 : * object does not have to fit such strict constraints (such as
911 : * having code at 0x20000), and safety checks are applied by
912 : * NaClTextDyncodeCreate() and NaClSysMmapIntern().
913 : */
914 31 : if (PT_LOAD != php->p_type) {
915 16 : continue;
916 : }
917 :
918 15 : if (0 != (php->p_flags & PF_X)) {
919 : /* Load code segment. */
920 : /*
921 : * We make a copy of the code. This is not ideal given that
922 : * GioMemoryFileSnapshot and NaClGioShm already have a copy of
923 : * the file in memory or mmapped.
924 : * TODO(mseaborn): Reduce the amount of copying here.
925 : */
926 5 : char *code_copy = malloc(filesz);
927 5 : if (NULL == code_copy) {
928 0 : NaClLog(LOG_ERROR, "NaClElfImageLoadDynamically: malloc failed\n");
929 0 : return LOAD_NO_MEMORY;
930 : }
931 5 : read_ret = (*NACL_VTBL(NaClDesc, ndp)->
932 : PRead)(ndp, code_copy, filesz, (nacl_off64_t) offset);
933 10 : if (NaClSSizeIsNegErrno(&read_ret) ||
934 : (size_t) read_ret != filesz) {
935 0 : free(code_copy);
936 0 : NaClLog(LOG_ERROR, "NaClElfImageLoadDynamically: "
937 : "failed to read code segment\n");
938 0 : return LOAD_READ_ERROR;
939 : }
940 5 : if (NULL != metadata) {
941 4 : metadata->code_offset = offset;
942 4 : }
943 5 : result = NaClTextDyncodeCreate(nap, (uint32_t) vaddr,
944 : code_copy, (uint32_t) filesz, metadata);
945 5 : free(code_copy);
946 5 : if (0 != result) {
947 0 : NaClLog(LOG_ERROR, "NaClElfImageLoadDynamically: "
948 : "failed to load code segment\n");
949 0 : return LOAD_UNLOADABLE;
950 : }
951 5 : } else {
952 : /* Load data segment. */
953 10 : void *paddr = (void *) NaClUserToSys(nap, vaddr);
954 10 : size_t mapping_size = NaClRoundAllocPage(memsz);
955 : /*
956 : * Note that we do not used NACL_ABI_MAP_FIXED because we do not
957 : * want to silently overwrite any existing mappings, such as the
958 : * user app's data segment or the stack. We detect overmapping
959 : * when mmap chooses not to use the preferred address we supply.
960 : * (Ideally mmap would provide a MAP_EXCL option for this
961 : * instead.)
962 : */
963 10 : result = NaClSysMmapIntern(
964 : nap, (void *) (uintptr_t) vaddr, mapping_size,
965 : NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
966 : NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE,
967 : -1, 0);
968 10 : if ((int32_t) vaddr != result) {
969 0 : NaClLog(LOG_ERROR, "NaClElfImageLoadDynamically: "
970 : "failed to map data segment\n");
971 0 : return LOAD_UNLOADABLE;
972 : }
973 10 : read_ret = (*NACL_VTBL(NaClDesc, ndp)->
974 : PRead)(ndp, paddr, filesz, (nacl_off64_t) offset);
975 20 : if (NaClSSizeIsNegErrno(&read_ret) ||
976 : (size_t) read_ret != filesz) {
977 0 : NaClLog(LOG_ERROR, "NaClElfImageLoadDynamically: "
978 : "failed to read data segment\n");
979 0 : return LOAD_READ_ERROR;
980 : }
981 : /*
982 : * Note that we do not need to zero the BSS (the region from
983 : * p_filesz to p_memsz) because it should already be zero
984 : * filled. This would not be the case if we were mapping the
985 : * data segment from the file.
986 : */
987 :
988 10 : if (0 == (php->p_flags & PF_W)) {
989 : /* Handle read-only data segment. */
990 5 : int rc = NaClMprotect(paddr, mapping_size, NACL_ABI_PROT_READ);
991 5 : if (0 != rc) {
992 0 : NaClLog(LOG_ERROR, "NaClElfImageLoadDynamically: "
993 : "failed to mprotect read-only data segment\n");
994 0 : return LOAD_MPROTECT_FAIL;
995 : }
996 :
997 5 : NaClVmmapAddWithOverwrite(&nap->mem_map,
998 : vaddr >> NACL_PAGESHIFT,
999 : mapping_size >> NACL_PAGESHIFT,
1000 : NACL_ABI_PROT_READ,
1001 : NACL_ABI_MAP_PRIVATE,
1002 : NULL,
1003 : 0,
1004 : 0);
1005 5 : }
1006 : }
1007 15 : }
1008 5 : return LOAD_OK;
1009 5 : }
1010 :
1011 276 : void NaClElfImageDelete(struct NaClElfImage *image) {
1012 276 : free(image);
1013 276 : }
1014 :
1015 :
1016 276 : uintptr_t NaClElfImageGetEntryPoint(struct NaClElfImage *image) {
1017 276 : return image->ehdr.e_entry;
1018 : }
|