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/gio/gio_nacl_desc.h"
39 #include "native_client/src/trusted/gio/gio_shm.h"
40 #include "native_client/src/trusted/interval_multiset/nacl_interval_range_tree_intern.h"
41 #include "native_client/src/trusted/service_runtime/arch/sel_ldr_arch.h"
42 #include "native_client/src/trusted/service_runtime/include/bits/nacl_syscalls.h"
43 #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
44 #include "native_client/src/trusted/service_runtime/include/sys/stat.h"
45 #include "native_client/src/trusted/service_runtime/include/sys/time.h"
46 #include "native_client/src/trusted/service_runtime/nacl_app.h"
47 #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
48 #include "native_client/src/trusted/service_runtime/nacl_desc_effector_ldr.h"
49 #include "native_client/src/trusted/service_runtime/nacl_globals.h"
50 #include "native_client/src/trusted/service_runtime/nacl_resource.h"
51 #include "native_client/src/trusted/service_runtime/nacl_reverse_quota_interface.h"
52 #include "native_client/src/trusted/service_runtime/nacl_syscall_common.h"
53 #include "native_client/src/trusted/service_runtime/nacl_syscall_handlers.h"
54 #include "native_client/src/trusted/service_runtime/nacl_valgrind_hooks.h"
55 #include "native_client/src/trusted/service_runtime/name_service/default_name_service.h"
56 #include "native_client/src/trusted/service_runtime/name_service/name_service.h"
57 #include "native_client/src/trusted/service_runtime/sel_addrspace.h"
58 #include "native_client/src/trusted/service_runtime/sel_ldr.h"
59 #include "native_client/src/trusted/service_runtime/sel_memory.h"
60 #include "native_client/src/trusted/service_runtime/sel_ldr_thread_interface.h"
61 #include "native_client/src/trusted/simple_service/nacl_simple_rservice.h"
62 #include "native_client/src/trusted/simple_service/nacl_simple_service.h"
63 #include "native_client/src/trusted/threading/nacl_thread_interface.h"
64 #include "native_client/src/trusted/validator/validation_cache.h"
66 static int IsEnvironmentVariableSet(char const *env_name) {
67 return NULL != getenv(env_name);
70 static int ShouldEnableDyncodeSyscalls(void) {
71 return !IsEnvironmentVariableSet("NACL_DISABLE_DYNCODE_SYSCALLS");
74 static int ShouldEnableDynamicLoading(void) {
75 return !IsEnvironmentVariableSet("NACL_DISABLE_DYNAMIC_LOADING");
78 int NaClAppWithSyscallTableCtor(struct NaClApp *nap,
79 struct NaClSyscallTableEntry *table) {
80 struct NaClDescEffectorLdr *effp;
82 /* Zero-initialize in case we miss any fields below. */
83 memset(nap, 0, sizeof(*nap));
85 /* The validation cache will be injected later, if it exists. */
86 nap->validation_cache = NULL;
88 nap->validator = NaClCreateValidator();
90 /* Get the set of features that the CPU we're running on supports. */
91 /* These may be adjusted later in sel_main.c for fixed-feature CPU mode. */
92 nap->cpu_features = (NaClCPUFeatures *) malloc(
93 nap->validator->CPUFeatureSize);
94 if (NULL == nap->cpu_features) {
97 nap->validator->GetCurrentCPUFeatures(nap->cpu_features);
98 nap->fixed_feature_cpu_mode = 0;
100 nap->addr_bits = NACL_MAX_ADDR_BITS;
102 nap->stack_size = NACL_DEFAULT_STACK_MAX;
103 nap->initial_nexe_max_code_bytes = 0;
107 #if (NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 \
108 && NACL_BUILD_SUBARCH == 32)
109 nap->pcrel_thunk = 0;
110 nap->pcrel_thunk_end = 0;
112 #if (NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 \
113 && NACL_BUILD_SUBARCH == 64)
114 nap->nacl_syscall_addr = 0;
115 nap->get_tls_fast_path1_addr = 0;
116 nap->get_tls_fast_path2_addr = 0;
119 nap->static_text_end = 0;
120 nap->dynamic_text_start = 0;
121 nap->dynamic_text_end = 0;
122 nap->rodata_start = 0;
126 nap->initial_entry_pt = 0;
127 nap->user_entry_pt = 0;
129 if (!DynArrayCtor(&nap->threads, 2)) {
130 goto cleanup_cpu_features;
132 if (!DynArrayCtor(&nap->desc_tbl, 2)) {
133 goto cleanup_threads;
135 if (!NaClVmmapCtor(&nap->mem_map)) {
136 goto cleanup_desc_tbl;
139 nap->mem_io_regions = (struct NaClIntervalMultiset *) malloc(
140 sizeof(struct NaClIntervalRangeTree));
141 if (NULL == nap->mem_io_regions) {
142 goto cleanup_mem_map;
145 if (!NaClIntervalRangeTreeCtor((struct NaClIntervalRangeTree *)
146 nap->mem_io_regions)) {
147 free(nap->mem_io_regions);
148 nap->mem_io_regions = NULL;
149 goto cleanup_mem_map;
152 effp = (struct NaClDescEffectorLdr *) malloc(sizeof *effp);
154 goto cleanup_mem_io_regions;
156 if (!NaClDescEffectorLdrCtor(effp, nap)) {
157 goto cleanup_effp_free;
159 nap->effp = (struct NaClDescEffector *) effp;
161 nap->enable_dyncode_syscalls = ShouldEnableDyncodeSyscalls();
162 nap->use_shm_for_dynamic_text = ShouldEnableDynamicLoading();
163 nap->text_shm = NULL;
164 if (!NaClMutexCtor(&nap->dynamic_load_mutex)) {
165 goto cleanup_effp_free;
167 nap->dynamic_page_bitmap = NULL;
169 nap->dynamic_regions = NULL;
170 nap->num_dynamic_regions = 0;
171 nap->dynamic_regions_allocated = 0;
172 nap->dynamic_delete_generation = 0;
174 nap->dynamic_mapcache_offset = 0;
175 nap->dynamic_mapcache_size = 0;
176 nap->dynamic_mapcache_ret = 0;
178 nap->service_port = NULL;
179 nap->service_address = NULL;
180 nap->secure_service_port = NULL;
181 nap->secure_service_address = NULL;
182 nap->bootstrap_channel = NULL;
183 nap->secure_service = NULL;
185 nap->main_exe_prevalidated = 0;
187 nap->kernel_service = NULL;
188 nap->resource_phase = NACL_RESOURCE_PHASE_START;
189 if (!NaClResourceNaClAppInit(&nap->resources, nap)) {
190 goto cleanup_dynamic_load_mutex;
193 if (!NaClMutexCtor(&nap->mu)) {
194 goto cleanup_dynamic_load_mutex;
196 if (!NaClCondVarCtor(&nap->cv)) {
201 nap->vm_hole_may_exist = 0;
202 nap->threads_launching = 0;
205 nap->syscall_table = table;
207 nap->runtime_host_interface = NULL;
208 nap->desc_quota_interface = NULL;
210 nap->module_initialization_state = NACL_MODULE_UNINITIALIZED;
211 nap->module_load_status = LOAD_STATUS_UNKNOWN;
213 nap->name_service = (struct NaClNameService *) malloc(
214 sizeof *nap->name_service);
215 if (NULL == nap->name_service) {
218 if (!NaClNameServiceCtor(nap->name_service,
219 NaClAddrSpSquattingThreadIfFactoryFunction,
221 free(nap->name_service);
224 nap->name_service_conn_cap = NaClDescRef(nap->name_service->
225 base.base.bound_and_cap[1]);
226 if (!NaClDefaultNameServiceInit(nap->name_service)) {
227 goto cleanup_name_service;
230 nap->ignore_validator_result = 0;
231 nap->skip_validator = 0;
232 nap->validator_stub_out_mode = 0;
234 if (IsEnvironmentVariableSet("NACL_DANGEROUS_ENABLE_FILE_ACCESS")) {
235 NaClInsecurelyBypassAllAclChecks();
236 NaClLog(LOG_INFO, "DANGER: ENABLED FILE ACCESS\n");
239 nap->enable_list_mappings = 0;
240 if (IsEnvironmentVariableSet("NACL_DANGEROUS_ENABLE_LIST_MAPPINGS")) {
242 * This syscall is not actually know to be dangerous, but is not yet
243 * exposed by our public API.
245 NaClLog(LOG_INFO, "DANGER: ENABLED LIST_MAPPINGS\n");
246 nap->enable_list_mappings = 1;
249 if (!NaClMutexCtor(&nap->threads_mu)) {
250 goto cleanup_name_service;
252 nap->num_threads = 0;
253 if (!NaClFastMutexCtor(&nap->desc_mu)) {
254 goto cleanup_threads_mu;
258 nap->exit_status = -1;
260 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
261 nap->code_seg_sel = 0;
262 nap->data_seg_sel = 0;
265 nap->debug_stub_callbacks = NULL;
266 nap->exception_handler = 0;
267 if (!NaClMutexCtor(&nap->exception_mu)) {
268 goto cleanup_desc_mu;
270 nap->enable_exception_handling = 0;
272 nap->debug_exception_handler_state = NACL_DEBUG_EXCEPTION_HANDLER_NOT_STARTED;
273 nap->attach_debug_exception_handler_func = NULL;
275 nap->enable_faulted_thread_queue = 0;
276 nap->faulted_thread_count = 0;
278 nap->faulted_thread_event = INVALID_HANDLE_VALUE;
280 nap->faulted_thread_fd_read = -1;
281 nap->faulted_thread_fd_write = -1;
285 #if NACL_LINUX || NACL_OSX
287 * Try to pre-cache information that we can't obtain with the outer
288 * sandbox on. If the outer sandbox has already been enabled, this
289 * will just set sc_nprocessors_onln to -1, and it is the
290 * responsibility of the caller to replace this with a sane value
291 * after the Ctor returns.
293 nap->sc_nprocessors_onln = sysconf(_SC_NPROCESSORS_ONLN);
296 if (!NaClMutexCtor(&nap->futex_wait_list_mu)) {
297 goto cleanup_exception_mu;
299 nap->futex_wait_list_head.next = &nap->futex_wait_list_head;
300 nap->futex_wait_list_head.prev = &nap->futex_wait_list_head;
304 cleanup_exception_mu:
305 NaClMutexDtor(&nap->exception_mu);
307 NaClFastMutexDtor(&nap->desc_mu);
309 NaClMutexDtor(&nap->threads_mu);
310 cleanup_name_service:
311 NaClDescUnref(nap->name_service_conn_cap);
312 NaClRefCountUnref((struct NaClRefCount *) nap->name_service);
314 NaClCondVarDtor(&nap->cv);
316 NaClMutexDtor(&nap->mu);
317 cleanup_dynamic_load_mutex:
318 NaClMutexDtor(&nap->dynamic_load_mutex);
321 cleanup_mem_io_regions:
322 NaClIntervalMultisetDelete(nap->mem_io_regions);
323 nap->mem_io_regions = NULL;
325 NaClVmmapDtor(&nap->mem_map);
327 DynArrayDtor(&nap->desc_tbl);
329 DynArrayDtor(&nap->threads);
330 cleanup_cpu_features:
331 free(nap->cpu_features);
336 int NaClAppCtor(struct NaClApp *nap) {
337 return NaClAppWithSyscallTableCtor(nap, nacl_syscall);
340 struct NaClApp *NaClAppCreate(void) {
341 struct NaClApp *nap = malloc(sizeof(struct NaClApp));
343 NaClLog(LOG_FATAL, "Failed to allocate NaClApp\n");
344 if (!NaClAppCtor(nap))
345 NaClLog(LOG_FATAL, "NaClAppCtor() failed\n");
350 * unaligned little-endian load. precondition: nbytes should never be
353 static uint64_t NaClLoadMem(uintptr_t addr,
354 size_t user_nbytes) {
357 CHECK(0 != user_nbytes && user_nbytes <= 8);
361 value |= ((uint8_t *) addr)[--user_nbytes];
362 } while (user_nbytes > 0);
366 #define GENERIC_LOAD(bits) \
367 static uint ## bits ## _t NaClLoad ## bits(uintptr_t addr) { \
368 return (uint ## bits ## _t) NaClLoadMem(addr, sizeof(uint ## bits ## _t)); \
371 #if NACL_TARGET_SUBARCH == 32
379 * unaligned little-endian store
381 static void NaClStoreMem(uintptr_t addr,
388 for (i = 0; i < nbytes; ++i) {
389 ((uint8_t *) addr)[i] = (uint8_t) value;
394 #define GENERIC_STORE(bits) \
395 static void NaClStore ## bits(uintptr_t addr, \
396 uint ## bits ## _t v) { \
397 NaClStoreMem(addr, sizeof(uint ## bits ## _t), v); \
406 struct NaClPatchInfo *NaClPatchInfoCtor(struct NaClPatchInfo *self) {
408 memset(self, 0, sizeof *self);
414 * This function is called by NaClLoadTrampoline and NaClLoadSpringboard to
415 * patch a single memory location specified in NaClPatchInfo structure.
417 void NaClApplyPatchToMemory(struct NaClPatchInfo *patch) {
421 uintptr_t target_addr;
423 memcpy((void *) patch->dst, (void *) patch->src, patch->nbytes);
425 reloc = patch->dst - patch->src;
428 for (i = 0; i < patch->num_abs64; ++i) {
429 offset = patch->abs64[i].target - patch->src;
430 target_addr = patch->dst + offset;
431 NaClStore64(target_addr, patch->abs64[i].value);
434 for (i = 0; i < patch->num_abs32; ++i) {
435 offset = patch->abs32[i].target - patch->src;
436 target_addr = patch->dst + offset;
437 NaClStore32(target_addr, (uint32_t) patch->abs32[i].value);
440 for (i = 0; i < patch->num_abs16; ++i) {
441 offset = patch->abs16[i].target - patch->src;
442 target_addr = patch->dst + offset;
443 NaClStore16(target_addr, (uint16_t) patch->abs16[i].value);
446 for (i = 0; i < patch->num_rel64; ++i) {
447 offset = patch->rel64[i] - patch->src;
448 target_addr = patch->dst + offset;
449 NaClStore64(target_addr, NaClLoad64(target_addr) - reloc);
453 * rel32 is only supported on 32-bit architectures. The range of a relative
454 * relocation in untrusted space is +/- 4GB. This can be represented as
455 * an unsigned 32-bit value mod 2^32, which is handy on a 32 bit system since
456 * all 32-bit pointer arithmetic is implicitly mod 2^32. On a 64 bit system,
457 * however, pointer arithmetic is implicitly modulo 2^64, which isn't as
458 * helpful for our purposes. We could simulate the 32-bit behavior by
459 * explicitly modding all relative addresses by 2^32, but that seems like an
460 * expensive way to save a few bytes per reloc.
462 #if NACL_TARGET_SUBARCH == 32
463 for (i = 0; i < patch->num_rel32; ++i) {
464 offset = patch->rel32[i] - patch->src;
465 target_addr = patch->dst + offset;
466 NaClStore32(target_addr,
467 (uint32_t) NaClLoad32(target_addr) - (int32_t) reloc);
474 * Install syscall trampolines at all possible well-formed entry
475 * points within the trampoline pages. Many of these syscalls will
476 * correspond to unimplemented system calls and will just abort the
479 void NaClLoadTrampoline(struct NaClApp *nap) {
484 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32
485 if (!NaClMakePcrelThunk(nap)) {
486 NaClLog(LOG_FATAL, "NaClMakePcrelThunk failed!\n");
489 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64
490 if (!NaClMakeDispatchAddrs(nap)) {
491 NaClLog(LOG_FATAL, "NaClMakeDispatchAddrs failed!\n");
494 NaClFillTrampolineRegion(nap);
497 * Do not bother to fill in the contents of page 0, since we make it
498 * inaccessible later (see sel_addrspace.c, NaClMemoryProtection)
499 * anyway to help detect NULL pointer errors, and we might as well
500 * not dirty the page.
502 * The last syscall entry point is used for springboard code.
504 num_syscalls = ((NACL_TRAMPOLINE_END - NACL_SYSCALL_START_ADDR)
505 / NACL_SYSCALL_BLOCK_SIZE) - 1;
507 NaClLog(2, "num_syscalls = %d (0x%x)\n", num_syscalls, num_syscalls);
509 for (i = 0, addr = nap->mem_start + NACL_SYSCALL_START_ADDR;
511 ++i, addr += NACL_SYSCALL_BLOCK_SIZE) {
512 NaClPatchOneTrampoline(nap, addr);
514 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64
515 NaClPatchOneTrampolineCall(nap->get_tls_fast_path1_addr,
516 nap->mem_start + NACL_SYSCALL_START_ADDR
517 + NACL_SYSCALL_BLOCK_SIZE * NACL_sys_tls_get);
518 NaClPatchOneTrampolineCall(nap->get_tls_fast_path2_addr,
519 nap->mem_start + NACL_SYSCALL_START_ADDR
520 + (NACL_SYSCALL_BLOCK_SIZE *
521 NACL_sys_second_tls_get));
524 NACL_TEST_INJECTION(ChangeTrampolines, (nap));
527 void NaClMemRegionPrinter(void *state,
528 struct NaClVmmapEntry *entry) {
529 struct Gio *gp = (struct Gio *) state;
531 gprintf(gp, "\nPage %"NACL_PRIdPTR" (0x%"NACL_PRIxPTR")\n",
532 entry->page_num, entry->page_num);
533 gprintf(gp, "npages %"NACL_PRIdS" (0x%"NACL_PRIxS")\n", entry->npages,
535 gprintf(gp, "start vaddr 0x%"NACL_PRIxPTR"\n",
536 entry->page_num << NACL_PAGESHIFT);
537 gprintf(gp, "end vaddr 0x%"NACL_PRIxPTR"\n",
538 (entry->page_num + entry->npages) << NACL_PAGESHIFT);
539 gprintf(gp, "prot 0x%08x\n", entry->prot);
540 gprintf(gp, "%sshared/backed by a file\n",
541 (NULL == entry->desc) ? "not " : "");
544 void NaClAppPrintDetails(struct NaClApp *nap,
546 NaClXMutexLock(&nap->mu);
548 "NaClAppPrintDetails((struct NaClApp *) 0x%08"NACL_PRIxPTR","
549 "(struct Gio *) 0x%08"NACL_PRIxPTR")\n", (uintptr_t) nap,
551 gprintf(gp, "addr space size: 2**%"NACL_PRId32"\n", nap->addr_bits);
552 gprintf(gp, "stack size: 0x%08"NACL_PRIx32"\n", nap->stack_size);
554 gprintf(gp, "mem start addr: 0x%08"NACL_PRIxPTR"\n", nap->mem_start);
555 /* 123456789012345678901234567890 */
557 gprintf(gp, "static_text_end: 0x%08"NACL_PRIxPTR"\n", nap->static_text_end);
558 gprintf(gp, "end-of-text: 0x%08"NACL_PRIxPTR"\n",
559 NaClEndOfStaticText(nap));
560 gprintf(gp, "rodata: 0x%08"NACL_PRIxPTR"\n", nap->rodata_start);
561 gprintf(gp, "data: 0x%08"NACL_PRIxPTR"\n", nap->data_start);
562 gprintf(gp, "data_end: 0x%08"NACL_PRIxPTR"\n", nap->data_end);
563 gprintf(gp, "break_addr: 0x%08"NACL_PRIxPTR"\n", nap->break_addr);
565 gprintf(gp, "ELF initial entry point: 0x%08x\n", nap->initial_entry_pt);
566 gprintf(gp, "ELF user entry point: 0x%08x\n", nap->user_entry_pt);
567 gprintf(gp, "memory map:\n");
568 NaClVmmapVisit(&nap->mem_map,
569 NaClMemRegionPrinter,
571 NaClXMutexUnlock(&nap->mu);
574 struct NaClDesc *NaClAppGetDescMu(struct NaClApp *nap,
576 struct NaClDesc *result;
578 result = (struct NaClDesc *) DynArrayGet(&nap->desc_tbl, d);
579 if (NULL != result) {
586 void NaClAppSetDescMu(struct NaClApp *nap,
588 struct NaClDesc *ndp) {
589 struct NaClDesc *result;
591 result = (struct NaClDesc *) DynArrayGet(&nap->desc_tbl, d);
592 NaClDescSafeUnref(result);
594 if (!DynArraySet(&nap->desc_tbl, d, ndp)) {
596 "NaClAppSetDesc: could not set descriptor %d to 0x%08"
603 int32_t NaClAppSetDescAvailMu(struct NaClApp *nap,
604 struct NaClDesc *ndp) {
607 pos = DynArrayFirstAvail(&nap->desc_tbl);
609 if (pos > INT32_MAX) {
611 ("NaClAppSetDescAvailMu: DynArrayFirstAvail returned a value"
612 " that is greather than 2**31-1.\n"));
615 NaClAppSetDescMu(nap, (int) pos, ndp);
617 return (int32_t) pos;
620 struct NaClDesc *NaClAppGetDesc(struct NaClApp *nap,
622 struct NaClDesc *res;
624 NaClFastMutexLock(&nap->desc_mu);
625 res = NaClAppGetDescMu(nap, d);
626 NaClFastMutexUnlock(&nap->desc_mu);
630 void NaClAppSetDesc(struct NaClApp *nap,
632 struct NaClDesc *ndp) {
633 NaClFastMutexLock(&nap->desc_mu);
634 NaClAppSetDescMu(nap, d, ndp);
635 NaClFastMutexUnlock(&nap->desc_mu);
638 int32_t NaClAppSetDescAvail(struct NaClApp *nap,
639 struct NaClDesc *ndp) {
642 NaClFastMutexLock(&nap->desc_mu);
643 pos = NaClAppSetDescAvailMu(nap, ndp);
644 NaClFastMutexUnlock(&nap->desc_mu);
649 int NaClAddThreadMu(struct NaClApp *nap,
650 struct NaClAppThread *natp) {
653 pos = DynArrayFirstAvail(&nap->threads);
655 if (!DynArraySet(&nap->threads, pos, natp)) {
657 "NaClAddThreadMu: DynArraySet at position %"NACL_PRIuS" failed\n",
664 int NaClAddThread(struct NaClApp *nap,
665 struct NaClAppThread *natp) {
668 NaClXMutexLock(&nap->threads_mu);
669 pos = NaClAddThreadMu(nap, natp);
670 NaClXMutexUnlock(&nap->threads_mu);
675 void NaClRemoveThreadMu(struct NaClApp *nap,
677 if (NULL == DynArrayGet(&nap->threads, thread_num)) {
679 "NaClRemoveThreadMu:: thread to be removed is not in the table\n");
681 if (nap->num_threads == 0) {
683 "NaClRemoveThreadMu:: num_threads cannot be 0!!!\n");
686 if (!DynArraySet(&nap->threads, thread_num, (struct NaClAppThread *) NULL)) {
688 "NaClRemoveThreadMu:: DynArraySet at position %d failed\n",
693 void NaClRemoveThread(struct NaClApp *nap,
695 NaClXMutexLock(&nap->threads_mu);
696 NaClRemoveThreadMu(nap, thread_num);
697 NaClXMutexUnlock(&nap->threads_mu);
700 struct NaClAppThread *NaClGetThreadMu(struct NaClApp *nap,
702 return (struct NaClAppThread *) DynArrayGet(&nap->threads, thread_num);
705 void NaClAddHostDescriptor(struct NaClApp *nap,
709 struct NaClDescIoDesc *dp;
712 "NaClAddHostDescriptor: host %d as nacl desc %d, flag 0x%x\n",
716 dp = NaClDescIoDescMake(NaClHostDescPosixMake(host_os_desc, flag));
718 NaClLog(LOG_FATAL, "NaClAddHostDescriptor: NaClDescIoDescMake failed\n");
720 NaClAppSetDesc(nap, nacl_desc, (struct NaClDesc *) dp);
723 void NaClAddImcHandle(struct NaClApp *nap,
726 struct NaClDescImcDesc *dp;
729 ("NaClAddImcHandle: importing NaClHandle %"NACL_PRIxPTR
730 " as nacl desc %d\n"),
733 dp = (struct NaClDescImcDesc *) malloc(sizeof *dp);
734 if (NACL_FI_ERROR_COND("NaClAddImcHandle__malloc", NULL == dp)) {
735 NaClLog(LOG_FATAL, "NaClAddImcHandle: no memory\n");
737 if (NACL_FI_ERROR_COND("NaClAddImcHandle__ctor",
738 !NaClDescImcDescCtor(dp, h))) {
739 NaClLog(LOG_FATAL, ("NaClAddImcHandle: cannot construct"
740 " IMC descriptor object\n"));
742 NaClAppSetDesc(nap, nacl_desc, (struct NaClDesc *) dp);
748 char const *env_name;
751 } const g_nacl_redir_control[] = {
752 { 0, "NACL_EXE_STDIN",
753 NACL_ABI_O_RDONLY, 0, },
754 { 1, "NACL_EXE_STDOUT",
755 NACL_ABI_O_WRONLY | NACL_ABI_O_APPEND | NACL_ABI_O_CREAT, 0777, },
756 { 2, "NACL_EXE_STDERR",
757 NACL_ABI_O_WRONLY | NACL_ABI_O_APPEND | NACL_ABI_O_CREAT, 0777, },
761 * File redirection is impossible if an outer sandbox is in place.
762 * For the command-line embedding, we sometimes have an outer sandbox:
763 * on OSX, it is enabled after loading the file is loaded. On the
764 * other hand, device redirection (DEBUG_ONLY:dev://postmessage) is
765 * impossible until the reverse channel setup has occurred.
767 * Because of this, we run NaClProcessRedirControl twice: once to
768 * process default inheritance, file redirection early on, and once
769 * after the reverse channel is in place to handle the device
770 * redirection. We try to hide knowledge about which redirection
771 * control values can be handled in which phases by allowing the
772 * NaClResourceOpen to fail, and only in the last phase do we check
773 * that the redirection succeeded in *some* phase.
775 static void NaClProcessRedirControl(struct NaClApp *nap) {
779 struct NaClDesc *ndp;
781 for (ix = 0; ix < NACL_ARRAY_SIZE(g_nacl_redir_control); ++ix) {
783 if (NULL != (env = getenv(g_nacl_redir_control[ix].env_name))) {
784 NaClLog(4, "getenv(%s) -> %s\n", g_nacl_redir_control[ix].env_name, env);
785 ndp = NaClResourceOpen((struct NaClResource *) &nap->resources,
787 g_nacl_redir_control[ix].nacl_flags,
788 g_nacl_redir_control[ix].mode);
789 NaClLog(4, " NaClResourceOpen returned %"NACL_PRIxPTR"\n",
794 NaClLog(4, "Setting descriptor %d\n", (int) ix);
795 NaClAppSetDesc(nap, (int) ix, ndp);
796 } else if (NACL_RESOURCE_PHASE_START == nap->resource_phase) {
798 * Environment not set or redirect failed -- handle default inheritance.
800 NaClAddHostDescriptor(nap, DUP(g_nacl_redir_control[ix].d),
801 g_nacl_redir_control[ix].nacl_flags, (int) ix);
807 * Process default descriptor inheritance. This means dup'ing
808 * descriptors 0-2 and making them available to the NaCl App.
810 * When standard input is inherited, this could result in a NaCl
811 * module competing for input from the terminal; for graphical /
812 * browser plugin environments, this never is allowed to happen, and
813 * having this is useful for debugging, and for potential standalone
814 * text-mode applications of NaCl.
816 * TODO(bsy): consider whether default inheritance should occur only
819 void NaClAppInitialDescriptorHookup(struct NaClApp *nap) {
821 NaClLog(4, "Processing I/O redirection/inheritance from environment\n");
822 nap->resource_phase = NACL_RESOURCE_PHASE_START;
823 NaClProcessRedirControl(nap);
824 NaClLog(4, "... done.\n");
827 void NaClCreateServiceSocket(struct NaClApp *nap) {
828 struct NaClDesc *secure_pair[2];
829 struct NaClDesc *pair[2];
831 NaClLog(3, "Entered NaClCreateServiceSocket\n");
833 if (NACL_FI_ERROR_COND("NaClCreateServiceSocket__secure_boundsock",
834 0 != NaClCommonDescMakeBoundSock(secure_pair))) {
835 NaClLog(LOG_FATAL, "Cound not create secure service socket\n");
838 "got bound socket at 0x%08"NACL_PRIxPTR", "
839 "addr at 0x%08"NACL_PRIxPTR"\n",
840 (uintptr_t) secure_pair[0],
841 (uintptr_t) secure_pair[1]);
843 NaClDescSafeUnref(nap->secure_service_port);
844 nap->secure_service_port = secure_pair[0];
846 NaClDescSafeUnref(nap->secure_service_address);
847 nap->secure_service_address = secure_pair[1];
849 if (NACL_FI_ERROR_COND("NaClCreateServiceSocket__boundsock",
850 0 != NaClCommonDescMakeBoundSock(pair))) {
851 NaClLog(LOG_FATAL, "Cound not create service socket\n");
854 "got bound socket at 0x%08"NACL_PRIxPTR", "
855 "addr at 0x%08"NACL_PRIxPTR"\n",
857 (uintptr_t) pair[1]);
858 NaClAppSetDesc(nap, NACL_SERVICE_PORT_DESCRIPTOR, pair[0]);
859 NaClAppSetDesc(nap, NACL_SERVICE_ADDRESS_DESCRIPTOR, pair[1]);
861 NaClDescSafeUnref(nap->service_port);
863 nap->service_port = pair[0];
864 NaClDescRef(nap->service_port);
866 NaClDescSafeUnref(nap->service_address);
868 nap->service_address = pair[1];
869 NaClDescRef(nap->service_address);
871 NaClLog(4, "Leaving NaClCreateServiceSocket\n");
875 * Import the |inherited_desc| descriptor as an IMC handle, save a
876 * reference to it at nap->bootstrap_channel, then send the
877 * service_address over that channel.
879 void NaClSetUpBootstrapChannel(struct NaClApp *nap,
880 NaClHandle inherited_desc) {
881 struct NaClDescImcDesc *channel;
882 struct NaClImcTypedMsgHdr hdr;
883 struct NaClDesc *descs[2];
887 "NaClSetUpBootstrapChannel(0x%08"NACL_PRIxPTR", %"NACL_PRIdPTR")\n",
889 (uintptr_t) inherited_desc);
891 channel = (struct NaClDescImcDesc *) malloc(sizeof *channel);
892 if (NULL == channel) {
893 NaClLog(LOG_FATAL, "NaClSetUpBootstrapChannel: no memory\n");
895 if (!NaClDescImcDescCtor(channel, inherited_desc)) {
897 ("NaClSetUpBootstrapChannel: cannot construct IMC descriptor"
898 " object for inherited descriptor %"NACL_PRIdPTR"\n"),
899 (uintptr_t) inherited_desc);
902 if (NULL == nap->secure_service_address) {
904 "NaClSetUpBootstrapChannel: secure service address not set\n");
907 if (NULL == nap->service_address) {
909 "NaClSetUpBootstrapChannel: service address not set\n");
913 * service_address and service_port are set together.
915 descs[0] = nap->secure_service_address;
916 descs[1] = nap->service_address;
918 hdr.iov = (struct NaClImcMsgIoVec *) NULL;
921 hdr.ndesc_length = NACL_ARRAY_SIZE(descs);
923 rv = (*NACL_VTBL(NaClDesc, channel)->SendMsg)((struct NaClDesc *) channel,
925 NaClXMutexLock(&nap->mu);
926 if (NULL != nap->bootstrap_channel) {
928 "NaClSetUpBootstrapChannel: cannot have two bootstrap channels\n");
930 nap->bootstrap_channel = (struct NaClDesc *) channel;
932 NaClXMutexUnlock(&nap->mu);
935 ("NaClSetUpBootstrapChannel: descriptor %"NACL_PRIdPTR
936 ", error %"NACL_PRIdS"\n"),
937 (uintptr_t) inherited_desc,
939 if (NACL_FI_ERROR_COND("NaClSetUpBootstrapChannel__SendMsg", 0 != rv)) {
941 "NaClSetUpBootstrapChannel: SendMsg failed, rv = %"NACL_PRIdS"\n",
946 NaClErrorCode NaClWaitForLoadModuleCommand(struct NaClApp *nap) {
947 NaClErrorCode status;
949 NaClLog(4, "NaClWaitForLoadModuleCommand started\n");
950 NaClXMutexLock(&nap->mu);
951 while (nap->module_initialization_state < NACL_MODULE_LOADED) {
952 NaClXCondVarWait(&nap->cv, &nap->mu);
954 status = nap->module_load_status;
955 NaClXMutexUnlock(&nap->mu);
956 NaClLog(4, "NaClWaitForLoadModuleCommand finished\n");
961 NaClErrorCode NaClWaitForLoadModuleStatus(struct NaClApp *nap) {
962 NaClErrorCode status;
964 NaClLog(4, "NaClWaitForLoadModuleStatus started\n");
965 NaClXMutexLock(&nap->mu);
966 while (LOAD_STATUS_UNKNOWN == (status = nap->module_load_status)) {
967 NaClXCondVarWait(&nap->cv, &nap->mu);
969 NaClXMutexUnlock(&nap->mu);
970 NaClLog(4, "NaClWaitForLoadModuleStatus finished\n");
975 NaClErrorCode NaClWaitForStartModuleCommand(struct NaClApp *nap) {
976 NaClErrorCode status;
978 NaClLog(4, "NaClWaitForStartModuleCommand started\n");
979 NaClXMutexLock(&nap->mu);
980 while (nap->module_initialization_state < NACL_MODULE_STARTED) {
981 NaClXCondVarWait(&nap->cv, &nap->mu);
983 status = nap->module_load_status;
984 NaClXMutexUnlock(&nap->mu);
985 NaClLog(4, "NaClWaitForStartModuleCommand finished\n");
990 void NaClBlockIfCommandChannelExists(struct NaClApp *nap) {
991 if (NULL != nap->secure_service) {
993 struct nacl_abi_timespec req;
996 NaClNanosleep(&req, (struct nacl_abi_timespec *) NULL);
1001 void NaClSecureCommandChannel(struct NaClApp *nap) {
1002 struct NaClSecureService *secure_command_server;
1004 NaClLog(4, "Entered NaClSecureCommandChannel\n");
1006 secure_command_server = (struct NaClSecureService *) malloc(
1007 sizeof *secure_command_server);
1008 if (NACL_FI_ERROR_COND("NaClSecureCommandChannel__malloc",
1009 NULL == secure_command_server)) {
1010 NaClLog(LOG_FATAL, "Out of memory for secure command channel\n");
1012 if (NACL_FI_ERROR_COND("NaClSecureCommandChannel__NaClSecureServiceCtor",
1013 !NaClSecureServiceCtor(secure_command_server,
1015 nap->secure_service_port,
1016 nap->secure_service_address))) {
1017 NaClLog(LOG_FATAL, "NaClSecureServiceCtor failed\n");
1019 nap->secure_service = secure_command_server;
1021 NaClLog(4, "NaClSecureCommandChannel: starting service thread\n");
1022 if (NACL_FI_ERROR_COND(
1023 "NaClSecureCommandChannel__NaClSimpleServiceStartServiceThread",
1024 !NaClSimpleServiceStartServiceThread((struct NaClSimpleService *)
1025 secure_command_server))) {
1027 "Could not start secure command channel service thread\n");
1030 NaClLog(4, "Leaving NaClSecureCommandChannel\n");
1034 void NaClAppLoadModule(struct NaClApp *nap,
1035 struct NaClDesc *nexe,
1036 void (*load_cb)(void *instance_data,
1037 NaClErrorCode status),
1038 void *instance_data) {
1039 NaClErrorCode status = LOAD_OK;
1042 ("Entered NaClAppLoadModule: nap 0x%"NACL_PRIxPTR","
1043 " nexe 0x%"NACL_PRIxPTR"\n"),
1044 (uintptr_t) nap, (uintptr_t) nexe);
1047 * TODO(bsy): consider doing the processing below after sending the
1048 * RPC reply to increase parallelism.
1050 NaClXMutexLock(&nap->mu);
1051 if (nap->module_initialization_state != NACL_MODULE_UNINITIALIZED) {
1052 NaClLog(LOG_ERROR, "NaClAppLoadModule: repeated invocation\n");
1053 status = LOAD_DUP_LOAD_MODULE;
1054 NaClXMutexUnlock(&nap->mu);
1055 if (NULL != load_cb) {
1056 (*load_cb)(instance_data, status);
1060 nap->module_initialization_state = NACL_MODULE_LOADING;
1061 NaClXCondVarBroadcast(&nap->cv);
1062 NaClXMutexUnlock(&nap->mu);
1064 if (NULL != load_cb) {
1065 (*load_cb)(instance_data, status);
1068 NaClXMutexLock(&nap->mu);
1071 * Check and possibly mark the nexe binary as OK to attempt memory
1072 * mapping. We first clear the safe-for-mmap flag -- if we do not
1073 * trust the renderer to really send us a safe-to-mmap descriptor
1074 * and have to query the validation cache, then we also do not want
1075 * to trust the metadata flag value that originated from the
1078 NaClDescMarkUnsafeForMmap(nexe);
1079 NaClReplaceDescIfValidationCacheAssertsMappable(&nexe,
1080 nap->validation_cache);
1082 status = NACL_FI_VAL("load_module", NaClErrorCode,
1083 NaClAppLoadFile(nexe, nap));
1085 if (LOAD_OK != status) {
1086 nap->module_load_status = status;
1087 nap->module_initialization_state = NACL_MODULE_ERROR;
1088 NaClXCondVarBroadcast(&nap->cv);
1090 NaClXMutexUnlock(&nap->mu); /* NaClAppPrepareToLaunch takes mu */
1091 if (LOAD_OK != status) {
1095 /***************************************************************************
1096 * TODO(bsy): Remove/merge the code invoking NaClAppPrepareToLaunch
1097 * and NaClGdbHook below with sel_main's main function. See comment
1099 ***************************************************************************/
1102 * Finish setting up the NaCl App.
1104 status = NaClAppPrepareToLaunch(nap);
1106 NaClXMutexLock(&nap->mu);
1107 nap->module_load_status = status;
1108 nap->module_initialization_state = NACL_MODULE_LOADED;
1109 NaClXCondVarBroadcast(&nap->cv);
1110 NaClXMutexUnlock(&nap->mu);
1112 /* Give debuggers a well known point at which xlate_base is known. */
1116 int NaClAppRuntimeHostSetup(struct NaClApp *nap,
1117 struct NaClRuntimeHostInterface *host_itf) {
1118 NaClErrorCode status = LOAD_OK;
1121 ("Entered NaClAppRuntimeHostSetup, nap 0x%"NACL_PRIxPTR","
1122 " host_itf 0x%"NACL_PRIxPTR"\n"),
1123 (uintptr_t) nap, (uintptr_t) host_itf);
1125 NaClXMutexLock(&nap->mu);
1126 if (nap->module_initialization_state > NACL_MODULE_STARTING) {
1127 NaClLog(LOG_ERROR, "NaClAppRuntimeHostSetup: too late\n");
1128 status = LOAD_INTERNAL;
1129 goto cleanup_status_mu;
1132 nap->runtime_host_interface = (struct NaClRuntimeHostInterface *)
1133 NaClRefCountRef((struct NaClRefCount *) host_itf);
1136 * Hook up runtime host enabled resources, e.g.,
1137 * DEBUG_ONLY:dev://postmessage. NB: Resources specified by
1138 * file:path should have been taken care of earlier, in
1139 * NaClAppInitialDescriptorHookup.
1141 nap->resource_phase = NACL_RESOURCE_PHASE_RUNTIME_HOST;
1142 NaClLog(4, "Processing dev I/O redirection/inheritance from environment\n");
1143 NaClProcessRedirControl(nap);
1144 NaClLog(4, "... done.\n");
1147 NaClXMutexUnlock(&nap->mu);
1148 return (int) status;
1151 int NaClAppDescQuotaSetup(struct NaClApp *nap,
1152 struct NaClDescQuotaInterface *quota_itf) {
1153 NaClErrorCode status = LOAD_OK;
1156 ("Entered NaClAppDescQuotaSetup, nap 0x%"NACL_PRIxPTR","
1157 " quota_itf 0x%"NACL_PRIxPTR"\n"),
1158 (uintptr_t) nap, (uintptr_t) quota_itf);
1160 NaClXMutexLock(&nap->mu);
1161 if (nap->module_initialization_state > NACL_MODULE_STARTING) {
1162 NaClLog(LOG_ERROR, "NaClAppDescQuotaSetup: too late\n");
1163 status = LOAD_INTERNAL;
1164 goto cleanup_status_mu;
1167 nap->desc_quota_interface = (struct NaClDescQuotaInterface *)
1168 NaClRefCountRef((struct NaClRefCount *) quota_itf);
1171 NaClXMutexUnlock(&nap->mu);
1172 return (int) status;
1175 void NaClAppStartModule(struct NaClApp *nap,
1176 void (*start_cb)(void *instance_data,
1177 NaClErrorCode status),
1178 void *instance_data) {
1179 NaClErrorCode status;
1182 ("Entered NaClAppStartModule, nap 0x%"NACL_PRIxPTR","
1183 " start_cb 0x%"NACL_PRIxPTR", instance_data 0x%"NACL_PRIxPTR"\n"),
1184 (uintptr_t) nap, (uintptr_t) start_cb, (uintptr_t) instance_data);
1187 * When module is loading, we have to block and wait till it is
1188 * fully loaded before we can proceed with start module.
1190 NaClXMutexLock(&nap->mu);
1191 if (NACL_MODULE_LOADING == nap->module_initialization_state) {
1192 while (NACL_MODULE_LOADED != nap->module_initialization_state) {
1193 NaClXCondVarWait(&nap->cv, &nap->mu);
1196 if (nap->module_initialization_state != NACL_MODULE_LOADED) {
1197 if (NACL_MODULE_ERROR == nap->module_initialization_state) {
1198 NaClLog(LOG_ERROR, "NaClAppStartModule: error loading module\n");
1199 status = nap->module_load_status;
1200 } else if (nap->module_initialization_state > NACL_MODULE_LOADED) {
1201 NaClLog(LOG_ERROR, "NaClAppStartModule: repeated invocation\n");
1202 status = LOAD_DUP_START_MODULE;
1203 } else if (nap->module_initialization_state < NACL_MODULE_LOADED) {
1204 NaClLog(LOG_ERROR, "NaClAppStartModule: module not loaded\n");
1205 status = LOAD_INTERNAL;
1207 NaClXMutexUnlock(&nap->mu);
1208 if (NULL != start_cb) {
1209 (*start_cb)(instance_data, status);
1213 status = nap->module_load_status;
1214 nap->module_initialization_state = NACL_MODULE_STARTING;
1215 NaClXCondVarBroadcast(&nap->cv);
1216 NaClXMutexUnlock(&nap->mu);
1218 NaClLog(4, "NaClSecureChannelStartModule: load status %d\n", status);
1221 * We need to invoke the callback now, before we signal the main thread
1222 * to possibly start by setting the state to NACL_MODULE_STARTED, since
1223 * in the case of failure the main thread may quickly exit; if the main
1224 * thread does this before we sent the reply, than the plugin (or any
1225 * other runtime host interface) will be left without an aswer. The
1226 * NACL_MODULE_STARTING state is used as an intermediate state to prevent
1227 * double invocations violating the protocol.
1229 if (NULL != start_cb) {
1230 (*start_cb)(instance_data, status);
1233 NaClXMutexLock(&nap->mu);
1234 nap->module_initialization_state = NACL_MODULE_STARTED;
1235 NaClXCondVarBroadcast(&nap->cv);
1236 NaClXMutexUnlock(&nap->mu);
1239 void NaClAppShutdown(struct NaClApp *nap,
1241 NaClLog(4, "NaClAppShutdown: nap 0x%"NACL_PRIxPTR
1242 ", exit_status %d\n", (uintptr_t) nap, exit_status);
1244 NaClXMutexLock(&nap->mu);
1245 nap->exit_status = exit_status;
1246 NaClXMutexUnlock(&nap->mu);
1247 if (NULL != nap->debug_stub_callbacks) {
1248 nap->debug_stub_callbacks->process_exit_hook();
1254 * It is fine to have multiple I/O operations read from memory in Write
1255 * or SendMsg like operations.
1257 void NaClVmIoWillStart(struct NaClApp *nap,
1258 uint32_t addr_first_usr,
1259 uint32_t addr_last_usr) {
1260 NaClXMutexLock(&nap->mu);
1261 (*nap->mem_io_regions->vtbl->AddInterval)(nap->mem_io_regions,
1264 NaClXMutexUnlock(&nap->mu);
1268 void NaClVmIoHasEnded(struct NaClApp *nap,
1269 uint32_t addr_first_usr,
1270 uint32_t addr_last_usr) {
1271 NaClXMutexLock(&nap->mu);
1272 (*nap->mem_io_regions->vtbl->RemoveInterval)(nap->mem_io_regions,
1275 NaClXMutexUnlock(&nap->mu);
1278 void NaClVmIoPendingCheck_mu(struct NaClApp *nap,
1279 uint32_t addr_first_usr,
1280 uint32_t addr_last_usr) {
1281 if ((*nap->mem_io_regions->vtbl->OverlapsWith)(nap->mem_io_regions,
1285 "NaClVmIoWillStart: program mem write race detected. ABORTING\n");
1290 * GDB's canonical overlay managment routine.
1291 * We need its symbol in the symbol table so don't inline it.
1292 * TODO(dje): add some explanation for the non-GDB person.
1295 __declspec(dllexport noinline)
1298 __attribute__((noinline))
1300 void _ovly_debug_event (void) {
1303 * The asm volatile is here as instructed by the GCC docs.
1304 * It's not enough to declare a function noinline.
1305 * GCC will still look inside the function to see if it's worth calling.
1307 __asm__ volatile ("");
1310 * Visual Studio inlines empty functions even with noinline attribute,
1311 * so we need a compile memory barrier to make this function not to be
1312 * inlined. Also, it guarantees that nacl_global_xlate_base initialization
1313 * is not reordered. This is important for gdb since it sets breakpoint on
1314 * this function and reads nacl_global_xlate_base value.
1316 _ReadWriteBarrier();
1320 static void StopForDebuggerInit (uintptr_t mem_start) {
1321 /* Put xlate_base in a place where gdb can find it. */
1322 nacl_global_xlate_base = mem_start;
1324 NaClSandboxMemoryStartForValgrind(mem_start);
1326 _ovly_debug_event();
1329 void NaClGdbHook(struct NaClApp const *nap) {
1330 StopForDebuggerInit(nap->mem_start);