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/public/desc_metadata_types.h"
18 #include "native_client/src/public/nacl_app.h"
19 #include "native_client/src/public/secure_service.h"
21 #include "native_client/src/shared/gio/gio.h"
22 #include "native_client/src/shared/platform/nacl_check.h"
23 #include "native_client/src/shared/platform/nacl_exit.h"
24 #include "native_client/src/shared/platform/nacl_log.h"
25 #include "native_client/src/shared/platform/nacl_sync.h"
26 #include "native_client/src/shared/platform/nacl_sync_checked.h"
27 #include "native_client/src/shared/platform/nacl_time.h"
28 #include "native_client/src/shared/srpc/nacl_srpc.h"
30 #include "native_client/src/trusted/desc/nacl_desc_base.h"
31 #include "native_client/src/trusted/desc/nacl_desc_conn_cap.h"
32 #include "native_client/src/trusted/desc/nacl_desc_imc.h"
33 #include "native_client/src/trusted/desc/nacl_desc_io.h"
34 #include "native_client/src/trusted/desc/nrd_xfer.h"
35 #include "native_client/src/trusted/desc_cacheability/desc_cacheability.h"
36 #include "native_client/src/trusted/fault_injection/fault_injection.h"
37 #include "native_client/src/trusted/fault_injection/test_injection.h"
38 #include "native_client/src/trusted/interval_multiset/nacl_interval_range_tree_intern.h"
39 #include "native_client/src/trusted/service_runtime/arch/sel_ldr_arch.h"
40 #include "native_client/src/trusted/service_runtime/include/bits/nacl_syscalls.h"
41 #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
42 #include "native_client/src/trusted/service_runtime/include/sys/stat.h"
43 #include "native_client/src/trusted/service_runtime/include/sys/time.h"
44 #include "native_client/src/trusted/service_runtime/nacl_app.h"
45 #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
46 #include "native_client/src/trusted/service_runtime/nacl_desc_effector_ldr.h"
47 #include "native_client/src/trusted/service_runtime/nacl_globals.h"
48 #include "native_client/src/trusted/service_runtime/nacl_resource.h"
49 #include "native_client/src/trusted/service_runtime/nacl_reverse_quota_interface.h"
50 #include "native_client/src/trusted/service_runtime/nacl_syscall_common.h"
51 #include "native_client/src/trusted/service_runtime/nacl_syscall_handlers.h"
52 #include "native_client/src/trusted/service_runtime/nacl_valgrind_hooks.h"
53 #include "native_client/src/trusted/service_runtime/name_service/name_service.h"
54 #include "native_client/src/trusted/service_runtime/sel_addrspace.h"
55 #include "native_client/src/trusted/service_runtime/sel_ldr.h"
56 #include "native_client/src/trusted/service_runtime/sel_memory.h"
57 #include "native_client/src/trusted/service_runtime/sel_ldr_thread_interface.h"
58 #include "native_client/src/trusted/simple_service/nacl_simple_rservice.h"
59 #include "native_client/src/trusted/simple_service/nacl_simple_service.h"
60 #include "native_client/src/trusted/threading/nacl_thread_interface.h"
61 #include "native_client/src/trusted/validator/rich_file_info.h"
62 #include "native_client/src/trusted/validator/validation_cache.h"
64 static int IsEnvironmentVariableSet(char const *env_name) {
65 return NULL != getenv(env_name);
68 static int ShouldEnableDyncodeSyscalls(void) {
69 return !IsEnvironmentVariableSet("NACL_DISABLE_DYNCODE_SYSCALLS");
72 static int ShouldEnableDynamicLoading(void) {
73 return !IsEnvironmentVariableSet("NACL_DISABLE_DYNAMIC_LOADING");
76 int NaClAppWithSyscallTableCtor(struct NaClApp *nap,
77 struct NaClSyscallTableEntry *table) {
78 struct NaClDescEffectorLdr *effp;
80 /* Zero-initialize in case we miss any fields below. */
81 memset(nap, 0, sizeof(*nap));
83 /* The validation cache will be injected later, if it exists. */
84 nap->validation_cache = NULL;
86 nap->validator = NaClCreateValidator();
88 /* Get the set of features that the CPU we're running on supports. */
89 /* These may be adjusted later in sel_main.c for fixed-feature CPU mode. */
90 nap->cpu_features = (NaClCPUFeatures *) malloc(
91 nap->validator->CPUFeatureSize);
92 if (NULL == nap->cpu_features) {
95 nap->validator->GetCurrentCPUFeatures(nap->cpu_features);
96 nap->fixed_feature_cpu_mode = 0;
98 nap->addr_bits = NACL_MAX_ADDR_BITS;
100 nap->stack_size = NACL_DEFAULT_STACK_MAX;
101 nap->initial_nexe_max_code_bytes = 0;
105 #if (NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 \
106 && NACL_BUILD_SUBARCH == 32)
107 nap->pcrel_thunk = 0;
108 nap->pcrel_thunk_end = 0;
110 #if (NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 \
111 && NACL_BUILD_SUBARCH == 64)
112 nap->nacl_syscall_addr = 0;
113 nap->get_tls_fast_path1_addr = 0;
114 nap->get_tls_fast_path2_addr = 0;
117 nap->static_text_end = 0;
118 nap->dynamic_text_start = 0;
119 nap->dynamic_text_end = 0;
120 nap->rodata_start = 0;
124 nap->initial_entry_pt = 0;
125 nap->user_entry_pt = 0;
127 if (!DynArrayCtor(&nap->threads, 2)) {
128 goto cleanup_cpu_features;
130 if (!DynArrayCtor(&nap->desc_tbl, 2)) {
131 goto cleanup_threads;
133 if (!NaClVmmapCtor(&nap->mem_map)) {
134 goto cleanup_desc_tbl;
137 nap->mem_io_regions = (struct NaClIntervalMultiset *) malloc(
138 sizeof(struct NaClIntervalRangeTree));
139 if (NULL == nap->mem_io_regions) {
140 goto cleanup_mem_map;
143 if (!NaClIntervalRangeTreeCtor((struct NaClIntervalRangeTree *)
144 nap->mem_io_regions)) {
145 free(nap->mem_io_regions);
146 nap->mem_io_regions = NULL;
147 goto cleanup_mem_map;
150 effp = (struct NaClDescEffectorLdr *) malloc(sizeof *effp);
152 goto cleanup_mem_io_regions;
154 if (!NaClDescEffectorLdrCtor(effp, nap)) {
155 goto cleanup_effp_free;
157 nap->effp = (struct NaClDescEffector *) effp;
159 nap->enable_dyncode_syscalls = ShouldEnableDyncodeSyscalls();
160 nap->use_shm_for_dynamic_text = ShouldEnableDynamicLoading();
161 nap->text_shm = NULL;
162 if (!NaClMutexCtor(&nap->dynamic_load_mutex)) {
163 goto cleanup_effp_free;
165 nap->dynamic_page_bitmap = NULL;
167 nap->dynamic_regions = NULL;
168 nap->num_dynamic_regions = 0;
169 nap->dynamic_regions_allocated = 0;
170 nap->dynamic_delete_generation = 0;
172 nap->dynamic_mapcache_offset = 0;
173 nap->dynamic_mapcache_size = 0;
174 nap->dynamic_mapcache_ret = 0;
176 nap->service_port = NULL;
177 nap->service_address = NULL;
178 nap->secure_service_port = NULL;
179 nap->secure_service_address = NULL;
180 nap->bootstrap_channel = NULL;
181 nap->secure_service = NULL;
182 nap->main_exe_prevalidated = 0;
184 nap->kernel_service = NULL;
185 nap->resource_phase = NACL_RESOURCE_PHASE_START;
186 if (!NaClResourceNaClAppInit(&nap->resources, nap)) {
187 goto cleanup_dynamic_load_mutex;
190 if (!NaClMutexCtor(&nap->mu)) {
191 goto cleanup_dynamic_load_mutex;
193 if (!NaClCondVarCtor(&nap->cv)) {
198 nap->vm_hole_may_exist = 0;
199 nap->threads_launching = 0;
202 nap->syscall_table = table;
204 nap->runtime_host_interface = NULL;
205 nap->desc_quota_interface = NULL;
207 nap->module_initialization_state = NACL_MODULE_UNINITIALIZED;
208 nap->module_load_status = LOAD_OK;
210 nap->name_service = (struct NaClNameService *) malloc(
211 sizeof *nap->name_service);
212 if (NULL == nap->name_service) {
215 if (!NaClNameServiceCtor(nap->name_service,
216 NaClAddrSpSquattingThreadIfFactoryFunction,
218 free(nap->name_service);
221 nap->name_service_conn_cap = NaClDescRef(nap->name_service->
222 base.base.bound_and_cap[1]);
224 nap->ignore_validator_result = 0;
225 nap->skip_validator = 0;
226 nap->validator_stub_out_mode = 0;
228 if (IsEnvironmentVariableSet("NACL_DANGEROUS_ENABLE_FILE_ACCESS")) {
229 NaClInsecurelyBypassAllAclChecks();
230 NaClLog(LOG_INFO, "DANGER: ENABLED FILE ACCESS\n");
233 nap->enable_list_mappings = 0;
234 if (IsEnvironmentVariableSet("NACL_DANGEROUS_ENABLE_LIST_MAPPINGS")) {
236 * This syscall is not actually know to be dangerous, but is not yet
237 * exposed by our public API.
239 NaClLog(LOG_INFO, "DANGER: ENABLED LIST_MAPPINGS\n");
240 nap->enable_list_mappings = 1;
244 if (!NaClMutexCtor(&nap->threads_mu)) {
245 goto cleanup_name_service;
247 nap->num_threads = 0;
248 if (!NaClFastMutexCtor(&nap->desc_mu)) {
249 goto cleanup_threads_mu;
253 nap->exit_status = -1;
255 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
256 nap->code_seg_sel = 0;
257 nap->data_seg_sel = 0;
260 nap->debug_stub_callbacks = NULL;
262 nap->debug_stub_port = 0;
264 nap->main_nexe_desc = NULL;
265 nap->irt_nexe_desc = NULL;
267 nap->exception_handler = 0;
268 if (!NaClMutexCtor(&nap->exception_mu)) {
269 goto cleanup_desc_mu;
271 nap->enable_exception_handling = 0;
273 nap->debug_exception_handler_state = NACL_DEBUG_EXCEPTION_HANDLER_NOT_STARTED;
274 nap->attach_debug_exception_handler_func = NULL;
276 nap->enable_faulted_thread_queue = 0;
277 nap->faulted_thread_count = 0;
279 nap->faulted_thread_event = INVALID_HANDLE_VALUE;
281 nap->faulted_thread_fd_read = -1;
282 nap->faulted_thread_fd_write = -1;
286 #if NACL_LINUX || NACL_OSX
288 * Try to pre-cache information that we can't obtain with the outer
289 * sandbox on. If the outer sandbox has already been enabled, this
290 * will just set sc_nprocessors_onln to -1, and it is the
291 * responsibility of the caller to replace this with a sane value
292 * after the Ctor returns.
294 nap->sc_nprocessors_onln = sysconf(_SC_NPROCESSORS_ONLN);
297 if (!NaClMutexCtor(&nap->futex_wait_list_mu)) {
298 goto cleanup_exception_mu;
300 nap->futex_wait_list_head.next = &nap->futex_wait_list_head;
301 nap->futex_wait_list_head.prev = &nap->futex_wait_list_head;
305 cleanup_exception_mu:
306 NaClMutexDtor(&nap->exception_mu);
308 NaClFastMutexDtor(&nap->desc_mu);
310 NaClMutexDtor(&nap->threads_mu);
311 cleanup_name_service:
312 NaClDescUnref(nap->name_service_conn_cap);
313 NaClRefCountUnref((struct NaClRefCount *) nap->name_service);
315 NaClCondVarDtor(&nap->cv);
317 NaClMutexDtor(&nap->mu);
318 cleanup_dynamic_load_mutex:
319 NaClMutexDtor(&nap->dynamic_load_mutex);
322 cleanup_mem_io_regions:
323 NaClIntervalMultisetDelete(nap->mem_io_regions);
324 nap->mem_io_regions = NULL;
326 NaClVmmapDtor(&nap->mem_map);
328 DynArrayDtor(&nap->desc_tbl);
330 DynArrayDtor(&nap->threads);
331 cleanup_cpu_features:
332 free(nap->cpu_features);
337 int NaClAppCtor(struct NaClApp *nap) {
338 return NaClAppWithSyscallTableCtor(nap, nacl_syscall);
341 struct NaClApp *NaClAppCreate(void) {
342 struct NaClApp *nap = malloc(sizeof(struct NaClApp));
344 NaClLog(LOG_FATAL, "Failed to allocate NaClApp\n");
345 if (!NaClAppCtor(nap))
346 NaClLog(LOG_FATAL, "NaClAppCtor() failed\n");
351 * unaligned little-endian load. precondition: nbytes should never be
354 static uint64_t NaClLoadMem(uintptr_t addr,
355 size_t user_nbytes) {
358 CHECK(0 != user_nbytes && user_nbytes <= 8);
362 value |= ((uint8_t *) addr)[--user_nbytes];
363 } while (user_nbytes > 0);
367 #define GENERIC_LOAD(bits) \
368 static uint ## bits ## _t NaClLoad ## bits(uintptr_t addr) { \
369 return (uint ## bits ## _t) NaClLoadMem(addr, sizeof(uint ## bits ## _t)); \
372 #if NACL_TARGET_SUBARCH == 32
380 * unaligned little-endian store
382 static void NaClStoreMem(uintptr_t addr,
389 for (i = 0; i < nbytes; ++i) {
390 ((uint8_t *) addr)[i] = (uint8_t) value;
395 #define GENERIC_STORE(bits) \
396 static void NaClStore ## bits(uintptr_t addr, \
397 uint ## bits ## _t v) { \
398 NaClStoreMem(addr, sizeof(uint ## bits ## _t), v); \
407 struct NaClPatchInfo *NaClPatchInfoCtor(struct NaClPatchInfo *self) {
409 memset(self, 0, sizeof *self);
415 * This function is called by NaClLoadTrampoline and NaClLoadSpringboard to
416 * patch a single memory location specified in NaClPatchInfo structure.
418 void NaClApplyPatchToMemory(struct NaClPatchInfo *patch) {
422 uintptr_t target_addr;
424 memcpy((void *) patch->dst, (void *) patch->src, patch->nbytes);
426 reloc = patch->dst - patch->src;
429 for (i = 0; i < patch->num_abs64; ++i) {
430 offset = patch->abs64[i].target - patch->src;
431 target_addr = patch->dst + offset;
432 NaClStore64(target_addr, patch->abs64[i].value);
435 for (i = 0; i < patch->num_abs32; ++i) {
436 offset = patch->abs32[i].target - patch->src;
437 target_addr = patch->dst + offset;
438 NaClStore32(target_addr, (uint32_t) patch->abs32[i].value);
441 for (i = 0; i < patch->num_abs16; ++i) {
442 offset = patch->abs16[i].target - patch->src;
443 target_addr = patch->dst + offset;
444 NaClStore16(target_addr, (uint16_t) patch->abs16[i].value);
447 for (i = 0; i < patch->num_rel64; ++i) {
448 offset = patch->rel64[i] - patch->src;
449 target_addr = patch->dst + offset;
450 NaClStore64(target_addr, NaClLoad64(target_addr) - reloc);
454 * rel32 is only supported on 32-bit architectures. The range of a relative
455 * relocation in untrusted space is +/- 4GB. This can be represented as
456 * an unsigned 32-bit value mod 2^32, which is handy on a 32 bit system since
457 * all 32-bit pointer arithmetic is implicitly mod 2^32. On a 64 bit system,
458 * however, pointer arithmetic is implicitly modulo 2^64, which isn't as
459 * helpful for our purposes. We could simulate the 32-bit behavior by
460 * explicitly modding all relative addresses by 2^32, but that seems like an
461 * expensive way to save a few bytes per reloc.
463 #if NACL_TARGET_SUBARCH == 32
464 for (i = 0; i < patch->num_rel32; ++i) {
465 offset = patch->rel32[i] - patch->src;
466 target_addr = patch->dst + offset;
467 NaClStore32(target_addr,
468 (uint32_t) NaClLoad32(target_addr) - (int32_t) reloc);
475 * Install syscall trampolines at all possible well-formed entry
476 * points within the trampoline pages. Many of these syscalls will
477 * correspond to unimplemented system calls and will just abort the
480 void NaClLoadTrampoline(struct NaClApp *nap, enum NaClAslrMode aslr_mode) {
485 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
486 if (!NaClMakePcrelThunk(nap, aslr_mode)) {
487 NaClLog(LOG_FATAL, "NaClMakePcrelThunk failed!\n");
490 UNREFERENCED_PARAMETER(aslr_mode);
492 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64
493 if (!NaClMakeDispatchAddrs(nap)) {
494 NaClLog(LOG_FATAL, "NaClMakeDispatchAddrs failed!\n");
497 NaClFillTrampolineRegion(nap);
500 * Do not bother to fill in the contents of page 0, since we make it
501 * inaccessible later (see sel_addrspace.c, NaClMemoryProtection)
502 * anyway to help detect NULL pointer errors, and we might as well
503 * not dirty the page.
505 * The last syscall entry point is used for springboard code.
507 num_syscalls = ((NACL_TRAMPOLINE_END - NACL_SYSCALL_START_ADDR)
508 / NACL_SYSCALL_BLOCK_SIZE) - 1;
510 NaClLog(2, "num_syscalls = %d (0x%x)\n", num_syscalls, num_syscalls);
512 for (i = 0, addr = nap->mem_start + NACL_SYSCALL_START_ADDR;
514 ++i, addr += NACL_SYSCALL_BLOCK_SIZE) {
515 NaClPatchOneTrampoline(nap, addr);
517 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64
518 NaClPatchOneTrampolineCall(nap->get_tls_fast_path1_addr,
519 nap->mem_start + NACL_SYSCALL_START_ADDR
520 + NACL_SYSCALL_BLOCK_SIZE * NACL_sys_tls_get);
521 NaClPatchOneTrampolineCall(nap->get_tls_fast_path2_addr,
522 nap->mem_start + NACL_SYSCALL_START_ADDR
523 + (NACL_SYSCALL_BLOCK_SIZE *
524 NACL_sys_second_tls_get));
527 NACL_TEST_INJECTION(ChangeTrampolines, (nap));
530 struct NaClDesc *NaClAppGetDescMu(struct NaClApp *nap,
532 struct NaClDesc *result;
534 result = (struct NaClDesc *) DynArrayGet(&nap->desc_tbl, d);
535 if (NULL != result) {
542 void NaClAppSetDescMu(struct NaClApp *nap,
544 struct NaClDesc *ndp) {
545 struct NaClDesc *result;
547 result = (struct NaClDesc *) DynArrayGet(&nap->desc_tbl, d);
548 NaClDescSafeUnref(result);
550 if (!DynArraySet(&nap->desc_tbl, d, ndp)) {
552 "NaClAppSetDesc: could not set descriptor %d to 0x%08"
559 int32_t NaClAppSetDescAvailMu(struct NaClApp *nap,
560 struct NaClDesc *ndp) {
563 pos = DynArrayFirstAvail(&nap->desc_tbl);
565 if (pos > INT32_MAX) {
567 ("NaClAppSetDescAvailMu: DynArrayFirstAvail returned a value"
568 " that is greather than 2**31-1.\n"));
571 NaClAppSetDescMu(nap, (int) pos, ndp);
573 return (int32_t) pos;
576 struct NaClDesc *NaClAppGetDesc(struct NaClApp *nap,
578 struct NaClDesc *res;
580 NaClFastMutexLock(&nap->desc_mu);
581 res = NaClAppGetDescMu(nap, d);
582 NaClFastMutexUnlock(&nap->desc_mu);
586 void NaClAppSetDesc(struct NaClApp *nap,
588 struct NaClDesc *ndp) {
589 NaClFastMutexLock(&nap->desc_mu);
590 NaClAppSetDescMu(nap, d, ndp);
591 NaClFastMutexUnlock(&nap->desc_mu);
594 int32_t NaClAppSetDescAvail(struct NaClApp *nap,
595 struct NaClDesc *ndp) {
598 NaClFastMutexLock(&nap->desc_mu);
599 pos = NaClAppSetDescAvailMu(nap, ndp);
600 NaClFastMutexUnlock(&nap->desc_mu);
605 int NaClAddThreadMu(struct NaClApp *nap,
606 struct NaClAppThread *natp) {
609 pos = DynArrayFirstAvail(&nap->threads);
611 if (!DynArraySet(&nap->threads, pos, natp)) {
613 "NaClAddThreadMu: DynArraySet at position %"NACL_PRIuS" failed\n",
620 int NaClAddThread(struct NaClApp *nap,
621 struct NaClAppThread *natp) {
624 NaClXMutexLock(&nap->threads_mu);
625 pos = NaClAddThreadMu(nap, natp);
626 NaClXMutexUnlock(&nap->threads_mu);
631 void NaClRemoveThreadMu(struct NaClApp *nap,
633 if (NULL == DynArrayGet(&nap->threads, thread_num)) {
635 "NaClRemoveThreadMu:: thread to be removed is not in the table\n");
637 if (nap->num_threads == 0) {
639 "NaClRemoveThreadMu:: num_threads cannot be 0!!!\n");
642 if (!DynArraySet(&nap->threads, thread_num, (struct NaClAppThread *) NULL)) {
644 "NaClRemoveThreadMu:: DynArraySet at position %d failed\n",
649 void NaClRemoveThread(struct NaClApp *nap,
651 NaClXMutexLock(&nap->threads_mu);
652 NaClRemoveThreadMu(nap, thread_num);
653 NaClXMutexUnlock(&nap->threads_mu);
656 struct NaClAppThread *NaClGetThreadMu(struct NaClApp *nap,
658 return (struct NaClAppThread *) DynArrayGet(&nap->threads, thread_num);
661 void NaClAddHostDescriptor(struct NaClApp *nap,
665 struct NaClDescIoDesc *dp;
668 "NaClAddHostDescriptor: host %d as nacl desc %d, flag 0x%x\n",
672 dp = NaClDescIoDescMake(NaClHostDescPosixMake(host_os_desc, flag));
674 NaClLog(LOG_FATAL, "NaClAddHostDescriptor: NaClDescIoDescMake failed\n");
676 NaClAppSetDesc(nap, nacl_desc, (struct NaClDesc *) dp);
679 void NaClAddImcHandle(struct NaClApp *nap,
682 struct NaClDescImcDesc *dp;
685 ("NaClAddImcHandle: importing NaClHandle %"NACL_PRIxPTR
686 " as nacl desc %d\n"),
689 dp = (struct NaClDescImcDesc *) malloc(sizeof *dp);
690 if (NACL_FI_ERROR_COND("NaClAddImcHandle__malloc", NULL == dp)) {
691 NaClLog(LOG_FATAL, "NaClAddImcHandle: no memory\n");
693 if (NACL_FI_ERROR_COND("NaClAddImcHandle__ctor",
694 !NaClDescImcDescCtor(dp, h))) {
695 NaClLog(LOG_FATAL, ("NaClAddImcHandle: cannot construct"
696 " IMC descriptor object\n"));
698 NaClAppSetDesc(nap, nacl_desc, (struct NaClDesc *) dp);
704 char const *env_name;
707 } const g_nacl_redir_control[] = {
708 { 0, "NACL_EXE_STDIN",
709 NACL_ABI_O_RDONLY, 0, },
710 { 1, "NACL_EXE_STDOUT",
711 NACL_ABI_O_WRONLY | NACL_ABI_O_APPEND | NACL_ABI_O_CREAT, 0777, },
712 { 2, "NACL_EXE_STDERR",
713 NACL_ABI_O_WRONLY | NACL_ABI_O_APPEND | NACL_ABI_O_CREAT, 0777, },
717 * File redirection is impossible if an outer sandbox is in place.
718 * For the command-line embedding, we sometimes have an outer sandbox:
719 * on OSX, it is enabled after loading the file is loaded. On the
720 * other hand, device redirection (DEBUG_ONLY:dev://postmessage) is
721 * impossible until the reverse channel setup has occurred.
723 * Because of this, we run NaClProcessRedirControl twice: once to
724 * process default inheritance, file redirection early on, and once
725 * after the reverse channel is in place to handle the device
726 * redirection. We try to hide knowledge about which redirection
727 * control values can be handled in which phases by allowing the
728 * NaClResourceOpen to fail, and only in the last phase do we check
729 * that the redirection succeeded in *some* phase.
731 static void NaClProcessRedirControl(struct NaClApp *nap) {
735 struct NaClDesc *ndp;
737 for (ix = 0; ix < NACL_ARRAY_SIZE(g_nacl_redir_control); ++ix) {
739 if (NULL != (env = getenv(g_nacl_redir_control[ix].env_name))) {
740 NaClLog(4, "getenv(%s) -> %s\n", g_nacl_redir_control[ix].env_name, env);
741 ndp = NaClResourceOpen((struct NaClResource *) &nap->resources,
743 g_nacl_redir_control[ix].nacl_flags,
744 g_nacl_redir_control[ix].mode);
745 NaClLog(4, " NaClResourceOpen returned %"NACL_PRIxPTR"\n",
750 NaClLog(4, "Setting descriptor %d\n", (int) ix);
751 NaClAppSetDesc(nap, (int) ix, ndp);
752 } else if (NACL_RESOURCE_PHASE_START == nap->resource_phase) {
754 * Environment not set or redirect failed -- handle default inheritance.
756 NaClAddHostDescriptor(nap, DUP(g_nacl_redir_control[ix].d),
757 g_nacl_redir_control[ix].nacl_flags, (int) ix);
763 * Process default descriptor inheritance. This means dup'ing
764 * descriptors 0-2 and making them available to the NaCl App.
766 * When standard input is inherited, this could result in a NaCl
767 * module competing for input from the terminal; for graphical /
768 * browser plugin environments, this never is allowed to happen, and
769 * having this is useful for debugging, and for potential standalone
770 * text-mode applications of NaCl.
772 * TODO(bsy): consider whether default inheritance should occur only
775 void NaClAppInitialDescriptorHookup(struct NaClApp *nap) {
777 NaClLog(4, "Processing I/O redirection/inheritance from environment\n");
778 nap->resource_phase = NACL_RESOURCE_PHASE_START;
779 NaClProcessRedirControl(nap);
780 NaClLog(4, "... done.\n");
783 void NaClCreateServiceSocket(struct NaClApp *nap) {
784 struct NaClDesc *secure_pair[2];
785 struct NaClDesc *pair[2];
787 NaClLog(3, "Entered NaClCreateServiceSocket\n");
789 if (NACL_FI_ERROR_COND("NaClCreateServiceSocket__secure_boundsock",
790 0 != NaClCommonDescMakeBoundSock(secure_pair))) {
791 NaClLog(LOG_FATAL, "Cound not create secure service socket\n");
794 "got bound socket at 0x%08"NACL_PRIxPTR", "
795 "addr at 0x%08"NACL_PRIxPTR"\n",
796 (uintptr_t) secure_pair[0],
797 (uintptr_t) secure_pair[1]);
799 NaClDescSafeUnref(nap->secure_service_port);
800 nap->secure_service_port = secure_pair[0];
802 NaClDescSafeUnref(nap->secure_service_address);
803 nap->secure_service_address = secure_pair[1];
805 if (NACL_FI_ERROR_COND("NaClCreateServiceSocket__boundsock",
806 0 != NaClCommonDescMakeBoundSock(pair))) {
807 NaClLog(LOG_FATAL, "Cound not create service socket\n");
810 "got bound socket at 0x%08"NACL_PRIxPTR", "
811 "addr at 0x%08"NACL_PRIxPTR"\n",
813 (uintptr_t) pair[1]);
814 NaClAppSetDesc(nap, NACL_SERVICE_PORT_DESCRIPTOR, pair[0]);
815 NaClAppSetDesc(nap, NACL_SERVICE_ADDRESS_DESCRIPTOR, pair[1]);
817 NaClDescSafeUnref(nap->service_port);
819 nap->service_port = pair[0];
820 NaClDescRef(nap->service_port);
822 NaClDescSafeUnref(nap->service_address);
824 nap->service_address = pair[1];
825 NaClDescRef(nap->service_address);
827 NaClLog(4, "Leaving NaClCreateServiceSocket\n");
831 * Import the |inherited_desc| descriptor as an IMC handle, save a
832 * reference to it at nap->bootstrap_channel, then send the
833 * service_address over that channel.
835 void NaClSetUpBootstrapChannel(struct NaClApp *nap,
836 NaClHandle inherited_desc) {
837 struct NaClDescImcDesc *channel;
838 struct NaClImcTypedMsgHdr hdr;
839 struct NaClDesc *descs[2];
843 "NaClSetUpBootstrapChannel(0x%08"NACL_PRIxPTR", %"NACL_PRIdPTR")\n",
845 (uintptr_t) inherited_desc);
847 channel = (struct NaClDescImcDesc *) malloc(sizeof *channel);
848 if (NULL == channel) {
849 NaClLog(LOG_FATAL, "NaClSetUpBootstrapChannel: no memory\n");
851 if (!NaClDescImcDescCtor(channel, inherited_desc)) {
853 ("NaClSetUpBootstrapChannel: cannot construct IMC descriptor"
854 " object for inherited descriptor %"NACL_PRIdPTR"\n"),
855 (uintptr_t) inherited_desc);
858 if (NULL == nap->secure_service_address) {
860 "NaClSetUpBootstrapChannel: secure service address not set\n");
863 if (NULL == nap->service_address) {
865 "NaClSetUpBootstrapChannel: service address not set\n");
869 * service_address and service_port are set together.
871 descs[0] = nap->secure_service_address;
872 descs[1] = nap->service_address;
874 hdr.iov = (struct NaClImcMsgIoVec *) NULL;
877 hdr.ndesc_length = NACL_ARRAY_SIZE(descs);
879 rv = (*NACL_VTBL(NaClDesc, channel)->SendMsg)((struct NaClDesc *) channel,
881 NaClXMutexLock(&nap->mu);
882 if (NULL != nap->bootstrap_channel) {
884 "NaClSetUpBootstrapChannel: cannot have two bootstrap channels\n");
886 nap->bootstrap_channel = (struct NaClDesc *) channel;
888 NaClXMutexUnlock(&nap->mu);
891 ("NaClSetUpBootstrapChannel: descriptor %"NACL_PRIdPTR
892 ", error %"NACL_PRIdS"\n"),
893 (uintptr_t) inherited_desc,
895 if (NACL_FI_ERROR_COND("NaClSetUpBootstrapChannel__SendMsg", 0 != rv)) {
897 "NaClSetUpBootstrapChannel: SendMsg failed, rv = %"NACL_PRIdS"\n",
902 enum NaClModuleInitializationState NaClGetInitState(struct NaClApp *nap) {
903 enum NaClModuleInitializationState state;
904 NaClXMutexLock(&nap->mu);
905 state = nap->module_initialization_state;
906 NaClXMutexUnlock(&nap->mu);
910 void NaClSetInitState(struct NaClApp *nap,
911 enum NaClModuleInitializationState state) {
912 NaClXMutexLock(&nap->mu);
913 /* The initialization state should be increasing monotonically. */
914 CHECK(state > nap->module_initialization_state);
915 nap->module_initialization_state = state;
916 NaClXCondVarBroadcast(&nap->cv);
917 NaClXMutexUnlock(&nap->mu);
920 NaClErrorCode NaClWaitForLoadModuleCommand(struct NaClApp *nap) {
921 NaClErrorCode status;
923 NaClLog(4, "NaClWaitForLoadModuleCommand started\n");
924 NaClXMutexLock(&nap->mu);
925 while (nap->module_initialization_state < NACL_MODULE_LOADED) {
926 NaClXCondVarWait(&nap->cv, &nap->mu);
928 status = nap->module_load_status;
929 NaClXMutexUnlock(&nap->mu);
930 NaClLog(4, "NaClWaitForLoadModuleCommand finished\n");
935 void NaClRememberLoadStatus(struct NaClApp *nap, NaClErrorCode status) {
936 NaClXMutexLock(&nap->mu);
937 /* Remember the first error we encountered. */
938 if (nap->module_load_status == LOAD_OK) {
939 nap->module_load_status = status;
941 NaClXMutexUnlock(&nap->mu);
945 NaClErrorCode NaClGetLoadStatus(struct NaClApp *nap) {
946 NaClErrorCode status;
947 NaClXMutexLock(&nap->mu);
948 status = nap->module_load_status;
949 NaClXMutexUnlock(&nap->mu);
953 NaClErrorCode NaClWaitForStartModuleCommand(struct NaClApp *nap) {
954 NaClErrorCode status;
956 NaClLog(4, "NaClWaitForStartModuleCommand started\n");
957 NaClXMutexLock(&nap->mu);
958 while (nap->module_initialization_state < NACL_MODULE_STARTED) {
959 NaClXCondVarWait(&nap->cv, &nap->mu);
961 status = nap->module_load_status;
962 NaClXMutexUnlock(&nap->mu);
963 NaClLog(4, "NaClWaitForStartModuleCommand finished\n");
968 void NaClBlockIfCommandChannelExists(struct NaClApp *nap) {
969 if (NULL != nap->secure_service) {
971 struct nacl_abi_timespec req;
974 NaClNanosleep(&req, (struct nacl_abi_timespec *) NULL);
979 void NaClSecureCommandChannel(struct NaClApp *nap) {
980 struct NaClSecureService *secure_command_server;
982 NaClLog(4, "Entered NaClSecureCommandChannel\n");
984 secure_command_server = (struct NaClSecureService *) malloc(
985 sizeof *secure_command_server);
986 if (NACL_FI_ERROR_COND("NaClSecureCommandChannel__malloc",
987 NULL == secure_command_server)) {
988 NaClLog(LOG_FATAL, "Out of memory for secure command channel\n");
990 if (NACL_FI_ERROR_COND("NaClSecureCommandChannel__NaClSecureServiceCtor",
991 !NaClSecureServiceCtor(secure_command_server,
993 nap->secure_service_port,
994 nap->secure_service_address))) {
995 NaClLog(LOG_FATAL, "NaClSecureServiceCtor failed\n");
997 nap->secure_service = secure_command_server;
999 NaClLog(4, "NaClSecureCommandChannel: starting service thread\n");
1000 if (NACL_FI_ERROR_COND(
1001 "NaClSecureCommandChannel__NaClSimpleServiceStartServiceThread",
1002 !NaClSimpleServiceStartServiceThread((struct NaClSimpleService *)
1003 secure_command_server))) {
1005 "Could not start secure command channel service thread\n");
1008 NaClLog(4, "Leaving NaClSecureCommandChannel\n");
1012 void NaClAppLoadModule(struct NaClApp *nap,
1013 struct NaClDesc *nexe,
1014 void (*load_cb)(void *instance_data,
1015 NaClErrorCode status),
1016 void *instance_data) {
1017 NaClErrorCode status = LOAD_OK;
1018 int is_double_init = NaClGetInitState(nap) != NACL_MODULE_UNINITIALIZED;
1021 ("Entered NaClAppLoadModule: nap 0x%"NACL_PRIxPTR","
1022 " nexe 0x%"NACL_PRIxPTR"\n"),
1023 (uintptr_t) nap, (uintptr_t) nexe);
1025 if (NULL != load_cb) {
1026 NaClErrorCode cb_status;
1027 if (is_double_init) {
1028 cb_status = LOAD_DUP_LOAD_MODULE;
1030 cb_status = LOAD_OK;
1032 (*load_cb)(instance_data, cb_status);
1035 if (is_double_init) {
1036 NaClLog(LOG_ERROR, "NaClAppLoadModule: repeated invocation\n");
1040 NaClSetInitState(nap, NACL_MODULE_LOADING);
1043 * Ref was passed by value into |nexe| parameter, so up the refcount.
1044 * Be sure to unref when the parameter's copy goes out of scope
1049 NaClXMutexLock(&nap->mu);
1052 * TODO(teravest): Remove this when file tokens are no longer used in |nexe|.
1054 NaClReplaceDescIfValidationCacheAssertsMappable(&nexe,
1055 nap->validation_cache);
1057 /* Transfer ownership from nexe to nap->main_nexe_desc. */
1058 CHECK(nap->main_nexe_desc == NULL);
1059 nap->main_nexe_desc = nexe;
1062 status = NACL_FI_VAL("load_module", NaClErrorCode,
1063 NaClAppLoadFile(nap->main_nexe_desc, nap));
1065 if (LOAD_OK != status) {
1066 NaClDescUnref(nap->main_nexe_desc);
1067 nap->main_nexe_desc = NULL;
1069 NaClXMutexUnlock(&nap->mu); /* NaClAppPrepareToLaunch takes mu */
1071 if (LOAD_OK != status) {
1072 NaClRememberLoadStatus(nap, status);
1073 NaClSetInitState(nap, NACL_MODULE_ERROR);
1077 /***************************************************************************
1078 * TODO(bsy): Remove/merge the code invoking NaClAppPrepareToLaunch
1079 * and NaClGdbHook below with sel_main's main function. See comment
1081 ***************************************************************************/
1084 * Finish setting up the NaCl App.
1086 status = NaClAppPrepareToLaunch(nap);
1087 NaClRememberLoadStatus(nap, status);
1088 NaClSetInitState(nap, NACL_MODULE_LOADED);
1090 /* Give debuggers a well known point at which xlate_base is known. */
1094 int NaClAppRuntimeHostSetup(struct NaClApp *nap,
1095 struct NaClRuntimeHostInterface *host_itf) {
1096 NaClErrorCode status = LOAD_OK;
1099 ("Entered NaClAppRuntimeHostSetup, nap 0x%"NACL_PRIxPTR","
1100 " host_itf 0x%"NACL_PRIxPTR"\n"),
1101 (uintptr_t) nap, (uintptr_t) host_itf);
1103 NaClXMutexLock(&nap->mu);
1104 if (nap->module_initialization_state > NACL_MODULE_STARTING) {
1105 NaClLog(LOG_ERROR, "NaClAppRuntimeHostSetup: too late\n");
1106 status = LOAD_INTERNAL;
1107 goto cleanup_status_mu;
1110 nap->runtime_host_interface = (struct NaClRuntimeHostInterface *)
1111 NaClRefCountRef((struct NaClRefCount *) host_itf);
1114 * Hook up runtime host enabled resources, e.g.,
1115 * DEBUG_ONLY:dev://postmessage. NB: Resources specified by
1116 * file:path should have been taken care of earlier, in
1117 * NaClAppInitialDescriptorHookup.
1119 nap->resource_phase = NACL_RESOURCE_PHASE_RUNTIME_HOST;
1120 NaClLog(4, "Processing dev I/O redirection/inheritance from environment\n");
1121 NaClProcessRedirControl(nap);
1122 NaClLog(4, "... done.\n");
1125 NaClXMutexUnlock(&nap->mu);
1126 return (int) status;
1129 int NaClAppDescQuotaSetup(struct NaClApp *nap,
1130 struct NaClDescQuotaInterface *quota_itf) {
1131 NaClErrorCode status = LOAD_OK;
1134 ("Entered NaClAppDescQuotaSetup, nap 0x%"NACL_PRIxPTR","
1135 " quota_itf 0x%"NACL_PRIxPTR"\n"),
1136 (uintptr_t) nap, (uintptr_t) quota_itf);
1138 NaClXMutexLock(&nap->mu);
1139 if (nap->module_initialization_state > NACL_MODULE_STARTING) {
1140 NaClLog(LOG_ERROR, "NaClAppDescQuotaSetup: too late\n");
1141 status = LOAD_INTERNAL;
1142 goto cleanup_status_mu;
1145 nap->desc_quota_interface = (struct NaClDescQuotaInterface *)
1146 NaClRefCountRef((struct NaClRefCount *) quota_itf);
1149 NaClXMutexUnlock(&nap->mu);
1150 return (int) status;
1153 void NaClAppStartModule(struct NaClApp *nap,
1154 void (*start_cb)(void *instance_data,
1155 NaClErrorCode status),
1156 void *instance_data) {
1157 NaClErrorCode status;
1160 ("Entered NaClAppStartModule, nap 0x%"NACL_PRIxPTR","
1161 " start_cb 0x%"NACL_PRIxPTR", instance_data 0x%"NACL_PRIxPTR"\n"),
1162 (uintptr_t) nap, (uintptr_t) start_cb, (uintptr_t) instance_data);
1165 * When module is loading, we have to block and wait till it is
1166 * fully loaded before we can proceed with start module.
1168 NaClXMutexLock(&nap->mu);
1169 if (NACL_MODULE_LOADING == nap->module_initialization_state) {
1170 while (NACL_MODULE_LOADING == nap->module_initialization_state) {
1171 NaClXCondVarWait(&nap->cv, &nap->mu);
1174 status = nap->module_load_status;
1175 if (nap->module_initialization_state != NACL_MODULE_LOADED) {
1176 if (NACL_MODULE_ERROR == nap->module_initialization_state) {
1177 NaClLog(LOG_ERROR, "NaClAppStartModule: error loading module\n");
1178 } else if (nap->module_initialization_state > NACL_MODULE_LOADED) {
1179 NaClLog(LOG_ERROR, "NaClAppStartModule: repeated invocation\n");
1180 status = LOAD_DUP_START_MODULE;
1181 } else if (nap->module_initialization_state < NACL_MODULE_LOADED) {
1182 NaClLog(LOG_ERROR, "NaClAppStartModule: module not loaded\n");
1183 status = LOAD_INTERNAL;
1185 NaClXMutexUnlock(&nap->mu);
1186 if (NULL != start_cb) {
1187 (*start_cb)(instance_data, status);
1191 NaClXMutexUnlock(&nap->mu);
1193 NaClSetInitState(nap, NACL_MODULE_STARTING);
1195 NaClLog(4, "NaClSecureChannelStartModule: load status %d\n", status);
1198 * We need to invoke the callback now, before we signal the main thread
1199 * to possibly start by setting the state to NACL_MODULE_STARTED, since
1200 * in the case of failure the main thread may quickly exit; if the main
1201 * thread does this before we sent the reply, than the plugin (or any
1202 * other runtime host interface) will be left without an aswer. The
1203 * NACL_MODULE_STARTING state is used as an intermediate state to prevent
1204 * double invocations violating the protocol.
1206 if (NULL != start_cb) {
1207 (*start_cb)(instance_data, status);
1210 NaClSetInitState(nap, NACL_MODULE_STARTED);
1213 void NaClAppShutdown(struct NaClApp *nap,
1215 NaClLog(4, "NaClAppShutdown: nap 0x%"NACL_PRIxPTR
1216 ", exit_status %d\n", (uintptr_t) nap, exit_status);
1218 NaClXMutexLock(&nap->mu);
1219 nap->exit_status = exit_status;
1220 NaClXMutexUnlock(&nap->mu);
1221 if (NULL != nap->debug_stub_callbacks) {
1222 nap->debug_stub_callbacks->process_exit_hook();
1228 * It is fine to have multiple I/O operations read from memory in Write
1229 * or SendMsg like operations.
1231 void NaClVmIoWillStart(struct NaClApp *nap,
1232 uint32_t addr_first_usr,
1233 uint32_t addr_last_usr) {
1234 NaClXMutexLock(&nap->mu);
1235 (*nap->mem_io_regions->vtbl->AddInterval)(nap->mem_io_regions,
1238 NaClXMutexUnlock(&nap->mu);
1242 void NaClVmIoHasEnded(struct NaClApp *nap,
1243 uint32_t addr_first_usr,
1244 uint32_t addr_last_usr) {
1245 NaClXMutexLock(&nap->mu);
1246 (*nap->mem_io_regions->vtbl->RemoveInterval)(nap->mem_io_regions,
1249 NaClXMutexUnlock(&nap->mu);
1252 void NaClVmIoPendingCheck_mu(struct NaClApp *nap,
1253 uint32_t addr_first_usr,
1254 uint32_t addr_last_usr) {
1255 if ((*nap->mem_io_regions->vtbl->OverlapsWith)(nap->mem_io_regions,
1259 "NaClVmIoWillStart: program mem write race detected. ABORTING\n");
1264 * GDB's canonical overlay managment routine.
1265 * We need its symbol in the symbol table so don't inline it.
1266 * TODO(dje): add some explanation for the non-GDB person.
1269 __declspec(dllexport noinline)
1272 __attribute__((noinline))
1274 void _ovly_debug_event (void) {
1277 * The asm volatile is here as instructed by the GCC docs.
1278 * It's not enough to declare a function noinline.
1279 * GCC will still look inside the function to see if it's worth calling.
1281 __asm__ volatile ("");
1284 * Visual Studio inlines empty functions even with noinline attribute,
1285 * so we need a compile memory barrier to make this function not to be
1286 * inlined. Also, it guarantees that nacl_global_xlate_base initialization
1287 * is not reordered. This is important for gdb since it sets breakpoint on
1288 * this function and reads nacl_global_xlate_base value.
1290 _ReadWriteBarrier();
1294 static void StopForDebuggerInit (uintptr_t mem_start) {
1295 /* Put xlate_base in a place where gdb can find it. */
1296 nacl_global_xlate_base = mem_start;
1298 NaClSandboxMemoryStartForValgrind(mem_start);
1300 _ovly_debug_event();
1303 void NaClGdbHook(struct NaClApp const *nap) {
1304 StopForDebuggerInit(nap->mem_start);