static int LoadApp(struct NaClApp *nap, struct NaClChromeMainArgs *args) { NaClErrorCode errcode = LOAD_OK; CHECK(g_initialized); /* Allow or disallow dyncode API based on args. */ nap->enable_dyncode_syscalls = args->enable_dyncode_syscalls; nap->initial_nexe_max_code_bytes = args->initial_nexe_max_code_bytes; nap->pnacl_mode = args->pnacl_mode; #if NACL_LINUX g_prereserved_sandbox_size = args->prereserved_sandbox_size; #endif #if NACL_LINUX || NACL_OSX /* * Overwrite value of sc_nprocessors_onln set in NaClAppCtor. In * the Chrome embedding, the outer sandbox was already enabled when * the NaClApp Ctor was invoked, so a bogus value was written in * sc_nprocessors_onln. */ if (-1 != args->number_of_cores) { nap->sc_nprocessors_onln = args->number_of_cores; } #endif if (args->create_memory_object_func != NULL) NaClSetCreateMemoryObjectFunc(args->create_memory_object_func); /* Inject the validation caching interface, if it exists. */ nap->validation_cache = args->validation_cache; NaClAppInitialDescriptorHookup(nap); /* * in order to report load error to the browser plugin through the * secure command channel, we do not immediate jump to cleanup code * on error. rather, we continue processing (assuming earlier * errors do not make it inappropriate) until the secure command * channel is set up, and then bail out. */ /* * Ensure this operating system platform is supported. */ if (args->skip_qualification) { fprintf(stderr, "PLATFORM QUALIFICATION DISABLED - " "Native Client's sandbox will be unreliable!\n"); } else { errcode = NACL_FI_VAL("pq", NaClErrorCode, NaClRunSelQualificationTests()); if (LOAD_OK != errcode) { nap->module_load_status = errcode; fprintf(stderr, "Error while loading in SelMain: %s\n", NaClErrorString(errcode)); goto error; } } /* * Patch the Windows exception dispatcher to be safe in the case * of faults inside x86-64 sandboxed code. The sandbox is not * secure on 64-bit Windows without this. */ #if (NACL_WINDOWS && NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && \ NACL_BUILD_SUBARCH == 64) NaClPatchWindowsExceptionDispatcher(); #endif NaClSignalTestCrashOnStartup(); nap->enable_exception_handling = args->enable_exception_handling; if (args->enable_exception_handling || args->enable_debug_stub) { #if NACL_LINUX /* NaCl's signal handler is always enabled on Linux. */ #elif NACL_OSX if (!NaClInterceptMachExceptions()) { NaClLog(LOG_FATAL, "LoadApp: Failed to set up Mach exception handler\n"); } #elif NACL_WINDOWS nap->attach_debug_exception_handler_func = args->attach_debug_exception_handler_func; #else # error Unknown host OS #endif } #if NACL_LINUX NaClSignalHandlerInit(); #endif /* Give debuggers a well known point at which xlate_base is known. */ NaClGdbHook(nap); CHECK(args->nexe_desc != NULL); NaClAppLoadModule(nap, args->nexe_desc); NaClDescUnref(args->nexe_desc); args->nexe_desc = NULL; NACL_FI_FATAL("BeforeLoadIrt"); /* * error reporting done; can quit now if there was an error earlier. */ errcode = NaClGetLoadStatus(nap); if (LOAD_OK != errcode) { goto error; } /* * Load the integrated runtime (IRT) library. * Skip if irt_load_optional and the nexe doesn't have the usual 256MB * segment gap. PNaCl's disabling of the segment gap doesn't actually * disable the segment gap. It only only reduces it drastically. */ if (args->irt_load_optional && nap->dynamic_text_end < 0x10000000) { NaClLog(1, "Skipped NaClLoadIrt, irt_load_optional with dynamic_text_end: %" NACL_PRIxPTR"\n", nap->dynamic_text_end); } else { if (args->irt_fd != -1) { CHECK(args->irt_desc == NULL); args->irt_desc = IrtDescFromFd(args->irt_fd); args->irt_fd = -1; } if (args->irt_desc != NULL) { NaClLoadIrt(nap, args->irt_desc); NaClDescUnref(args->irt_desc); args->irt_desc = NULL; } } if (args->enable_debug_stub) { #if NACL_LINUX || NACL_OSX if (args->debug_stub_pipe_fd != NACL_INVALID_HANDLE) { NaClDebugStubSetPipe(args->debug_stub_pipe_fd); } else if (args->debug_stub_server_bound_socket_fd != NACL_INVALID_SOCKET) { NaClDebugSetBoundSocket(args->debug_stub_server_bound_socket_fd); } #endif if (!NaClDebugInit(nap)) { goto error; } #if NACL_WINDOWS if (NULL != args->debug_stub_server_port_selected_handler_func) { args->debug_stub_server_port_selected_handler_func( NaClDebugGetBoundPort()); } #endif } if (args->load_status_handler_func != NULL) { args->load_status_handler_func(LOAD_OK); } return LOAD_OK; error: fflush(stdout); /* Don't return LOAD_OK if we had some failure loading. */ if (LOAD_OK == errcode) { errcode = LOAD_INTERNAL; } /* * If there is a load status callback, call that now and transfer logs * in preparation for process exit. */ if (args->load_status_handler_func != NULL) { args->load_status_handler_func(errcode); NaClLog(LOG_ERROR, "NaCl LoadApp failed. Transferring logs before exit.\n"); NaClLogRunAbortBehavior(); } return errcode; }
static int LoadApp(struct NaClApp *nap, struct NaClChromeMainArgs *args) { NaClErrorCode errcode = LOAD_OK; int has_bootstrap_channel = args->imc_bootstrap_handle != NACL_INVALID_HANDLE; CHECK(g_initialized); /* Allow or disallow dyncode API based on args. */ nap->enable_dyncode_syscalls = args->enable_dyncode_syscalls; nap->initial_nexe_max_code_bytes = args->initial_nexe_max_code_bytes; nap->pnacl_mode = args->pnacl_mode; #if NACL_LINUX g_prereserved_sandbox_size = args->prereserved_sandbox_size; #endif #if NACL_LINUX || NACL_OSX /* * Overwrite value of sc_nprocessors_onln set in NaClAppCtor. In * the Chrome embedding, the outer sandbox was already enabled when * the NaClApp Ctor was invoked, so a bogus value was written in * sc_nprocessors_onln. */ if (-1 != args->number_of_cores) { nap->sc_nprocessors_onln = args->number_of_cores; } #endif if (args->create_memory_object_func != NULL) NaClSetCreateMemoryObjectFunc(args->create_memory_object_func); /* Inject the validation caching interface, if it exists. */ nap->validation_cache = args->validation_cache; #if NACL_WINDOWS if (args->broker_duplicate_handle_func != NULL) NaClSetBrokerDuplicateHandleFunc(args->broker_duplicate_handle_func); #endif NaClAppInitialDescriptorHookup(nap); /* * NACL_SERVICE_PORT_DESCRIPTOR and NACL_SERVICE_ADDRESS_DESCRIPTOR * are 3 and 4. */ /* * in order to report load error to the browser plugin through the * secure command channel, we do not immediate jump to cleanup code * on error. rather, we continue processing (assuming earlier * errors do not make it inappropriate) until the secure command * channel is set up, and then bail out. */ /* * Ensure this operating system platform is supported. */ if (args->skip_qualification) { fprintf(stderr, "PLATFORM QUALIFICATION DISABLED - " "Native Client's sandbox will be unreliable!\n"); } else { errcode = NACL_FI_VAL("pq", NaClErrorCode, NaClRunSelQualificationTests()); if (LOAD_OK != errcode) { nap->module_load_status = errcode; fprintf(stderr, "Error while loading in SelMain: %s\n", NaClErrorString(errcode)); } } /* * Patch the Windows exception dispatcher to be safe in the case * of faults inside x86-64 sandboxed code. The sandbox is not * secure on 64-bit Windows without this. */ #if (NACL_WINDOWS && NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && \ NACL_BUILD_SUBARCH == 64) NaClPatchWindowsExceptionDispatcher(); #endif NaClSignalTestCrashOnStartup(); nap->enable_exception_handling = args->enable_exception_handling; if (args->enable_exception_handling || args->enable_debug_stub) { #if NACL_LINUX /* NaCl's signal handler is always enabled on Linux. */ #elif NACL_OSX if (!NaClInterceptMachExceptions()) { NaClLog(LOG_FATAL, "LoadApp: Failed to set up Mach exception handler\n"); } #elif NACL_WINDOWS nap->attach_debug_exception_handler_func = args->attach_debug_exception_handler_func; #else # error Unknown host OS #endif } #if NACL_LINUX NaClSignalHandlerInit(); #endif /* Give debuggers a well known point at which xlate_base is known. */ NaClGdbHook(nap); if (has_bootstrap_channel) { NaClCreateServiceSocket(nap); /* * LOG_FATAL errors that occur before NaClSetUpBootstrapChannel will * not be reported via the crash log mechanism (for Chromium * embedding of NaCl, shown in the JavaScript console). * * Some errors, such as due to NaClRunSelQualificationTests, do not * trigger a LOG_FATAL but instead set module_load_status to be sent * in the start_module RPC reply. Log messages associated with such * errors would be seen, since NaClSetUpBootstrapChannel will get * called. */ NaClSetUpBootstrapChannel(nap, args->imc_bootstrap_handle); } CHECK(args->nexe_desc != NULL); NaClAppLoadModule(nap, args->nexe_desc, NULL, NULL); NaClDescUnref(args->nexe_desc); args->nexe_desc = NULL; if (has_bootstrap_channel) { NACL_FI_FATAL("BeforeSecureCommandChannel"); /* * Spawns a thread that uses the command channel. * Hereafter any changes to nap should be done while holding locks. */ NaClSecureCommandChannel(nap); NaClLog(4, "NaClSecureCommandChannel has spawned channel\n"); NaClLog(4, "secure service = %"NACL_PRIxPTR"\n", (uintptr_t) nap->secure_service); } NACL_FI_FATAL("BeforeLoadIrt"); /* * error reporting done; can quit now if there was an error earlier. */ if (LOAD_OK == errcode) { errcode = NaClGetLoadStatus(nap); } if (LOAD_OK != errcode) { goto done; } /* * Load the integrated runtime (IRT) library. * Skip if irt_load_optional and the nexe doesn't have the usual 256MB * segment gap. PNaCl's disabling of the segment gap doesn't actually * disable the segment gap. It only only reduces it drastically. */ if (args->irt_load_optional && nap->dynamic_text_end < 0x10000000) { NaClLog(1, "Skipped NaClLoadIrt, irt_load_optional with dynamic_text_end: %" NACL_PRIxPTR"\n", nap->dynamic_text_end); } else { if (args->irt_fd != -1) { CHECK(args->irt_desc == NULL); args->irt_desc = IrtDescFromFd(args->irt_fd); args->irt_fd = -1; } if (args->irt_desc != NULL) { NaClLoadIrt(nap, args->irt_desc); NaClDescUnref(args->irt_desc); args->irt_desc = NULL; } } if (args->enable_debug_stub) { #if NACL_LINUX || NACL_OSX if (args->debug_stub_server_bound_socket_fd != NACL_INVALID_SOCKET) { NaClDebugSetBoundSocket(args->debug_stub_server_bound_socket_fd); } #endif if (!NaClDebugInit(nap)) { goto done; } #if NACL_WINDOWS if (NULL != args->debug_stub_server_port_selected_handler_func) { args->debug_stub_server_port_selected_handler_func(nap->debug_stub_port); } #endif } if (args->load_status_handler_func != NULL) { args->load_status_handler_func(LOAD_OK); } return LOAD_OK; done: fflush(stdout); /* * If there is a load status callback, call that now and transfer logs * in preparation for process exit. */ if (args->load_status_handler_func != NULL) { /* Don't return LOAD_OK if we had some failure loading. */ if (LOAD_OK == errcode) { errcode = LOAD_INTERNAL; } args->load_status_handler_func(errcode); NaClLog(LOG_ERROR, "NaCl LoadApp failed. Transferring logs before exit.\n"); NaClLogRunAbortBehavior(); /* * Fall through and run NaClBlockIfCommandChannelExists. * TODO(jvoung): remove NaClBlockIfCommandChannelExists() and use the * callback to indicate the load_status after Chromium no longer calls * start_module. We also need to change Chromium so that it does not * attempt to set up the command channel if there is a known load error. * Otherwise there is a race between this process's exit / load error * reporting, and the command channel setup on the Chromium side (plus * the associated reporting). Thus this could end up with two different * load errors being reported (1) the real load error from here, and * (2) the command channel setup failure because the process exited in * the middle of setting up the command channel. */ } /* * If there is a secure command channel, we sent an RPC reply with * the reason that the nexe was rejected. If we exit now, that * reply may still be in-flight and the various channel closure (esp * reverse channel) may be detected first. This would result in a * crash being reported, rather than the error in the RPC reply. * Instead, we wait for the hard-shutdown on the command channel. */ if (LOAD_OK != errcode) { NaClBlockIfCommandChannelExists(nap); } else { /* * Don't return LOAD_OK if we had some failure loading. */ errcode = LOAD_INTERNAL; } return errcode; }