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;
100 #if (NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 \
101 && NACL_BUILD_SUBARCH == 32)
102 nap->pcrel_thunk = 0;
103 nap->pcrel_thunk_end = 0;
105 #if (NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 \
106 && NACL_BUILD_SUBARCH == 64)
107 nap->nacl_syscall_addr = 0;
108 nap->get_tls_fast_path1_addr = 0;
109 nap->get_tls_fast_path2_addr = 0;
112 nap->static_text_end = 0;
113 nap->dynamic_text_start = 0;
114 nap->dynamic_text_end = 0;
115 nap->rodata_start = 0;
119 nap->initial_entry_pt = 0;
120 nap->user_entry_pt = 0;
122 if (!DynArrayCtor(&nap->threads, 2)) {
123 goto cleanup_cpu_features;
125 if (!DynArrayCtor(&nap->desc_tbl, 2)) {
126 goto cleanup_threads;
128 if (!NaClVmmapCtor(&nap->mem_map)) {
129 goto cleanup_desc_tbl;
132 nap->mem_io_regions = (struct NaClIntervalMultiset *) malloc(
133 sizeof(struct NaClIntervalRangeTree));
134 if (NULL == nap->mem_io_regions) {
135 goto cleanup_mem_map;
138 if (!NaClIntervalRangeTreeCtor((struct NaClIntervalRangeTree *)
139 nap->mem_io_regions)) {
140 free(nap->mem_io_regions);
141 nap->mem_io_regions = NULL;
142 goto cleanup_mem_map;
145 effp = (struct NaClDescEffectorLdr *) malloc(sizeof *effp);
147 goto cleanup_mem_io_regions;
149 if (!NaClDescEffectorLdrCtor(effp, nap)) {
150 goto cleanup_effp_free;
152 nap->effp = (struct NaClDescEffector *) effp;
154 nap->enable_dyncode_syscalls = ShouldEnableDyncodeSyscalls();
155 nap->use_shm_for_dynamic_text = ShouldEnableDynamicLoading();
156 nap->text_shm = NULL;
157 if (!NaClMutexCtor(&nap->dynamic_load_mutex)) {
158 goto cleanup_effp_free;
160 nap->dynamic_page_bitmap = NULL;
162 nap->dynamic_regions = NULL;
163 nap->num_dynamic_regions = 0;
164 nap->dynamic_regions_allocated = 0;
165 nap->dynamic_delete_generation = 0;
167 nap->dynamic_mapcache_offset = 0;
168 nap->dynamic_mapcache_size = 0;
169 nap->dynamic_mapcache_ret = 0;
171 nap->service_port = NULL;
172 nap->service_address = NULL;
173 nap->secure_service_port = NULL;
174 nap->secure_service_address = NULL;
175 nap->bootstrap_channel = NULL;
176 nap->secure_service = NULL;
178 nap->main_exe_prevalidated = 0;
180 nap->kernel_service = NULL;
181 nap->resource_phase = NACL_RESOURCE_PHASE_START;
182 if (!NaClResourceNaClAppInit(&nap->resources, nap)) {
183 goto cleanup_dynamic_load_mutex;
186 if (!NaClMutexCtor(&nap->mu)) {
187 goto cleanup_dynamic_load_mutex;
189 if (!NaClCondVarCtor(&nap->cv)) {
194 nap->vm_hole_may_exist = 0;
195 nap->threads_launching = 0;
198 nap->syscall_table = table;
200 nap->runtime_host_interface = NULL;
201 nap->desc_quota_interface = NULL;
203 nap->module_initialization_state = NACL_MODULE_UNINITIALIZED;
204 nap->module_load_status = LOAD_STATUS_UNKNOWN;
206 nap->name_service = (struct NaClNameService *) malloc(
207 sizeof *nap->name_service);
208 if (NULL == nap->name_service) {
211 if (!NaClNameServiceCtor(nap->name_service,
212 NaClAddrSpSquattingThreadIfFactoryFunction,
214 free(nap->name_service);
217 nap->name_service_conn_cap = NaClDescRef(nap->name_service->
218 base.base.bound_and_cap[1]);
219 if (!NaClDefaultNameServiceInit(nap->name_service)) {
220 goto cleanup_name_service;
223 nap->ignore_validator_result = 0;
224 nap->skip_validator = 0;
225 nap->validator_stub_out_mode = 0;
227 if (IsEnvironmentVariableSet("NACL_DANGEROUS_ENABLE_FILE_ACCESS")) {
228 NaClInsecurelyBypassAllAclChecks();
229 NaClLog(LOG_INFO, "DANGER: ENABLED FILE ACCESS\n");
232 nap->enable_list_mappings = 0;
233 if (IsEnvironmentVariableSet("NACL_DANGEROUS_ENABLE_LIST_MAPPINGS")) {
235 * This syscall is not actually know to be dangerous, but is not yet
236 * exposed by our public API.
238 NaClLog(LOG_INFO, "DANGER: ENABLED LIST_MAPPINGS\n");
239 nap->enable_list_mappings = 1;
242 if (!NaClMutexCtor(&nap->threads_mu)) {
243 goto cleanup_name_service;
245 nap->num_threads = 0;
246 if (!NaClFastMutexCtor(&nap->desc_mu)) {
247 goto cleanup_threads_mu;
251 nap->exit_status = -1;
253 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
254 nap->code_seg_sel = 0;
255 nap->data_seg_sel = 0;
258 nap->debug_stub_callbacks = NULL;
259 nap->exception_handler = 0;
260 if (!NaClMutexCtor(&nap->exception_mu)) {
261 goto cleanup_desc_mu;
263 nap->enable_exception_handling = 0;
265 nap->debug_exception_handler_state = NACL_DEBUG_EXCEPTION_HANDLER_NOT_STARTED;
266 nap->attach_debug_exception_handler_func = NULL;
268 nap->enable_faulted_thread_queue = 0;
269 nap->faulted_thread_count = 0;
271 nap->faulted_thread_event = INVALID_HANDLE_VALUE;
273 nap->faulted_thread_fd_read = -1;
274 nap->faulted_thread_fd_write = -1;
278 #if NACL_LINUX || NACL_OSX
280 * Try to pre-cache information that we can't obtain with the outer
281 * sandbox on. If the outer sandbox has already been enabled, this
282 * will just set sc_nprocessors_onln to -1, and it is the
283 * responsibility of the caller to replace this with a sane value
284 * after the Ctor returns.
286 nap->sc_nprocessors_onln = sysconf(_SC_NPROCESSORS_ONLN);
289 if (!NaClMutexCtor(&nap->futex_wait_list_mu)) {
290 goto cleanup_exception_mu;
292 nap->futex_wait_list_head.next = &nap->futex_wait_list_head;
293 nap->futex_wait_list_head.prev = &nap->futex_wait_list_head;
297 cleanup_exception_mu:
298 NaClMutexDtor(&nap->exception_mu);
300 NaClFastMutexDtor(&nap->desc_mu);
302 NaClMutexDtor(&nap->threads_mu);
303 cleanup_name_service:
304 NaClDescUnref(nap->name_service_conn_cap);
305 NaClRefCountUnref((struct NaClRefCount *) nap->name_service);
307 NaClCondVarDtor(&nap->cv);
309 NaClMutexDtor(&nap->mu);
310 cleanup_dynamic_load_mutex:
311 NaClMutexDtor(&nap->dynamic_load_mutex);
314 cleanup_mem_io_regions:
315 NaClIntervalMultisetDelete(nap->mem_io_regions);
316 nap->mem_io_regions = NULL;
318 NaClVmmapDtor(&nap->mem_map);
320 DynArrayDtor(&nap->desc_tbl);
322 DynArrayDtor(&nap->threads);
323 cleanup_cpu_features:
324 free(nap->cpu_features);
329 int NaClAppCtor(struct NaClApp *nap) {
330 return NaClAppWithSyscallTableCtor(nap, nacl_syscall);
334 * unaligned little-endian load. precondition: nbytes should never be
337 static uint64_t NaClLoadMem(uintptr_t addr,
338 size_t user_nbytes) {
341 CHECK(0 != user_nbytes && user_nbytes <= 8);
345 value |= ((uint8_t *) addr)[--user_nbytes];
346 } while (user_nbytes > 0);
350 #define GENERIC_LOAD(bits) \
351 static uint ## bits ## _t NaClLoad ## bits(uintptr_t addr) { \
352 return (uint ## bits ## _t) NaClLoadMem(addr, sizeof(uint ## bits ## _t)); \
355 #if NACL_TARGET_SUBARCH == 32
363 * unaligned little-endian store
365 static void NaClStoreMem(uintptr_t addr,
372 for (i = 0; i < nbytes; ++i) {
373 ((uint8_t *) addr)[i] = (uint8_t) value;
378 #define GENERIC_STORE(bits) \
379 static void NaClStore ## bits(uintptr_t addr, \
380 uint ## bits ## _t v) { \
381 NaClStoreMem(addr, sizeof(uint ## bits ## _t), v); \
390 struct NaClPatchInfo *NaClPatchInfoCtor(struct NaClPatchInfo *self) {
392 memset(self, 0, sizeof *self);
398 * This function is called by NaClLoadTrampoline and NaClLoadSpringboard to
399 * patch a single memory location specified in NaClPatchInfo structure.
401 void NaClApplyPatchToMemory(struct NaClPatchInfo *patch) {
405 uintptr_t target_addr;
407 memcpy((void *) patch->dst, (void *) patch->src, patch->nbytes);
409 reloc = patch->dst - patch->src;
412 for (i = 0; i < patch->num_abs64; ++i) {
413 offset = patch->abs64[i].target - patch->src;
414 target_addr = patch->dst + offset;
415 NaClStore64(target_addr, patch->abs64[i].value);
418 for (i = 0; i < patch->num_abs32; ++i) {
419 offset = patch->abs32[i].target - patch->src;
420 target_addr = patch->dst + offset;
421 NaClStore32(target_addr, (uint32_t) patch->abs32[i].value);
424 for (i = 0; i < patch->num_abs16; ++i) {
425 offset = patch->abs16[i].target - patch->src;
426 target_addr = patch->dst + offset;
427 NaClStore16(target_addr, (uint16_t) patch->abs16[i].value);
430 for (i = 0; i < patch->num_rel64; ++i) {
431 offset = patch->rel64[i] - patch->src;
432 target_addr = patch->dst + offset;
433 NaClStore64(target_addr, NaClLoad64(target_addr) - reloc);
437 * rel32 is only supported on 32-bit architectures. The range of a relative
438 * relocation in untrusted space is +/- 4GB. This can be represented as
439 * an unsigned 32-bit value mod 2^32, which is handy on a 32 bit system since
440 * all 32-bit pointer arithmetic is implicitly mod 2^32. On a 64 bit system,
441 * however, pointer arithmetic is implicitly modulo 2^64, which isn't as
442 * helpful for our purposes. We could simulate the 32-bit behavior by
443 * explicitly modding all relative addresses by 2^32, but that seems like an
444 * expensive way to save a few bytes per reloc.
446 #if NACL_TARGET_SUBARCH == 32
447 for (i = 0; i < patch->num_rel32; ++i) {
448 offset = patch->rel32[i] - patch->src;
449 target_addr = patch->dst + offset;
450 NaClStore32(target_addr,
451 (uint32_t) NaClLoad32(target_addr) - (int32_t) reloc);
458 * Install syscall trampolines at all possible well-formed entry
459 * points within the trampoline pages. Many of these syscalls will
460 * correspond to unimplemented system calls and will just abort the
463 void NaClLoadTrampoline(struct NaClApp *nap) {
468 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
469 if (!NaClMakePcrelThunk(nap)) {
470 NaClLog(LOG_FATAL, "NaClMakePcrelThunk failed!\n");
473 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64
474 if (!NaClMakeDispatchAddrs(nap)) {
475 NaClLog(LOG_FATAL, "NaClMakeDispatchAddrs failed!\n");
478 NaClFillTrampolineRegion(nap);
481 * Do not bother to fill in the contents of page 0, since we make it
482 * inaccessible later (see sel_addrspace.c, NaClMemoryProtection)
483 * anyway to help detect NULL pointer errors, and we might as well
484 * not dirty the page.
486 * The last syscall entry point is used for springboard code.
488 num_syscalls = ((NACL_TRAMPOLINE_END - NACL_SYSCALL_START_ADDR)
489 / NACL_SYSCALL_BLOCK_SIZE) - 1;
491 NaClLog(2, "num_syscalls = %d (0x%x)\n", num_syscalls, num_syscalls);
493 #if defined(NACL_TARGET_ARM_THUMB2_MODE)
494 CHECK(0 != ((nap->user_entry_pt | nap->initial_entry_pt) & 0x1));
496 * Thumb trampolines start 2 bytes before the aligned syscall address used
497 * by ordinary ARM. We initialize this by adding 0xe to the start address
498 * of each trampoline. Because the last start address would actually start
499 * into user code above, this allows one fewer trampolines than in ARM.
501 for (i = 0, addr = nap->mem_start + NACL_SYSCALL_START_ADDR + 0xe;
502 i < num_syscalls - 1;
503 ++i, addr += NACL_SYSCALL_BLOCK_SIZE) {
504 NaClPatchOneTrampoline(nap, addr);
507 for (i = 0, addr = nap->mem_start + NACL_SYSCALL_START_ADDR;
509 ++i, addr += NACL_SYSCALL_BLOCK_SIZE) {
510 NaClPatchOneTrampoline(nap, addr);
513 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64
514 NaClPatchOneTrampolineCall(nap->get_tls_fast_path1_addr,
515 nap->mem_start + NACL_SYSCALL_START_ADDR
516 + NACL_SYSCALL_BLOCK_SIZE * NACL_sys_tls_get);
517 NaClPatchOneTrampolineCall(nap->get_tls_fast_path2_addr,
518 nap->mem_start + NACL_SYSCALL_START_ADDR
519 + (NACL_SYSCALL_BLOCK_SIZE *
520 NACL_sys_second_tls_get));
523 NACL_TEST_INJECTION(ChangeTrampolines, (nap));
526 void NaClMemRegionPrinter(void *state,
527 struct NaClVmmapEntry *entry) {
528 struct Gio *gp = (struct Gio *) state;
530 gprintf(gp, "\nPage %"NACL_PRIdPTR" (0x%"NACL_PRIxPTR")\n",
531 entry->page_num, entry->page_num);
532 gprintf(gp, "npages %"NACL_PRIdS" (0x%"NACL_PRIxS")\n", entry->npages,
534 gprintf(gp, "start vaddr 0x%"NACL_PRIxPTR"\n",
535 entry->page_num << NACL_PAGESHIFT);
536 gprintf(gp, "end vaddr 0x%"NACL_PRIxPTR"\n",
537 (entry->page_num + entry->npages) << NACL_PAGESHIFT);
538 gprintf(gp, "prot 0x%08x\n", entry->prot);
539 gprintf(gp, "%sshared/backed by a file\n",
540 (NULL == entry->desc) ? "not " : "");
543 void NaClAppPrintDetails(struct NaClApp *nap,
545 NaClXMutexLock(&nap->mu);
547 "NaClAppPrintDetails((struct NaClApp *) 0x%08"NACL_PRIxPTR","
548 "(struct Gio *) 0x%08"NACL_PRIxPTR")\n", (uintptr_t) nap,
550 gprintf(gp, "addr space size: 2**%"NACL_PRId32"\n", nap->addr_bits);
551 gprintf(gp, "stack size: 0x%08"NACL_PRIx32"\n", nap->stack_size);
553 gprintf(gp, "mem start addr: 0x%08"NACL_PRIxPTR"\n", nap->mem_start);
554 /* 123456789012345678901234567890 */
556 gprintf(gp, "static_text_end: 0x%08"NACL_PRIxPTR"\n", nap->static_text_end);
557 gprintf(gp, "end-of-text: 0x%08"NACL_PRIxPTR"\n",
558 NaClEndOfStaticText(nap));
559 gprintf(gp, "rodata: 0x%08"NACL_PRIxPTR"\n", nap->rodata_start);
560 gprintf(gp, "data: 0x%08"NACL_PRIxPTR"\n", nap->data_start);
561 gprintf(gp, "data_end: 0x%08"NACL_PRIxPTR"\n", nap->data_end);
562 gprintf(gp, "break_addr: 0x%08"NACL_PRIxPTR"\n", nap->break_addr);
564 gprintf(gp, "ELF initial entry point: 0x%08x\n", nap->initial_entry_pt);
565 gprintf(gp, "ELF user entry point: 0x%08x\n", nap->user_entry_pt);
566 gprintf(gp, "memory map:\n");
567 NaClVmmapVisit(&nap->mem_map,
568 NaClMemRegionPrinter,
570 NaClXMutexUnlock(&nap->mu);
573 struct NaClDesc *NaClGetDescMu(struct NaClApp *nap,
575 struct NaClDesc *result;
577 result = (struct NaClDesc *) DynArrayGet(&nap->desc_tbl, d);
578 if (NULL != result) {
585 void NaClSetDescMu(struct NaClApp *nap,
587 struct NaClDesc *ndp) {
588 struct NaClDesc *result;
590 result = (struct NaClDesc *) DynArrayGet(&nap->desc_tbl, d);
591 NaClDescSafeUnref(result);
593 if (!DynArraySet(&nap->desc_tbl, d, ndp)) {
595 "NaClSetDesc: could not set descriptor %d to 0x%08"
602 int32_t NaClSetAvailMu(struct NaClApp *nap,
603 struct NaClDesc *ndp) {
606 pos = DynArrayFirstAvail(&nap->desc_tbl);
608 if (pos > INT32_MAX) {
610 ("NaClSetAvailMu: DynArrayFirstAvail returned a value"
611 " that is greather than 2**31-1.\n"));
614 NaClSetDescMu(nap, (int) pos, ndp);
616 return (int32_t) pos;
619 struct NaClDesc *NaClGetDesc(struct NaClApp *nap,
621 struct NaClDesc *res;
623 NaClFastMutexLock(&nap->desc_mu);
624 res = NaClGetDescMu(nap, d);
625 NaClFastMutexUnlock(&nap->desc_mu);
629 void NaClSetDesc(struct NaClApp *nap,
631 struct NaClDesc *ndp) {
632 NaClFastMutexLock(&nap->desc_mu);
633 NaClSetDescMu(nap, d, ndp);
634 NaClFastMutexUnlock(&nap->desc_mu);
637 int32_t NaClSetAvail(struct NaClApp *nap,
638 struct NaClDesc *ndp) {
641 NaClFastMutexLock(&nap->desc_mu);
642 pos = NaClSetAvailMu(nap, ndp);
643 NaClFastMutexUnlock(&nap->desc_mu);
648 int NaClAddThreadMu(struct NaClApp *nap,
649 struct NaClAppThread *natp) {
652 pos = DynArrayFirstAvail(&nap->threads);
654 if (!DynArraySet(&nap->threads, pos, natp)) {
656 "NaClAddThreadMu: DynArraySet at position %"NACL_PRIuS" failed\n",
663 int NaClAddThread(struct NaClApp *nap,
664 struct NaClAppThread *natp) {
667 NaClXMutexLock(&nap->threads_mu);
668 pos = NaClAddThreadMu(nap, natp);
669 NaClXMutexUnlock(&nap->threads_mu);
674 void NaClRemoveThreadMu(struct NaClApp *nap,
676 if (NULL == DynArrayGet(&nap->threads, thread_num)) {
678 "NaClRemoveThreadMu:: thread to be removed is not in the table\n");
680 if (nap->num_threads == 0) {
682 "NaClRemoveThreadMu:: num_threads cannot be 0!!!\n");
685 if (!DynArraySet(&nap->threads, thread_num, (struct NaClAppThread *) NULL)) {
687 "NaClRemoveThreadMu:: DynArraySet at position %d failed\n",
692 void NaClRemoveThread(struct NaClApp *nap,
694 NaClXMutexLock(&nap->threads_mu);
695 NaClRemoveThreadMu(nap, thread_num);
696 NaClXMutexUnlock(&nap->threads_mu);
699 struct NaClAppThread *NaClGetThreadMu(struct NaClApp *nap,
701 return (struct NaClAppThread *) DynArrayGet(&nap->threads, thread_num);
704 void NaClAddHostDescriptor(struct NaClApp *nap,
708 struct NaClDescIoDesc *dp;
711 "NaClAddHostDescriptor: host %d as nacl desc %d, flag 0x%x\n",
715 dp = NaClDescIoDescMake(NaClHostDescPosixMake(host_os_desc, flag));
717 NaClLog(LOG_FATAL, "NaClAddHostDescriptor: NaClDescIoDescMake failed\n");
719 NaClSetDesc(nap, nacl_desc, (struct NaClDesc *) dp);
722 void NaClAddImcHandle(struct NaClApp *nap,
725 struct NaClDescImcDesc *dp;
728 ("NaClAddImcHandle: importing NaClHandle %"NACL_PRIxPTR
729 " as nacl desc %d\n"),
732 dp = (struct NaClDescImcDesc *) malloc(sizeof *dp);
733 if (NACL_FI_ERROR_COND("NaClAddImcHandle__malloc", NULL == dp)) {
734 NaClLog(LOG_FATAL, "NaClAddImcHandle: no memory\n");
736 if (NACL_FI_ERROR_COND("NaClAddImcHandle__ctor",
737 !NaClDescImcDescCtor(dp, h))) {
738 NaClLog(LOG_FATAL, ("NaClAddImcHandle: cannot construct"
739 " IMC descriptor object\n"));
741 NaClSetDesc(nap, nacl_desc, (struct NaClDesc *) dp);
747 char const *env_name;
750 } const g_nacl_redir_control[] = {
751 { 0, "NACL_EXE_STDIN",
752 NACL_ABI_O_RDONLY, 0, },
753 { 1, "NACL_EXE_STDOUT",
754 NACL_ABI_O_WRONLY | NACL_ABI_O_APPEND | NACL_ABI_O_CREAT, 0777, },
755 { 2, "NACL_EXE_STDERR",
756 NACL_ABI_O_WRONLY | NACL_ABI_O_APPEND | NACL_ABI_O_CREAT, 0777, },
760 * File redirection is impossible if an outer sandbox is in place.
761 * For the command-line embedding, we sometimes have an outer sandbox:
762 * on OSX, it is enabled after loading the file is loaded. On the
763 * other hand, device redirection (DEBUG_ONLY:dev://postmessage) is
764 * impossible until the reverse channel setup has occurred.
766 * Because of this, we run NaClProcessRedirControl twice: once to
767 * process default inheritance, file redirection early on, and once
768 * after the reverse channel is in place to handle the device
769 * redirection. We try to hide knowledge about which redirection
770 * control values can be handled in which phases by allowing the
771 * NaClResourceOpen to fail, and only in the last phase do we check
772 * that the redirection succeeded in *some* phase.
774 static void NaClProcessRedirControl(struct NaClApp *nap) {
778 struct NaClDesc *ndp;
780 for (ix = 0; ix < NACL_ARRAY_SIZE(g_nacl_redir_control); ++ix) {
782 if (NULL != (env = getenv(g_nacl_redir_control[ix].env_name))) {
783 NaClLog(4, "getenv(%s) -> %s\n", g_nacl_redir_control[ix].env_name, env);
784 ndp = NaClResourceOpen((struct NaClResource *) &nap->resources,
786 g_nacl_redir_control[ix].nacl_flags,
787 g_nacl_redir_control[ix].mode);
788 NaClLog(4, " NaClResourceOpen returned %"NACL_PRIxPTR"\n",
793 NaClLog(4, "Setting descriptor %d\n", (int) ix);
794 NaClSetDesc(nap, (int) ix, ndp);
795 } else if (NACL_RESOURCE_PHASE_START == nap->resource_phase) {
797 * Environment not set or redirect failed -- handle default inheritance.
799 NaClAddHostDescriptor(nap, DUP(g_nacl_redir_control[ix].d),
800 g_nacl_redir_control[ix].nacl_flags, (int) ix);
806 * Process default descriptor inheritance. This means dup'ing
807 * descriptors 0-2 and making them available to the NaCl App.
809 * When standard input is inherited, this could result in a NaCl
810 * module competing for input from the terminal; for graphical /
811 * browser plugin environments, this never is allowed to happen, and
812 * having this is useful for debugging, and for potential standalone
813 * text-mode applications of NaCl.
815 * TODO(bsy): consider whether default inheritance should occur only
818 void NaClAppInitialDescriptorHookup(struct NaClApp *nap) {
820 NaClLog(4, "Processing I/O redirection/inheritance from environment\n");
821 nap->resource_phase = NACL_RESOURCE_PHASE_START;
822 NaClProcessRedirControl(nap);
823 NaClLog(4, "... done.\n");
826 void NaClCreateServiceSocket(struct NaClApp *nap) {
827 struct NaClDesc *secure_pair[2];
828 struct NaClDesc *pair[2];
830 NaClLog(3, "Entered NaClCreateServiceSocket\n");
832 if (NACL_FI_ERROR_COND("NaClCreateServiceSocket__secure_boundsock",
833 0 != NaClCommonDescMakeBoundSock(secure_pair))) {
834 NaClLog(LOG_FATAL, "Cound not create secure service socket\n");
837 "got bound socket at 0x%08"NACL_PRIxPTR", "
838 "addr at 0x%08"NACL_PRIxPTR"\n",
839 (uintptr_t) secure_pair[0],
840 (uintptr_t) secure_pair[1]);
842 NaClDescSafeUnref(nap->secure_service_port);
843 nap->secure_service_port = secure_pair[0];
845 NaClDescSafeUnref(nap->secure_service_address);
846 nap->secure_service_address = secure_pair[1];
848 if (NACL_FI_ERROR_COND("NaClCreateServiceSocket__boundsock",
849 0 != NaClCommonDescMakeBoundSock(pair))) {
850 NaClLog(LOG_FATAL, "Cound not create service socket\n");
853 "got bound socket at 0x%08"NACL_PRIxPTR", "
854 "addr at 0x%08"NACL_PRIxPTR"\n",
856 (uintptr_t) pair[1]);
857 NaClSetDesc(nap, NACL_SERVICE_PORT_DESCRIPTOR, pair[0]);
858 NaClSetDesc(nap, NACL_SERVICE_ADDRESS_DESCRIPTOR, pair[1]);
860 NaClDescSafeUnref(nap->service_port);
862 nap->service_port = pair[0];
863 NaClDescRef(nap->service_port);
865 NaClDescSafeUnref(nap->service_address);
867 nap->service_address = pair[1];
868 NaClDescRef(nap->service_address);
870 NaClLog(4, "Leaving NaClCreateServiceSocket\n");
874 * Import the |inherited_desc| descriptor as an IMC handle, save a
875 * reference to it at nap->bootstrap_channel, then send the
876 * service_address over that channel.
878 void NaClSetUpBootstrapChannel(struct NaClApp *nap,
879 NaClHandle inherited_desc) {
880 struct NaClDescImcDesc *channel;
881 struct NaClImcTypedMsgHdr hdr;
882 struct NaClDesc *descs[2];
886 "NaClSetUpBootstrapChannel(0x%08"NACL_PRIxPTR", %"NACL_PRIdPTR")\n",
888 (uintptr_t) inherited_desc);
890 channel = (struct NaClDescImcDesc *) malloc(sizeof *channel);
891 if (NULL == channel) {
892 NaClLog(LOG_FATAL, "NaClSetUpBootstrapChannel: no memory\n");
894 if (!NaClDescImcDescCtor(channel, inherited_desc)) {
896 ("NaClSetUpBootstrapChannel: cannot construct IMC descriptor"
897 " object for inherited descriptor %"NACL_PRIdPTR"\n"),
898 (uintptr_t) inherited_desc);
901 if (NULL == nap->secure_service_address) {
903 "NaClSetUpBootstrapChannel: secure service address not set\n");
906 if (NULL == nap->service_address) {
908 "NaClSetUpBootstrapChannel: service address not set\n");
912 * service_address and service_port are set together.
914 descs[0] = nap->secure_service_address;
915 descs[1] = nap->service_address;
917 hdr.iov = (struct NaClImcMsgIoVec *) NULL;
920 hdr.ndesc_length = NACL_ARRAY_SIZE(descs);
922 rv = (*NACL_VTBL(NaClDesc, channel)->SendMsg)((struct NaClDesc *) channel,
924 NaClXMutexLock(&nap->mu);
925 if (NULL != nap->bootstrap_channel) {
927 "NaClSetUpBootstrapChannel: cannot have two bootstrap channels\n");
929 nap->bootstrap_channel = (struct NaClDesc *) channel;
931 NaClXMutexUnlock(&nap->mu);
934 ("NaClSetUpBootstrapChannel: descriptor %"NACL_PRIdPTR
935 ", error %"NACL_PRIdS"\n"),
936 (uintptr_t) inherited_desc,
938 if (NACL_FI_ERROR_COND("NaClSetUpBootstrapChannel__SendMsg", 0 != rv)) {
940 "NaClSetUpBootstrapChannel: SendMsg failed, rv = %"NACL_PRIdS"\n",
945 NaClErrorCode NaClWaitForLoadModuleCommand(struct NaClApp *nap) {
946 NaClErrorCode status;
948 NaClLog(4, "NaClWaitForLoadModuleCommand started\n");
949 NaClXMutexLock(&nap->mu);
950 while (nap->module_initialization_state < NACL_MODULE_LOADED) {
951 NaClXCondVarWait(&nap->cv, &nap->mu);
953 status = nap->module_load_status;
954 NaClXMutexUnlock(&nap->mu);
955 NaClLog(4, "NaClWaitForLoadModuleCommand finished\n");
960 NaClErrorCode NaClWaitForLoadModuleStatus(struct NaClApp *nap) {
961 NaClErrorCode status;
963 NaClLog(4, "NaClWaitForLoadModuleStatus started\n");
964 NaClXMutexLock(&nap->mu);
965 while (LOAD_STATUS_UNKNOWN == (status = nap->module_load_status)) {
966 NaClXCondVarWait(&nap->cv, &nap->mu);
968 NaClXMutexUnlock(&nap->mu);
969 NaClLog(4, "NaClWaitForLoadModuleStatus finished\n");
974 NaClErrorCode NaClWaitForStartModuleCommand(struct NaClApp *nap) {
975 NaClErrorCode status;
977 NaClLog(4, "NaClWaitForStartModuleCommand started\n");
978 NaClXMutexLock(&nap->mu);
979 while (nap->module_initialization_state < NACL_MODULE_STARTED) {
980 NaClXCondVarWait(&nap->cv, &nap->mu);
982 status = nap->module_load_status;
983 NaClXMutexUnlock(&nap->mu);
984 NaClLog(4, "NaClWaitForStartModuleCommand finished\n");
989 void NaClBlockIfCommandChannelExists(struct NaClApp *nap) {
990 if (NULL != nap->secure_service) {
992 struct nacl_abi_timespec req;
995 NaClNanosleep(&req, (struct nacl_abi_timespec *) NULL);
1000 void NaClSecureCommandChannel(struct NaClApp *nap) {
1001 struct NaClSecureService *secure_command_server;
1003 NaClLog(4, "Entered NaClSecureCommandChannel\n");
1005 secure_command_server = (struct NaClSecureService *) malloc(
1006 sizeof *secure_command_server);
1007 if (NACL_FI_ERROR_COND("NaClSecureCommandChannel__malloc",
1008 NULL == secure_command_server)) {
1009 NaClLog(LOG_FATAL, "Out of memory for secure command channel\n");
1011 if (NACL_FI_ERROR_COND("NaClSecureCommandChannel__NaClSecureServiceCtor",
1012 !NaClSecureServiceCtor(secure_command_server,
1014 nap->secure_service_port,
1015 nap->secure_service_address))) {
1016 NaClLog(LOG_FATAL, "NaClSecureServiceCtor failed\n");
1018 nap->secure_service = secure_command_server;
1020 NaClLog(4, "NaClSecureCommandChannel: starting service thread\n");
1021 if (NACL_FI_ERROR_COND(
1022 "NaClSecureCommandChannel__NaClSimpleServiceStartServiceThread",
1023 !NaClSimpleServiceStartServiceThread((struct NaClSimpleService *)
1024 secure_command_server))) {
1026 "Could not start secure command channel service thread\n");
1029 NaClLog(4, "Leaving NaClSecureCommandChannel\n");
1032 void NaClAppLoadModule(struct NaClApp *nap,
1033 struct NaClDesc *nexe,
1035 void (*load_cb)(void *instance_data,
1036 NaClErrorCode status),
1037 void *instance_data) {
1038 NaClErrorCode status = LOAD_OK;
1041 ("Entered NaClAppLoadModule: nap 0x%"NACL_PRIxPTR","
1042 " nexe 0x%"NACL_PRIxPTR", aux_info \"%s\"\n"),
1043 (uintptr_t) nap, (uintptr_t) nexe, aux_info);
1046 * TODO(bsy): consider doing the processing below after sending the
1047 * RPC reply to increase parallelism.
1049 NaClXMutexLock(&nap->mu);
1050 if (nap->module_initialization_state != NACL_MODULE_UNINITIALIZED) {
1051 NaClLog(LOG_ERROR, "NaClAppLoadModule: repeated invocation\n");
1052 status = LOAD_DUP_LOAD_MODULE;
1053 NaClXMutexUnlock(&nap->mu);
1054 if (NULL != load_cb) {
1055 (*load_cb)(instance_data, status);
1059 nap->module_initialization_state = NACL_MODULE_LOADING;
1060 NaClXCondVarBroadcast(&nap->cv);
1061 NaClXMutexUnlock(&nap->mu);
1063 if (NULL != load_cb) {
1064 (*load_cb)(instance_data, status);
1067 NaClXMutexLock(&nap->mu);
1068 free(nap->aux_info);
1069 nap->aux_info = aux_info;
1072 * Check / Mark the nexe binary as OK to attempt memory mapping.
1074 * TODO(bsy): change needed to get NaClFileToken and resolve to file
1075 * path information, set NaClRichFileInfo, and stash via
1076 * NaClSetFileOriginInfo, then set NACL_DESC_FLAGS_MMAP_EXEC_OK.
1079 status = NACL_FI_VAL("load_module", NaClErrorCode,
1080 NaClAppLoadFile(nexe, nap));
1082 if (LOAD_OK != status) {
1083 nap->module_load_status = status;
1084 nap->module_initialization_state = NACL_MODULE_ERROR;
1085 NaClXCondVarBroadcast(&nap->cv);
1087 NaClXMutexUnlock(&nap->mu); /* NaClAppPrepareToLaunch takes mu */
1088 if (LOAD_OK != status) {
1092 /***************************************************************************
1093 * TODO(bsy): Remove/merge the code invoking NaClAppPrepareToLaunch
1094 * and NaClGdbHook below with sel_main's main function. See comment
1096 ***************************************************************************/
1099 * Finish setting up the NaCl App.
1101 status = NaClAppPrepareToLaunch(nap);
1103 NaClXMutexLock(&nap->mu);
1104 nap->module_load_status = status;
1105 nap->module_initialization_state = NACL_MODULE_LOADED;
1106 NaClXCondVarBroadcast(&nap->cv);
1107 NaClXMutexUnlock(&nap->mu);
1109 /* Give debuggers a well known point at which xlate_base is known. */
1113 int NaClAppRuntimeHostSetup(struct NaClApp *nap,
1114 struct NaClRuntimeHostInterface *host_itf) {
1115 NaClErrorCode status = LOAD_OK;
1118 ("Entered NaClAppRuntimeHostSetup, nap 0x%"NACL_PRIxPTR","
1119 " host_itf 0x%"NACL_PRIxPTR"\n"),
1120 (uintptr_t) nap, (uintptr_t) host_itf);
1122 NaClXMutexLock(&nap->mu);
1123 if (nap->module_initialization_state > NACL_MODULE_STARTING) {
1124 NaClLog(LOG_ERROR, "NaClAppRuntimeHostSetup: too late\n");
1125 status = LOAD_INTERNAL;
1126 goto cleanup_status_mu;
1129 nap->runtime_host_interface = (struct NaClRuntimeHostInterface *)
1130 NaClRefCountRef((struct NaClRefCount *) host_itf);
1133 * Hook up runtime host enabled resources, e.g.,
1134 * DEBUG_ONLY:dev://postmessage. NB: Resources specified by
1135 * file:path should have been taken care of earlier, in
1136 * NaClAppInitialDescriptorHookup.
1138 nap->resource_phase = NACL_RESOURCE_PHASE_RUNTIME_HOST;
1139 NaClLog(4, "Processing dev I/O redirection/inheritance from environment\n");
1140 NaClProcessRedirControl(nap);
1141 NaClLog(4, "... done.\n");
1144 NaClXMutexUnlock(&nap->mu);
1145 return (int) status;
1148 int NaClAppDescQuotaSetup(struct NaClApp *nap,
1149 struct NaClDescQuotaInterface *quota_itf) {
1150 NaClErrorCode status = LOAD_OK;
1153 ("Entered NaClAppDescQuotaSetup, nap 0x%"NACL_PRIxPTR","
1154 " quota_itf 0x%"NACL_PRIxPTR"\n"),
1155 (uintptr_t) nap, (uintptr_t) quota_itf);
1157 NaClXMutexLock(&nap->mu);
1158 if (nap->module_initialization_state > NACL_MODULE_STARTING) {
1159 NaClLog(LOG_ERROR, "NaClAppDescQuotaSetup: too late\n");
1160 status = LOAD_INTERNAL;
1161 goto cleanup_status_mu;
1164 nap->desc_quota_interface = (struct NaClDescQuotaInterface *)
1165 NaClRefCountRef((struct NaClRefCount *) quota_itf);
1168 NaClXMutexUnlock(&nap->mu);
1169 return (int) status;
1172 void NaClAppStartModule(struct NaClApp *nap,
1173 void (*start_cb)(void *instance_data,
1174 NaClErrorCode status),
1175 void *instance_data) {
1176 NaClErrorCode status;
1179 ("Entered NaClAppStartModule, nap 0x%"NACL_PRIxPTR","
1180 " start_cb 0x%"NACL_PRIxPTR", instance_data 0x%"NACL_PRIxPTR"\n"),
1181 (uintptr_t) nap, (uintptr_t) start_cb, (uintptr_t) instance_data);
1184 * When module is loading, we have to block and wait till it is
1185 * fully loaded before we can proceed with start module.
1187 NaClXMutexLock(&nap->mu);
1188 if (NACL_MODULE_LOADING == nap->module_initialization_state) {
1189 while (NACL_MODULE_LOADED != nap->module_initialization_state) {
1190 NaClXCondVarWait(&nap->cv, &nap->mu);
1193 if (nap->module_initialization_state != NACL_MODULE_LOADED) {
1194 if (NACL_MODULE_ERROR == nap->module_initialization_state) {
1195 NaClLog(LOG_ERROR, "NaClAppStartModule: error loading module\n");
1196 status = nap->module_load_status;
1197 } else if (nap->module_initialization_state > NACL_MODULE_LOADED) {
1198 NaClLog(LOG_ERROR, "NaClAppStartModule: repeated invocation\n");
1199 status = LOAD_DUP_START_MODULE;
1200 } else if (nap->module_initialization_state < NACL_MODULE_LOADED) {
1201 NaClLog(LOG_ERROR, "NaClAppStartModule: module not loaded\n");
1202 status = LOAD_INTERNAL;
1204 NaClXMutexUnlock(&nap->mu);
1205 if (NULL != start_cb) {
1206 (*start_cb)(instance_data, status);
1210 status = nap->module_load_status;
1211 nap->module_initialization_state = NACL_MODULE_STARTING;
1212 NaClXCondVarBroadcast(&nap->cv);
1213 NaClXMutexUnlock(&nap->mu);
1215 NaClLog(4, "NaClSecureChannelStartModule: load status %d\n", status);
1218 * We need to invoke the callback now, before we signal the main thread
1219 * to possibly start by setting the state to NACL_MODULE_STARTED, since
1220 * in the case of failure the main thread may quickly exit; if the main
1221 * thread does this before we sent the reply, than the plugin (or any
1222 * other runtime host interface) will be left without an aswer. The
1223 * NACL_MODULE_STARTING state is used as an intermediate state to prevent
1224 * double invocations violating the protocol.
1226 if (NULL != start_cb) {
1227 (*start_cb)(instance_data, status);
1230 NaClXMutexLock(&nap->mu);
1231 nap->module_initialization_state = NACL_MODULE_STARTED;
1232 NaClXCondVarBroadcast(&nap->cv);
1233 NaClXMutexUnlock(&nap->mu);
1236 void NaClAppShutdown(struct NaClApp *nap,
1238 NaClLog(4, "NaClAppShutdown: nap 0x%"NACL_PRIxPTR
1239 ", exit_status %d\n", (uintptr_t) nap, exit_status);
1241 NaClXMutexLock(&nap->mu);
1242 nap->exit_status = exit_status;
1243 NaClXMutexUnlock(&nap->mu);
1244 if (NULL != nap->debug_stub_callbacks) {
1245 nap->debug_stub_callbacks->process_exit_hook();
1251 * It is fine to have multiple I/O operations read from memory in Write
1252 * or SendMsg like operations.
1254 void NaClVmIoWillStart(struct NaClApp *nap,
1255 uint32_t addr_first_usr,
1256 uint32_t addr_last_usr) {
1257 NaClXMutexLock(&nap->mu);
1258 (*nap->mem_io_regions->vtbl->AddInterval)(nap->mem_io_regions,
1261 NaClXMutexUnlock(&nap->mu);
1265 void NaClVmIoHasEnded(struct NaClApp *nap,
1266 uint32_t addr_first_usr,
1267 uint32_t addr_last_usr) {
1268 NaClXMutexLock(&nap->mu);
1269 (*nap->mem_io_regions->vtbl->RemoveInterval)(nap->mem_io_regions,
1272 NaClXMutexUnlock(&nap->mu);
1275 void NaClVmIoPendingCheck_mu(struct NaClApp *nap,
1276 uint32_t addr_first_usr,
1277 uint32_t addr_last_usr) {
1278 if ((*nap->mem_io_regions->vtbl->OverlapsWith)(nap->mem_io_regions,
1282 "NaClVmIoWillStart: program mem write race detected. ABORTING\n");
1287 * GDB's canonical overlay managment routine.
1288 * We need its symbol in the symbol table so don't inline it.
1289 * TODO(dje): add some explanation for the non-GDB person.
1292 __declspec(dllexport noinline)
1295 __attribute__((noinline))
1297 void _ovly_debug_event (void) {
1300 * The asm volatile is here as instructed by the GCC docs.
1301 * It's not enough to declare a function noinline.
1302 * GCC will still look inside the function to see if it's worth calling.
1304 __asm__ volatile ("");
1307 * Visual Studio inlines empty functions even with noinline attribute,
1308 * so we need a compile memory barrier to make this function not to be
1309 * inlined. Also, it guarantees that nacl_global_xlate_base initialization
1310 * is not reordered. This is important for gdb since it sets breakpoint on
1311 * this function and reads nacl_global_xlate_base value.
1313 _ReadWriteBarrier();
1317 static void StopForDebuggerInit (uintptr_t mem_start) {
1318 /* Put xlate_base in a place where gdb can find it. */
1319 nacl_global_xlate_base = mem_start;
1321 NaClSandboxMemoryStartForValgrind(mem_start);
1323 _ovly_debug_event();
1326 void NaClGdbHook(struct NaClApp const *nap) {
1327 StopForDebuggerInit(nap->mem_start);