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.
10 * NaCl Simple/secure ELF loader (NaCl SEL).
12 #include "native_client/src/include/portability.h"
13 #include "native_client/src/include/portability_io.h"
14 #include "native_client/src/include/portability_string.h"
15 #include "native_client/src/include/nacl_macros.h"
17 #include "native_client/src/shared/gio/gio.h"
18 #include "native_client/src/shared/platform/nacl_check.h"
19 #include "native_client/src/shared/platform/nacl_exit.h"
20 #include "native_client/src/shared/platform/nacl_log.h"
21 #include "native_client/src/shared/platform/nacl_sync.h"
22 #include "native_client/src/shared/platform/nacl_sync_checked.h"
23 #include "native_client/src/shared/platform/nacl_time.h"
24 #include "native_client/src/shared/srpc/nacl_srpc.h"
26 #include "native_client/src/trusted/desc/nacl_desc_base.h"
27 #include "native_client/src/trusted/desc/nacl_desc_conn_cap.h"
28 #include "native_client/src/trusted/desc/nacl_desc_imc.h"
29 #include "native_client/src/trusted/desc/nacl_desc_io.h"
30 #include "native_client/src/trusted/desc/nrd_xfer.h"
31 #include "native_client/src/trusted/fault_injection/fault_injection.h"
32 #include "native_client/src/trusted/fault_injection/test_injection.h"
33 #include "native_client/src/trusted/gio/gio_nacl_desc.h"
34 #include "native_client/src/trusted/gio/gio_shm.h"
35 #include "native_client/src/trusted/interval_multiset/nacl_interval_range_tree_intern.h"
36 #include "native_client/src/trusted/service_runtime/arch/sel_ldr_arch.h"
37 #include "native_client/src/trusted/service_runtime/include/bits/nacl_syscalls.h"
38 #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
39 #include "native_client/src/trusted/service_runtime/include/sys/stat.h"
40 #include "native_client/src/trusted/service_runtime/include/sys/time.h"
41 #include "native_client/src/trusted/service_runtime/nacl_app.h"
42 #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
43 #include "native_client/src/trusted/service_runtime/nacl_desc_effector_ldr.h"
44 #include "native_client/src/trusted/service_runtime/nacl_globals.h"
45 #include "native_client/src/trusted/service_runtime/nacl_resource.h"
46 #include "native_client/src/trusted/service_runtime/nacl_reverse_quota_interface.h"
47 #include "native_client/src/trusted/service_runtime/nacl_syscall_common.h"
48 #include "native_client/src/trusted/service_runtime/nacl_syscall_handlers.h"
49 #include "native_client/src/trusted/service_runtime/nacl_valgrind_hooks.h"
50 #include "native_client/src/trusted/service_runtime/name_service/default_name_service.h"
51 #include "native_client/src/trusted/service_runtime/name_service/name_service.h"
52 #include "native_client/src/trusted/service_runtime/sel_addrspace.h"
53 #include "native_client/src/trusted/service_runtime/sel_ldr.h"
54 #include "native_client/src/trusted/service_runtime/sel_memory.h"
55 #include "native_client/src/trusted/service_runtime/sel_ldr_thread_interface.h"
56 #include "native_client/src/trusted/simple_service/nacl_simple_rservice.h"
57 #include "native_client/src/trusted/simple_service/nacl_simple_service.h"
58 #include "native_client/src/trusted/threading/nacl_thread_interface.h"
60 static int IsEnvironmentVariableSet(char const *env_name) {
61 return NULL != getenv(env_name);
64 static int ShouldEnableDyncodeSyscalls(void) {
65 return !IsEnvironmentVariableSet("NACL_DISABLE_DYNCODE_SYSCALLS");
68 static int ShouldEnableDynamicLoading(void) {
69 return !IsEnvironmentVariableSet("NACL_DISABLE_DYNAMIC_LOADING");
72 int NaClAppWithSyscallTableCtor(struct NaClApp *nap,
73 struct NaClSyscallTableEntry *table) {
74 struct NaClDescEffectorLdr *effp;
76 /* The validation cache will be injected later, if it exists. */
77 nap->validation_cache = NULL;
79 nap->validator = NaClCreateValidator();
81 /* Get the set of features that the CPU we're running on supports. */
82 /* These may be adjusted later in sel_main.c for fixed-feature CPU mode. */
83 nap->cpu_features = (NaClCPUFeatures *) malloc(
84 nap->validator->CPUFeatureSize);
85 if (NULL == nap->cpu_features) {
88 nap->validator->GetCurrentCPUFeatures(nap->cpu_features);
89 nap->fixed_feature_cpu_mode = 0;
91 nap->addr_bits = NACL_MAX_ADDR_BITS;
93 nap->stack_size = NACL_DEFAULT_STACK_MAX;
94 nap->initial_nexe_max_code_bytes = 0;
98 #if (NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 \
99 && NACL_BUILD_SUBARCH == 32)
100 nap->pcrel_thunk = 0;
101 nap->pcrel_thunk_end = 0;
103 #if (NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 \
104 && NACL_BUILD_SUBARCH == 64)
105 nap->nacl_syscall_addr = 0;
106 nap->get_tls_fast_path1_addr = 0;
107 nap->get_tls_fast_path2_addr = 0;
110 nap->static_text_end = 0;
111 nap->dynamic_text_start = 0;
112 nap->dynamic_text_end = 0;
113 nap->rodata_start = 0;
117 nap->initial_entry_pt = 0;
118 nap->user_entry_pt = 0;
120 if (!DynArrayCtor(&nap->threads, 2)) {
121 goto cleanup_cpu_features;
123 if (!DynArrayCtor(&nap->desc_tbl, 2)) {
124 goto cleanup_threads;
126 if (!NaClVmmapCtor(&nap->mem_map)) {
127 goto cleanup_desc_tbl;
130 nap->mem_io_regions = (struct NaClIntervalMultiset *) malloc(
131 sizeof(struct NaClIntervalRangeTree));
132 if (NULL == nap->mem_io_regions) {
133 goto cleanup_mem_map;
136 if (!NaClIntervalRangeTreeCtor((struct NaClIntervalRangeTree *)
137 nap->mem_io_regions)) {
138 free(nap->mem_io_regions);
139 nap->mem_io_regions = NULL;
140 goto cleanup_mem_map;
143 effp = (struct NaClDescEffectorLdr *) malloc(sizeof *effp);
145 goto cleanup_mem_io_regions;
147 if (!NaClDescEffectorLdrCtor(effp, nap)) {
148 goto cleanup_effp_free;
150 nap->effp = (struct NaClDescEffector *) effp;
152 nap->enable_dyncode_syscalls = ShouldEnableDyncodeSyscalls();
153 nap->use_shm_for_dynamic_text = ShouldEnableDynamicLoading();
154 nap->text_shm = NULL;
155 if (!NaClMutexCtor(&nap->dynamic_load_mutex)) {
156 goto cleanup_effp_free;
158 nap->dynamic_page_bitmap = NULL;
160 nap->dynamic_regions = NULL;
161 nap->num_dynamic_regions = 0;
162 nap->dynamic_regions_allocated = 0;
163 nap->dynamic_delete_generation = 0;
165 nap->dynamic_mapcache_offset = 0;
166 nap->dynamic_mapcache_size = 0;
167 nap->dynamic_mapcache_ret = 0;
169 nap->service_port = NULL;
170 nap->service_address = NULL;
171 nap->secure_service_port = NULL;
172 nap->secure_service_address = NULL;
173 nap->bootstrap_channel = NULL;
174 nap->secure_service = NULL;
176 nap->main_exe_prevalidated = 0;
178 nap->kernel_service = NULL;
179 nap->resource_phase = NACL_RESOURCE_PHASE_START;
180 if (!NaClResourceNaClAppInit(&nap->resources, nap)) {
181 goto cleanup_dynamic_load_mutex;
184 if (!NaClMutexCtor(&nap->mu)) {
185 goto cleanup_dynamic_load_mutex;
187 if (!NaClCondVarCtor(&nap->cv)) {
192 nap->vm_hole_may_exist = 0;
193 nap->threads_launching = 0;
196 nap->syscall_table = table;
198 nap->runtime_host_interface = NULL;
199 nap->desc_quota_interface = NULL;
201 nap->module_initialization_state = NACL_MODULE_UNINITIALIZED;
202 nap->module_load_status = LOAD_STATUS_UNKNOWN;
204 nap->name_service = (struct NaClNameService *) malloc(
205 sizeof *nap->name_service);
206 if (NULL == nap->name_service) {
209 if (!NaClNameServiceCtor(nap->name_service,
210 NaClAddrSpSquattingThreadIfFactoryFunction,
212 free(nap->name_service);
215 nap->name_service_conn_cap = NaClDescRef(nap->name_service->
216 base.base.bound_and_cap[1]);
217 if (!NaClDefaultNameServiceInit(nap->name_service)) {
218 goto cleanup_name_service;
221 nap->ignore_validator_result = 0;
222 nap->skip_validator = 0;
223 nap->validator_stub_out_mode = 0;
225 if (IsEnvironmentVariableSet("NACL_DANGEROUS_ENABLE_FILE_ACCESS")) {
226 NaClInsecurelyBypassAllAclChecks();
227 NaClLog(LOG_INFO, "DANGER: ENABLED FILE ACCESS\n");
230 nap->enable_list_mappings = 0;
231 if (IsEnvironmentVariableSet("NACL_DANGEROUS_ENABLE_LIST_MAPPINGS")) {
233 * This syscall is not actually know to be dangerous, but is not yet
234 * exposed by our public API.
236 NaClLog(LOG_INFO, "DANGER: ENABLED LIST_MAPPINGS\n");
237 nap->enable_list_mappings = 1;
240 if (!NaClMutexCtor(&nap->threads_mu)) {
241 goto cleanup_name_service;
243 nap->num_threads = 0;
244 if (!NaClFastMutexCtor(&nap->desc_mu)) {
245 goto cleanup_threads_mu;
249 nap->exit_status = -1;
251 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
252 nap->code_seg_sel = 0;
253 nap->data_seg_sel = 0;
256 nap->debug_stub_callbacks = NULL;
257 nap->exception_handler = 0;
258 if (!NaClMutexCtor(&nap->exception_mu)) {
259 goto cleanup_desc_mu;
261 nap->enable_exception_handling = 0;
263 nap->debug_exception_handler_state = NACL_DEBUG_EXCEPTION_HANDLER_NOT_STARTED;
264 nap->attach_debug_exception_handler_func = NULL;
266 nap->enable_faulted_thread_queue = 0;
267 nap->faulted_thread_count = 0;
269 nap->faulted_thread_event = INVALID_HANDLE_VALUE;
271 nap->faulted_thread_fd_read = -1;
272 nap->faulted_thread_fd_write = -1;
276 #if NACL_LINUX || NACL_OSX
278 * Try to pre-cache information that we can't obtain with the outer
279 * sandbox on. If the outer sandbox has already been enabled, this
280 * will just set sc_nprocessors_onln to -1, and it is the
281 * responsibility of the caller to replace this with a sane value
282 * after the Ctor returns.
284 nap->sc_nprocessors_onln = sysconf(_SC_NPROCESSORS_ONLN);
287 if (!NaClMutexCtor(&nap->futex_wait_list_mu)) {
288 goto cleanup_exception_mu;
290 nap->futex_wait_list_head.next = &nap->futex_wait_list_head;
291 nap->futex_wait_list_head.prev = &nap->futex_wait_list_head;
295 cleanup_exception_mu:
296 NaClMutexDtor(&nap->exception_mu);
298 NaClFastMutexDtor(&nap->desc_mu);
300 NaClMutexDtor(&nap->threads_mu);
301 cleanup_name_service:
302 NaClDescUnref(nap->name_service_conn_cap);
303 NaClRefCountUnref((struct NaClRefCount *) nap->name_service);
305 NaClCondVarDtor(&nap->cv);
307 NaClMutexDtor(&nap->mu);
308 cleanup_dynamic_load_mutex:
309 NaClMutexDtor(&nap->dynamic_load_mutex);
312 cleanup_mem_io_regions:
313 NaClIntervalMultisetDelete(nap->mem_io_regions);
314 nap->mem_io_regions = NULL;
316 NaClVmmapDtor(&nap->mem_map);
318 DynArrayDtor(&nap->desc_tbl);
320 DynArrayDtor(&nap->threads);
321 cleanup_cpu_features:
322 free(nap->cpu_features);
327 int NaClAppCtor(struct NaClApp *nap) {
328 return NaClAppWithSyscallTableCtor(nap, nacl_syscall);
332 * unaligned little-endian load. precondition: nbytes should never be
335 static uint64_t NaClLoadMem(uintptr_t addr,
336 size_t user_nbytes) {
339 CHECK(0 != user_nbytes && user_nbytes <= 8);
343 value |= ((uint8_t *) addr)[--user_nbytes];
344 } while (user_nbytes > 0);
348 #define GENERIC_LOAD(bits) \
349 static uint ## bits ## _t NaClLoad ## bits(uintptr_t addr) { \
350 return (uint ## bits ## _t) NaClLoadMem(addr, sizeof(uint ## bits ## _t)); \
353 #if NACL_TARGET_SUBARCH == 32
361 * unaligned little-endian store
363 static void NaClStoreMem(uintptr_t addr,
370 for (i = 0; i < nbytes; ++i) {
371 ((uint8_t *) addr)[i] = (uint8_t) value;
376 #define GENERIC_STORE(bits) \
377 static void NaClStore ## bits(uintptr_t addr, \
378 uint ## bits ## _t v) { \
379 NaClStoreMem(addr, sizeof(uint ## bits ## _t), v); \
388 struct NaClPatchInfo *NaClPatchInfoCtor(struct NaClPatchInfo *self) {
390 memset(self, 0, sizeof *self);
396 * This function is called by NaClLoadTrampoline and NaClLoadSpringboard to
397 * patch a single memory location specified in NaClPatchInfo structure.
399 void NaClApplyPatchToMemory(struct NaClPatchInfo *patch) {
403 uintptr_t target_addr;
405 memcpy((void *) patch->dst, (void *) patch->src, patch->nbytes);
407 reloc = patch->dst - patch->src;
410 for (i = 0; i < patch->num_abs64; ++i) {
411 offset = patch->abs64[i].target - patch->src;
412 target_addr = patch->dst + offset;
413 NaClStore64(target_addr, patch->abs64[i].value);
416 for (i = 0; i < patch->num_abs32; ++i) {
417 offset = patch->abs32[i].target - patch->src;
418 target_addr = patch->dst + offset;
419 NaClStore32(target_addr, (uint32_t) patch->abs32[i].value);
422 for (i = 0; i < patch->num_abs16; ++i) {
423 offset = patch->abs16[i].target - patch->src;
424 target_addr = patch->dst + offset;
425 NaClStore16(target_addr, (uint16_t) patch->abs16[i].value);
428 for (i = 0; i < patch->num_rel64; ++i) {
429 offset = patch->rel64[i] - patch->src;
430 target_addr = patch->dst + offset;
431 NaClStore64(target_addr, NaClLoad64(target_addr) - reloc);
435 * rel32 is only supported on 32-bit architectures. The range of a relative
436 * relocation in untrusted space is +/- 4GB. This can be represented as
437 * an unsigned 32-bit value mod 2^32, which is handy on a 32 bit system since
438 * all 32-bit pointer arithmetic is implicitly mod 2^32. On a 64 bit system,
439 * however, pointer arithmetic is implicitly modulo 2^64, which isn't as
440 * helpful for our purposes. We could simulate the 32-bit behavior by
441 * explicitly modding all relative addresses by 2^32, but that seems like an
442 * expensive way to save a few bytes per reloc.
444 #if NACL_TARGET_SUBARCH == 32
445 for (i = 0; i < patch->num_rel32; ++i) {
446 offset = patch->rel32[i] - patch->src;
447 target_addr = patch->dst + offset;
448 NaClStore32(target_addr,
449 (uint32_t) NaClLoad32(target_addr) - (int32_t) reloc);
456 * Install syscall trampolines at all possible well-formed entry
457 * points within the trampoline pages. Many of these syscalls will
458 * correspond to unimplemented system calls and will just abort the
461 void NaClLoadTrampoline(struct NaClApp *nap) {
466 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
467 if (!NaClMakePcrelThunk(nap)) {
468 NaClLog(LOG_FATAL, "NaClMakePcrelThunk failed!\n");
471 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64
472 if (!NaClMakeDispatchAddrs(nap)) {
473 NaClLog(LOG_FATAL, "NaClMakeDispatchAddrs failed!\n");
476 NaClFillTrampolineRegion(nap);
479 * Do not bother to fill in the contents of page 0, since we make it
480 * inaccessible later (see sel_addrspace.c, NaClMemoryProtection)
481 * anyway to help detect NULL pointer errors, and we might as well
482 * not dirty the page.
484 * The last syscall entry point is used for springboard code.
486 num_syscalls = ((NACL_TRAMPOLINE_END - NACL_SYSCALL_START_ADDR)
487 / NACL_SYSCALL_BLOCK_SIZE) - 1;
489 NaClLog(2, "num_syscalls = %d (0x%x)\n", num_syscalls, num_syscalls);
491 #if defined(NACL_TARGET_ARM_THUMB2_MODE)
492 CHECK(0 != ((nap->user_entry_pt | nap->initial_entry_pt) & 0x1));
494 * Thumb trampolines start 2 bytes before the aligned syscall address used
495 * by ordinary ARM. We initialize this by adding 0xe to the start address
496 * of each trampoline. Because the last start address would actually start
497 * into user code above, this allows one fewer trampolines than in ARM.
499 for (i = 0, addr = nap->mem_start + NACL_SYSCALL_START_ADDR + 0xe;
500 i < num_syscalls - 1;
501 ++i, addr += NACL_SYSCALL_BLOCK_SIZE) {
502 NaClPatchOneTrampoline(nap, addr);
505 for (i = 0, addr = nap->mem_start + NACL_SYSCALL_START_ADDR;
507 ++i, addr += NACL_SYSCALL_BLOCK_SIZE) {
508 NaClPatchOneTrampoline(nap, addr);
511 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64
512 NaClPatchOneTrampolineCall(nap->get_tls_fast_path1_addr,
513 nap->mem_start + NACL_SYSCALL_START_ADDR
514 + NACL_SYSCALL_BLOCK_SIZE * NACL_sys_tls_get);
515 NaClPatchOneTrampolineCall(nap->get_tls_fast_path2_addr,
516 nap->mem_start + NACL_SYSCALL_START_ADDR
517 + (NACL_SYSCALL_BLOCK_SIZE *
518 NACL_sys_second_tls_get));
521 NACL_TEST_INJECTION(ChangeTrampolines, (nap));
524 void NaClMemRegionPrinter(void *state,
525 struct NaClVmmapEntry *entry) {
526 struct Gio *gp = (struct Gio *) state;
528 gprintf(gp, "\nPage %"NACL_PRIdPTR" (0x%"NACL_PRIxPTR")\n",
529 entry->page_num, entry->page_num);
530 gprintf(gp, "npages %"NACL_PRIdS" (0x%"NACL_PRIxS")\n", entry->npages,
532 gprintf(gp, "start vaddr 0x%"NACL_PRIxPTR"\n",
533 entry->page_num << NACL_PAGESHIFT);
534 gprintf(gp, "end vaddr 0x%"NACL_PRIxPTR"\n",
535 (entry->page_num + entry->npages) << NACL_PAGESHIFT);
536 gprintf(gp, "prot 0x%08x\n", entry->prot);
537 gprintf(gp, "%sshared/backed by a file\n",
538 (NULL == entry->desc) ? "not " : "");
541 void NaClAppPrintDetails(struct NaClApp *nap,
543 NaClXMutexLock(&nap->mu);
545 "NaClAppPrintDetails((struct NaClApp *) 0x%08"NACL_PRIxPTR","
546 "(struct Gio *) 0x%08"NACL_PRIxPTR")\n", (uintptr_t) nap,
548 gprintf(gp, "addr space size: 2**%"NACL_PRId32"\n", nap->addr_bits);
549 gprintf(gp, "stack size: 0x%08"NACL_PRIx32"\n", nap->stack_size);
551 gprintf(gp, "mem start addr: 0x%08"NACL_PRIxPTR"\n", nap->mem_start);
552 /* 123456789012345678901234567890 */
554 gprintf(gp, "static_text_end: 0x%08"NACL_PRIxPTR"\n", nap->static_text_end);
555 gprintf(gp, "end-of-text: 0x%08"NACL_PRIxPTR"\n",
556 NaClEndOfStaticText(nap));
557 gprintf(gp, "rodata: 0x%08"NACL_PRIxPTR"\n", nap->rodata_start);
558 gprintf(gp, "data: 0x%08"NACL_PRIxPTR"\n", nap->data_start);
559 gprintf(gp, "data_end: 0x%08"NACL_PRIxPTR"\n", nap->data_end);
560 gprintf(gp, "break_addr: 0x%08"NACL_PRIxPTR"\n", nap->break_addr);
562 gprintf(gp, "ELF initial entry point: 0x%08x\n", nap->initial_entry_pt);
563 gprintf(gp, "ELF user entry point: 0x%08x\n", nap->user_entry_pt);
564 gprintf(gp, "memory map:\n");
565 NaClVmmapVisit(&nap->mem_map,
566 NaClMemRegionPrinter,
568 NaClXMutexUnlock(&nap->mu);
571 struct NaClDesc *NaClGetDescMu(struct NaClApp *nap,
573 struct NaClDesc *result;
575 result = (struct NaClDesc *) DynArrayGet(&nap->desc_tbl, d);
576 if (NULL != result) {
583 void NaClSetDescMu(struct NaClApp *nap,
585 struct NaClDesc *ndp) {
586 struct NaClDesc *result;
588 result = (struct NaClDesc *) DynArrayGet(&nap->desc_tbl, d);
589 NaClDescSafeUnref(result);
591 if (!DynArraySet(&nap->desc_tbl, d, ndp)) {
593 "NaClSetDesc: could not set descriptor %d to 0x%08"
600 int32_t NaClSetAvailMu(struct NaClApp *nap,
601 struct NaClDesc *ndp) {
604 pos = DynArrayFirstAvail(&nap->desc_tbl);
606 if (pos > INT32_MAX) {
608 ("NaClSetAvailMu: DynArrayFirstAvail returned a value"
609 " that is greather than 2**31-1.\n"));
612 NaClSetDescMu(nap, (int) pos, ndp);
614 return (int32_t) pos;
617 struct NaClDesc *NaClGetDesc(struct NaClApp *nap,
619 struct NaClDesc *res;
621 NaClFastMutexLock(&nap->desc_mu);
622 res = NaClGetDescMu(nap, d);
623 NaClFastMutexUnlock(&nap->desc_mu);
627 void NaClSetDesc(struct NaClApp *nap,
629 struct NaClDesc *ndp) {
630 NaClFastMutexLock(&nap->desc_mu);
631 NaClSetDescMu(nap, d, ndp);
632 NaClFastMutexUnlock(&nap->desc_mu);
635 int32_t NaClSetAvail(struct NaClApp *nap,
636 struct NaClDesc *ndp) {
639 NaClFastMutexLock(&nap->desc_mu);
640 pos = NaClSetAvailMu(nap, ndp);
641 NaClFastMutexUnlock(&nap->desc_mu);
646 int NaClAddThreadMu(struct NaClApp *nap,
647 struct NaClAppThread *natp) {
650 pos = DynArrayFirstAvail(&nap->threads);
652 if (!DynArraySet(&nap->threads, pos, natp)) {
654 "NaClAddThreadMu: DynArraySet at position %"NACL_PRIuS" failed\n",
661 int NaClAddThread(struct NaClApp *nap,
662 struct NaClAppThread *natp) {
665 NaClXMutexLock(&nap->threads_mu);
666 pos = NaClAddThreadMu(nap, natp);
667 NaClXMutexUnlock(&nap->threads_mu);
672 void NaClRemoveThreadMu(struct NaClApp *nap,
674 if (NULL == DynArrayGet(&nap->threads, thread_num)) {
676 "NaClRemoveThreadMu:: thread to be removed is not in the table\n");
678 if (nap->num_threads == 0) {
680 "NaClRemoveThreadMu:: num_threads cannot be 0!!!\n");
683 if (!DynArraySet(&nap->threads, thread_num, (struct NaClAppThread *) NULL)) {
685 "NaClRemoveThreadMu:: DynArraySet at position %d failed\n",
690 void NaClRemoveThread(struct NaClApp *nap,
692 NaClXMutexLock(&nap->threads_mu);
693 NaClRemoveThreadMu(nap, thread_num);
694 NaClXMutexUnlock(&nap->threads_mu);
697 struct NaClAppThread *NaClGetThreadMu(struct NaClApp *nap,
699 return (struct NaClAppThread *) DynArrayGet(&nap->threads, thread_num);
702 void NaClAddHostDescriptor(struct NaClApp *nap,
706 struct NaClDescIoDesc *dp;
709 "NaClAddHostDescriptor: host %d as nacl desc %d, flag 0x%x\n",
713 dp = NaClDescIoDescMake(NaClHostDescPosixMake(host_os_desc, flag));
715 NaClLog(LOG_FATAL, "NaClAddHostDescriptor: NaClDescIoDescMake failed\n");
717 NaClSetDesc(nap, nacl_desc, (struct NaClDesc *) dp);
720 void NaClAddImcHandle(struct NaClApp *nap,
723 struct NaClDescImcDesc *dp;
726 ("NaClAddImcHandle: importing NaClHandle %"NACL_PRIxPTR
727 " as nacl desc %d\n"),
730 dp = (struct NaClDescImcDesc *) malloc(sizeof *dp);
731 if (NACL_FI_ERROR_COND("NaClAddImcHandle__malloc", NULL == dp)) {
732 NaClLog(LOG_FATAL, "NaClAddImcHandle: no memory\n");
734 if (NACL_FI_ERROR_COND("NaClAddImcHandle__ctor",
735 !NaClDescImcDescCtor(dp, h))) {
736 NaClLog(LOG_FATAL, ("NaClAddImcHandle: cannot construct"
737 " IMC descriptor object\n"));
739 NaClSetDesc(nap, nacl_desc, (struct NaClDesc *) dp);
745 char const *env_name;
748 } const g_nacl_redir_control[] = {
749 { 0, "NACL_EXE_STDIN",
750 NACL_ABI_O_RDONLY, 0, },
751 { 1, "NACL_EXE_STDOUT",
752 NACL_ABI_O_WRONLY | NACL_ABI_O_APPEND | NACL_ABI_O_CREAT, 0777, },
753 { 2, "NACL_EXE_STDERR",
754 NACL_ABI_O_WRONLY | NACL_ABI_O_APPEND | NACL_ABI_O_CREAT, 0777, },
758 * File redirection is impossible if an outer sandbox is in place.
759 * For the command-line embedding, we sometimes have an outer sandbox:
760 * on OSX, it is enabled after loading the file is loaded. On the
761 * other hand, device redirection (DEBUG_ONLY:dev://postmessage) is
762 * impossible until the reverse channel setup has occurred.
764 * Because of this, we run NaClProcessRedirControl twice: once to
765 * process default inheritance, file redirection early on, and once
766 * after the reverse channel is in place to handle the device
767 * redirection. We try to hide knowledge about which redirection
768 * control values can be handled in which phases by allowing the
769 * NaClResourceOpen to fail, and only in the last phase do we check
770 * that the redirection succeeded in *some* phase.
772 static void NaClProcessRedirControl(struct NaClApp *nap) {
776 struct NaClDesc *ndp;
778 for (ix = 0; ix < NACL_ARRAY_SIZE(g_nacl_redir_control); ++ix) {
780 if (NULL != (env = getenv(g_nacl_redir_control[ix].env_name))) {
781 NaClLog(4, "getenv(%s) -> %s\n", g_nacl_redir_control[ix].env_name, env);
782 ndp = NaClResourceOpen((struct NaClResource *) &nap->resources,
784 g_nacl_redir_control[ix].nacl_flags,
785 g_nacl_redir_control[ix].mode);
786 NaClLog(4, " NaClResourceOpen returned %"NACL_PRIxPTR"\n",
791 NaClLog(4, "Setting descriptor %d\n", (int) ix);
792 NaClSetDesc(nap, (int) ix, ndp);
793 } else if (NACL_RESOURCE_PHASE_START == nap->resource_phase) {
795 * Environment not set or redirect failed -- handle default inheritance.
797 NaClAddHostDescriptor(nap, DUP(g_nacl_redir_control[ix].d),
798 g_nacl_redir_control[ix].nacl_flags, (int) ix);
804 * Process default descriptor inheritance. This means dup'ing
805 * descriptors 0-2 and making them available to the NaCl App.
807 * When standard input is inherited, this could result in a NaCl
808 * module competing for input from the terminal; for graphical /
809 * browser plugin environments, this never is allowed to happen, and
810 * having this is useful for debugging, and for potential standalone
811 * text-mode applications of NaCl.
813 * TODO(bsy): consider whether default inheritance should occur only
816 void NaClAppInitialDescriptorHookup(struct NaClApp *nap) {
818 NaClLog(4, "Processing I/O redirection/inheritance from environment\n");
819 nap->resource_phase = NACL_RESOURCE_PHASE_START;
820 NaClProcessRedirControl(nap);
821 NaClLog(4, "... done.\n");
824 void NaClCreateServiceSocket(struct NaClApp *nap) {
825 struct NaClDesc *secure_pair[2];
826 struct NaClDesc *pair[2];
828 NaClLog(3, "Entered NaClCreateServiceSocket\n");
830 if (NACL_FI_ERROR_COND("NaClCreateServiceSocket__secure_boundsock",
831 0 != NaClCommonDescMakeBoundSock(secure_pair))) {
832 NaClLog(LOG_FATAL, "Cound not create secure service socket\n");
835 "got bound socket at 0x%08"NACL_PRIxPTR", "
836 "addr at 0x%08"NACL_PRIxPTR"\n",
837 (uintptr_t) secure_pair[0],
838 (uintptr_t) secure_pair[1]);
840 NaClDescSafeUnref(nap->secure_service_port);
841 nap->secure_service_port = secure_pair[0];
843 NaClDescSafeUnref(nap->secure_service_address);
844 nap->secure_service_address = secure_pair[1];
846 if (NACL_FI_ERROR_COND("NaClCreateServiceSocket__boundsock",
847 0 != NaClCommonDescMakeBoundSock(pair))) {
848 NaClLog(LOG_FATAL, "Cound not create service socket\n");
851 "got bound socket at 0x%08"NACL_PRIxPTR", "
852 "addr at 0x%08"NACL_PRIxPTR"\n",
854 (uintptr_t) pair[1]);
855 NaClSetDesc(nap, NACL_SERVICE_PORT_DESCRIPTOR, pair[0]);
856 NaClSetDesc(nap, NACL_SERVICE_ADDRESS_DESCRIPTOR, pair[1]);
858 NaClDescSafeUnref(nap->service_port);
860 nap->service_port = pair[0];
861 NaClDescRef(nap->service_port);
863 NaClDescSafeUnref(nap->service_address);
865 nap->service_address = pair[1];
866 NaClDescRef(nap->service_address);
868 NaClLog(4, "Leaving NaClCreateServiceSocket\n");
872 * Import the |inherited_desc| descriptor as an IMC handle, save a
873 * reference to it at nap->bootstrap_channel, then send the
874 * service_address over that channel.
876 void NaClSetUpBootstrapChannel(struct NaClApp *nap,
877 NaClHandle inherited_desc) {
878 struct NaClDescImcDesc *channel;
879 struct NaClImcTypedMsgHdr hdr;
880 struct NaClDesc *descs[2];
884 "NaClSetUpBootstrapChannel(0x%08"NACL_PRIxPTR", %"NACL_PRIdPTR")\n",
886 (uintptr_t) inherited_desc);
888 channel = (struct NaClDescImcDesc *) malloc(sizeof *channel);
889 if (NULL == channel) {
890 NaClLog(LOG_FATAL, "NaClSetUpBootstrapChannel: no memory\n");
892 if (!NaClDescImcDescCtor(channel, inherited_desc)) {
894 ("NaClSetUpBootstrapChannel: cannot construct IMC descriptor"
895 " object for inherited descriptor %"NACL_PRIdPTR"\n"),
896 (uintptr_t) inherited_desc);
899 if (NULL == nap->secure_service_address) {
901 "NaClSetUpBootstrapChannel: secure service address not set\n");
904 if (NULL == nap->service_address) {
906 "NaClSetUpBootstrapChannel: service address not set\n");
910 * service_address and service_port are set together.
912 descs[0] = nap->secure_service_address;
913 descs[1] = nap->service_address;
915 hdr.iov = (struct NaClImcMsgIoVec *) NULL;
918 hdr.ndesc_length = NACL_ARRAY_SIZE(descs);
920 rv = (*NACL_VTBL(NaClDesc, channel)->SendMsg)((struct NaClDesc *) channel,
922 NaClXMutexLock(&nap->mu);
923 if (NULL != nap->bootstrap_channel) {
925 "NaClSetUpBootstrapChannel: cannot have two bootstrap channels\n");
927 nap->bootstrap_channel = (struct NaClDesc *) channel;
929 NaClXMutexUnlock(&nap->mu);
932 ("NaClSetUpBootstrapChannel: descriptor %"NACL_PRIdPTR
933 ", error %"NACL_PRIdS"\n"),
934 (uintptr_t) inherited_desc,
936 if (NACL_FI_ERROR_COND("NaClSetUpBootstrapChannel__SendMsg", 0 != rv)) {
938 "NaClSetUpBootstrapChannel: SendMsg failed, rv = %"NACL_PRIdS"\n",
943 NaClErrorCode NaClWaitForLoadModuleCommand(struct NaClApp *nap) {
944 NaClErrorCode status;
946 NaClLog(4, "NaClWaitForLoadModuleCommand started\n");
947 NaClXMutexLock(&nap->mu);
948 while (nap->module_initialization_state < NACL_MODULE_LOADED) {
949 NaClXCondVarWait(&nap->cv, &nap->mu);
951 status = nap->module_load_status;
952 NaClXMutexUnlock(&nap->mu);
953 NaClLog(4, "NaClWaitForLoadModuleCommand finished\n");
958 NaClErrorCode NaClWaitForLoadModuleStatus(struct NaClApp *nap) {
959 NaClErrorCode status;
961 NaClLog(4, "NaClWaitForLoadModuleStatus started\n");
962 NaClXMutexLock(&nap->mu);
963 while (LOAD_STATUS_UNKNOWN == (status = nap->module_load_status)) {
964 NaClXCondVarWait(&nap->cv, &nap->mu);
966 NaClXMutexUnlock(&nap->mu);
967 NaClLog(4, "NaClWaitForLoadModuleStatus finished\n");
972 NaClErrorCode NaClWaitForStartModuleCommand(struct NaClApp *nap) {
973 NaClErrorCode status;
975 NaClLog(4, "NaClWaitForStartModuleCommand started\n");
976 NaClXMutexLock(&nap->mu);
977 while (nap->module_initialization_state < NACL_MODULE_STARTED) {
978 NaClXCondVarWait(&nap->cv, &nap->mu);
980 status = nap->module_load_status;
981 NaClXMutexUnlock(&nap->mu);
982 NaClLog(4, "NaClWaitForStartModuleCommand finished\n");
987 void NaClBlockIfCommandChannelExists(struct NaClApp *nap) {
988 if (NULL != nap->secure_service) {
990 struct nacl_abi_timespec req;
993 NaClNanosleep(&req, (struct nacl_abi_timespec *) NULL);
998 void NaClSecureCommandChannel(struct NaClApp *nap) {
999 struct NaClSecureService *secure_command_server;
1001 NaClLog(4, "Entered NaClSecureCommandChannel\n");
1003 secure_command_server = (struct NaClSecureService *) malloc(
1004 sizeof *secure_command_server);
1005 if (NACL_FI_ERROR_COND("NaClSecureCommandChannel__malloc",
1006 NULL == secure_command_server)) {
1007 NaClLog(LOG_FATAL, "Out of memory for secure command channel\n");
1009 if (NACL_FI_ERROR_COND("NaClSecureCommandChannel__NaClSecureServiceCtor",
1010 !NaClSecureServiceCtor(secure_command_server,
1012 nap->secure_service_port,
1013 nap->secure_service_address))) {
1014 NaClLog(LOG_FATAL, "NaClSecureServiceCtor failed\n");
1016 nap->secure_service = secure_command_server;
1018 NaClLog(4, "NaClSecureCommandChannel: starting service thread\n");
1019 if (NACL_FI_ERROR_COND(
1020 "NaClSecureCommandChannel__NaClSimpleServiceStartServiceThread",
1021 !NaClSimpleServiceStartServiceThread((struct NaClSimpleService *)
1022 secure_command_server))) {
1024 "Could not start secure command channel service thread\n");
1027 NaClLog(4, "Leaving NaClSecureCommandChannel\n");
1030 void NaClAppLoadModule(struct NaClApp *nap,
1031 struct NaClDesc *nexe,
1032 void (*load_cb)(void *instance_data,
1033 NaClErrorCode status),
1034 void *instance_data) {
1035 NaClErrorCode status = LOAD_OK;
1038 ("Entered NaClAppLoadModule: nap 0x%"NACL_PRIxPTR","
1039 " nexe 0x%"NACL_PRIxPTR"\n"),
1040 (uintptr_t) nap, (uintptr_t) nexe);
1043 * TODO(bsy): consider doing the processing below after sending the
1044 * RPC reply to increase parallelism.
1046 NaClXMutexLock(&nap->mu);
1047 if (nap->module_initialization_state != NACL_MODULE_UNINITIALIZED) {
1048 NaClLog(LOG_ERROR, "NaClAppLoadModule: repeated invocation\n");
1049 status = LOAD_DUP_LOAD_MODULE;
1050 NaClXMutexUnlock(&nap->mu);
1051 if (NULL != load_cb) {
1052 (*load_cb)(instance_data, status);
1056 nap->module_initialization_state = NACL_MODULE_LOADING;
1057 NaClXCondVarBroadcast(&nap->cv);
1058 NaClXMutexUnlock(&nap->mu);
1060 if (NULL != load_cb) {
1061 (*load_cb)(instance_data, status);
1064 NaClXMutexLock(&nap->mu);
1067 * Check / Mark the nexe binary as OK to attempt memory mapping.
1069 * TODO(bsy): change needed to get NaClFileToken and resolve to file
1070 * path information, set NaClRichFileInfo, and stash via
1071 * NaClSetFileOriginInfo, then set NACL_DESC_FLAGS_MMAP_EXEC_OK.
1074 status = NACL_FI_VAL("load_module", NaClErrorCode,
1075 NaClAppLoadFile(nexe, nap));
1077 if (LOAD_OK != status) {
1078 nap->module_load_status = status;
1079 nap->module_initialization_state = NACL_MODULE_ERROR;
1080 NaClXCondVarBroadcast(&nap->cv);
1082 NaClXMutexUnlock(&nap->mu); /* NaClAppPrepareToLaunch takes mu */
1083 if (LOAD_OK != status) {
1087 /***************************************************************************
1088 * TODO(bsy): Remove/merge the code invoking NaClAppPrepareToLaunch
1089 * and NaClGdbHook below with sel_main's main function. See comment
1091 ***************************************************************************/
1094 * Finish setting up the NaCl App.
1096 status = NaClAppPrepareToLaunch(nap);
1098 NaClXMutexLock(&nap->mu);
1099 nap->module_load_status = status;
1100 nap->module_initialization_state = NACL_MODULE_LOADED;
1101 NaClXCondVarBroadcast(&nap->cv);
1102 NaClXMutexUnlock(&nap->mu);
1104 /* Give debuggers a well known point at which xlate_base is known. */
1108 int NaClAppRuntimeHostSetup(struct NaClApp *nap,
1109 struct NaClRuntimeHostInterface *host_itf) {
1110 NaClErrorCode status = LOAD_OK;
1113 ("Entered NaClAppRuntimeHostSetup, nap 0x%"NACL_PRIxPTR","
1114 " host_itf 0x%"NACL_PRIxPTR"\n"),
1115 (uintptr_t) nap, (uintptr_t) host_itf);
1117 NaClXMutexLock(&nap->mu);
1118 if (nap->module_initialization_state > NACL_MODULE_STARTING) {
1119 NaClLog(LOG_ERROR, "NaClAppRuntimeHostSetup: too late\n");
1120 status = LOAD_INTERNAL;
1121 goto cleanup_status_mu;
1124 nap->runtime_host_interface = (struct NaClRuntimeHostInterface *)
1125 NaClRefCountRef((struct NaClRefCount *) host_itf);
1128 * Hook up runtime host enabled resources, e.g.,
1129 * DEBUG_ONLY:dev://postmessage. NB: Resources specified by
1130 * file:path should have been taken care of earlier, in
1131 * NaClAppInitialDescriptorHookup.
1133 nap->resource_phase = NACL_RESOURCE_PHASE_RUNTIME_HOST;
1134 NaClLog(4, "Processing dev I/O redirection/inheritance from environment\n");
1135 NaClProcessRedirControl(nap);
1136 NaClLog(4, "... done.\n");
1139 NaClXMutexUnlock(&nap->mu);
1140 return (int) status;
1143 int NaClAppDescQuotaSetup(struct NaClApp *nap,
1144 struct NaClDescQuotaInterface *quota_itf) {
1145 NaClErrorCode status = LOAD_OK;
1148 ("Entered NaClAppDescQuotaSetup, nap 0x%"NACL_PRIxPTR","
1149 " quota_itf 0x%"NACL_PRIxPTR"\n"),
1150 (uintptr_t) nap, (uintptr_t) quota_itf);
1152 NaClXMutexLock(&nap->mu);
1153 if (nap->module_initialization_state > NACL_MODULE_STARTING) {
1154 NaClLog(LOG_ERROR, "NaClAppDescQuotaSetup: too late\n");
1155 status = LOAD_INTERNAL;
1156 goto cleanup_status_mu;
1159 nap->desc_quota_interface = (struct NaClDescQuotaInterface *)
1160 NaClRefCountRef((struct NaClRefCount *) quota_itf);
1163 NaClXMutexUnlock(&nap->mu);
1164 return (int) status;
1167 void NaClAppStartModule(struct NaClApp *nap,
1168 void (*start_cb)(void *instance_data,
1169 NaClErrorCode status),
1170 void *instance_data) {
1171 NaClErrorCode status;
1174 ("Entered NaClAppStartModule, nap 0x%"NACL_PRIxPTR","
1175 " start_cb 0x%"NACL_PRIxPTR", instance_data 0x%"NACL_PRIxPTR"\n"),
1176 (uintptr_t) nap, (uintptr_t) start_cb, (uintptr_t) instance_data);
1179 * When module is loading, we have to block and wait till it is
1180 * fully loaded before we can proceed with start module.
1182 NaClXMutexLock(&nap->mu);
1183 if (NACL_MODULE_LOADING == nap->module_initialization_state) {
1184 while (NACL_MODULE_LOADED != nap->module_initialization_state) {
1185 NaClXCondVarWait(&nap->cv, &nap->mu);
1188 if (nap->module_initialization_state != NACL_MODULE_LOADED) {
1189 if (NACL_MODULE_ERROR == nap->module_initialization_state) {
1190 NaClLog(LOG_ERROR, "NaClAppStartModule: error loading module\n");
1191 status = nap->module_load_status;
1192 } else if (nap->module_initialization_state > NACL_MODULE_LOADED) {
1193 NaClLog(LOG_ERROR, "NaClAppStartModule: repeated invocation\n");
1194 status = LOAD_DUP_START_MODULE;
1195 } else if (nap->module_initialization_state < NACL_MODULE_LOADED) {
1196 NaClLog(LOG_ERROR, "NaClAppStartModule: module not loaded\n");
1197 status = LOAD_INTERNAL;
1199 NaClXMutexUnlock(&nap->mu);
1200 if (NULL != start_cb) {
1201 (*start_cb)(instance_data, status);
1205 status = nap->module_load_status;
1206 nap->module_initialization_state = NACL_MODULE_STARTING;
1207 NaClXCondVarBroadcast(&nap->cv);
1208 NaClXMutexUnlock(&nap->mu);
1210 NaClLog(4, "NaClSecureChannelStartModule: load status %d\n", status);
1213 * We need to invoke the callback now, before we signal the main thread
1214 * to possibly start by setting the state to NACL_MODULE_STARTED, since
1215 * in the case of failure the main thread may quickly exit; if the main
1216 * thread does this before we sent the reply, than the plugin (or any
1217 * other runtime host interface) will be left without an aswer. The
1218 * NACL_MODULE_STARTING state is used as an intermediate state to prevent
1219 * double invocations violating the protocol.
1221 if (NULL != start_cb) {
1222 (*start_cb)(instance_data, status);
1225 NaClXMutexLock(&nap->mu);
1226 nap->module_initialization_state = NACL_MODULE_STARTED;
1227 NaClXCondVarBroadcast(&nap->cv);
1228 NaClXMutexUnlock(&nap->mu);
1231 void NaClAppShutdown(struct NaClApp *nap,
1233 NaClLog(4, "NaClAppShutdown: nap 0x%"NACL_PRIxPTR
1234 ", exit_status %d\n", (uintptr_t) nap, exit_status);
1236 NaClXMutexLock(&nap->mu);
1237 nap->exit_status = exit_status;
1238 NaClXMutexUnlock(&nap->mu);
1239 if (NULL != nap->debug_stub_callbacks) {
1240 nap->debug_stub_callbacks->process_exit_hook();
1246 * It is fine to have multiple I/O operations read from memory in Write
1247 * or SendMsg like operations.
1249 void NaClVmIoWillStart(struct NaClApp *nap,
1250 uint32_t addr_first_usr,
1251 uint32_t addr_last_usr) {
1252 NaClXMutexLock(&nap->mu);
1253 (*nap->mem_io_regions->vtbl->AddInterval)(nap->mem_io_regions,
1256 NaClXMutexUnlock(&nap->mu);
1260 void NaClVmIoHasEnded(struct NaClApp *nap,
1261 uint32_t addr_first_usr,
1262 uint32_t addr_last_usr) {
1263 NaClXMutexLock(&nap->mu);
1264 (*nap->mem_io_regions->vtbl->RemoveInterval)(nap->mem_io_regions,
1267 NaClXMutexUnlock(&nap->mu);
1270 void NaClVmIoPendingCheck_mu(struct NaClApp *nap,
1271 uint32_t addr_first_usr,
1272 uint32_t addr_last_usr) {
1273 if ((*nap->mem_io_regions->vtbl->OverlapsWith)(nap->mem_io_regions,
1277 "NaClVmIoWillStart: program mem write race detected. ABORTING\n");
1282 * GDB's canonical overlay managment routine.
1283 * We need its symbol in the symbol table so don't inline it.
1284 * TODO(dje): add some explanation for the non-GDB person.
1287 __declspec(dllexport noinline)
1290 __attribute__((noinline))
1292 void _ovly_debug_event (void) {
1295 * The asm volatile is here as instructed by the GCC docs.
1296 * It's not enough to declare a function noinline.
1297 * GCC will still look inside the function to see if it's worth calling.
1299 __asm__ volatile ("");
1302 * Visual Studio inlines empty functions even with noinline attribute,
1303 * so we need a compile memory barrier to make this function not to be
1304 * inlined. Also, it guarantees that nacl_global_xlate_base initialization
1305 * is not reordered. This is important for gdb since it sets breakpoint on
1306 * this function and reads nacl_global_xlate_base value.
1308 _ReadWriteBarrier();
1312 static void StopForDebuggerInit (uintptr_t mem_start) {
1313 /* Put xlate_base in a place where gdb can find it. */
1314 nacl_global_xlate_base = mem_start;
1316 NaClSandboxMemoryStartForValgrind(mem_start);
1318 _ovly_debug_event();
1321 void NaClGdbHook(struct NaClApp const *nap) {
1322 StopForDebuggerInit(nap->mem_start);