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.
8 * NaCl Simple/secure ELF loader (NaCl SEL).
10 #include "native_client/src/include/portability.h"
11 #include "native_client/src/include/portability_io.h"
25 #include "native_client/src/shared/gio/gio.h"
26 #include "native_client/src/shared/imc/nacl_imc_c.h"
27 #include "native_client/src/shared/platform/nacl_check.h"
28 #include "native_client/src/shared/platform/nacl_exit.h"
29 #include "native_client/src/shared/platform/nacl_log.h"
30 #include "native_client/src/shared/platform/nacl_sync.h"
31 #include "native_client/src/shared/platform/nacl_sync_checked.h"
32 #include "native_client/src/shared/srpc/nacl_srpc.h"
34 #include "native_client/src/trusted/desc/nacl_desc_base.h"
35 #include "native_client/src/trusted/desc/nacl_desc_io.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/perf_counter/nacl_perf_counter.h"
39 #include "native_client/src/trusted/service_runtime/env_cleanser.h"
40 #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
41 #include "native_client/src/trusted/service_runtime/load_file.h"
42 #include "native_client/src/trusted/service_runtime/nacl_app.h"
43 #include "native_client/src/trusted/service_runtime/nacl_all_modules.h"
44 #include "native_client/src/trusted/service_runtime/nacl_bootstrap_channel_error_reporter.h"
45 #include "native_client/src/trusted/service_runtime/nacl_debug_init.h"
46 #include "native_client/src/trusted/service_runtime/nacl_error_log_hook.h"
47 #include "native_client/src/trusted/service_runtime/nacl_globals.h"
48 #include "native_client/src/trusted/service_runtime/nacl_runtime_host_interface.h"
49 #include "native_client/src/trusted/service_runtime/nacl_signal.h"
50 #include "native_client/src/trusted/service_runtime/nacl_syscall_common.h"
51 #include "native_client/src/trusted/service_runtime/nacl_valgrind_hooks.h"
52 #include "native_client/src/trusted/service_runtime/osx/mach_exception_handler.h"
53 #include "native_client/src/trusted/service_runtime/outer_sandbox.h"
54 #include "native_client/src/trusted/service_runtime/sel_ldr.h"
55 #include "native_client/src/trusted/service_runtime/sel_main_common.h"
56 #include "native_client/src/trusted/service_runtime/sel_qualify.h"
57 #include "native_client/src/trusted/service_runtime/win/exception_patch/ntdll_patch.h"
58 #include "native_client/src/trusted/service_runtime/win/debug_exception_handler.h"
61 static void (*g_enable_outer_sandbox_func)(void) =
63 NaClEnableOuterSandbox;
68 void NaClSetEnableOuterSandboxFunc(void (*func)(void)) {
69 g_enable_outer_sandbox_func = func;
72 static void VmentryPrinter(void *state,
73 struct NaClVmmapEntry *vmep) {
74 UNREFERENCED_PARAMETER(state);
75 printf("page num 0x%06x\n", (uint32_t)vmep->page_num);
76 printf("num pages %d\n", (uint32_t)vmep->npages);
77 printf("prot bits %x\n", vmep->prot);
81 static void PrintVmmap(struct NaClApp *nap) {
82 printf("In PrintVmmap\n");
84 NaClXMutexLock(&nap->mu);
85 NaClVmmapVisit(&nap->mem_map, VmentryPrinter, (void *) 0);
87 NaClXMutexUnlock(&nap->mu);
104 struct NaClSocketAddress addr;
108 int ImportModeMap(char opt) {
117 fprintf(stderr, ("option %c not understood as a host descriptor"
124 static void PrintUsage(void) {
125 /* NOTE: this is broken up into multiple statements to work around
126 the constant string size limit */
128 "Usage: sel_ldr [-h d:D] [-r d:D] [-w d:D] [-i d:D]\n"
131 " [-X d] [-acFglQRsSQv]\n"
132 " -- [nacl_file] [args]\n"
137 " -w associate a host POSIX descriptor D with app desc d\n"
138 " that was opened in O_RDWR, O_RDONLY, and O_WRONLY modes\n"
140 " -i associates an IMC handle D with app desc d\n"
141 " -f file to load; if omitted, 1st arg after \"--\" is loaded\n"
142 " -B additional ELF file to load as a blob library\n"
143 " -v increases verbosity\n"
144 " -X create a bound socket and export the address via an\n"
145 " IMC message to a corresponding inherited IMC app descriptor\n"
146 " (use -1 to create the bound socket / address descriptor\n"
147 " pair, but that no export via IMC should occur)\n");
149 " -R an RPC supplies the NaCl module.\n"
150 " No nacl_file argument is expected, and the -f flag cannot be\n"
151 " used with this flag.\n"
154 " -a allow file access plus some other syscalls! dangerous!\n"
155 " -c ignore validator! dangerous! Repeating this option twice skips\n"
156 " validation completely.\n"
157 " -F fuzz testing; quit after loading NaCl app\n"
158 " -g enable gdb debug stub. Not secure on x86-64 Windows.\n"
159 " -l <file> write log output to the given file\n"
160 " -q quiet; suppress diagnostic/warning messages at startup\n"
161 " -Q disable platform qualification (dangerous!)\n"
162 " -s safely stub out non-validating instructions\n"
163 " -S enable signal handling. Not supported on Windows.\n"
164 " -E <name=value>|<name> set an environment variable\n"
165 " -Z use fixed feature x86 CPU mode\n"
167 " (For full effect, put -l and -q at the beginning.)\n"
168 ); /* easier to add new flags/lines */
172 static const struct option longopts[] = {
173 { "r_debug", required_argument, NULL, 'D' },
174 { "reserved_at_zero", required_argument, NULL, 'z' },
178 static int my_getopt(int argc, char *const *argv, const char *shortopts) {
179 return getopt_long(argc, argv, shortopts, longopts, NULL);
182 #define my_getopt getopt
185 struct SelLdrOptions {
187 char *blob_library_file;
193 int fuzzing_quit_after_load;
194 int skip_qualification;
196 int enable_exception_handling;
197 int enable_debug_stub;
198 int rpc_supplies_nexe;
200 int debug_mode_bypass_acl_checks;
201 int debug_mode_ignore_validator;
202 int debug_mode_startup_signal;
203 struct redir *redir_queue;
204 struct redir **redir_qend;
207 static void SelLdrOptionsCtor(struct SelLdrOptions *options) {
208 /* Just to be safe. */
209 memset(options, 0, sizeof(*options));
211 options->nacl_file = NULL;
212 options->blob_library_file = NULL;
213 options->app_argc = 0;
214 options->app_argv = NULL;
217 options->verbosity = 0;
218 options->fuzzing_quit_after_load = 0;
219 options->skip_qualification = 0;
220 options->handle_signals = 0;
221 options->enable_exception_handling = 0;
222 options->enable_debug_stub = 0;
223 options->rpc_supplies_nexe = 0;
224 options->export_addr_to = -1;
225 options->debug_mode_bypass_acl_checks = 0;
226 options->debug_mode_ignore_validator = 0;
227 options->debug_mode_startup_signal = 0;
228 options->redir_queue = NULL;
229 options->redir_qend = &(options->redir_queue);
232 /* TODO(ncbray): do not directly set fields on NaClApp. */
233 static void NaClSelLdrParseArgs(int argc, char **argv,
234 struct SelLdrOptions *options,
235 struct DynArray *env_vars,
236 struct NaClApp *nap) {
241 options->verbosity = NaClLogGetVerbosity();
244 * On platforms with glibc getopt, require POSIXLY_CORRECT behavior,
245 * viz, no reordering of the arglist -- stop argument processing as
246 * soon as an unrecognized argument is encountered, so that, for
247 * example, in the invocation
249 * sel_ldr foo.nexe -vvv
251 * the -vvv flags are made available to the nexe, rather than being
252 * consumed by getopt. This makes the behavior of the Linux build
253 * of sel_ldr consistent with the Windows and OSX builds.
255 while ((opt = my_getopt(argc, argv,
259 "aB:cdeE:f:Fgh:i:l:qQr:RsSvw:X:Z")) != -1) {
263 fprintf(stderr, "DEBUG MODE ENABLED (bypass acl)\n");
264 options->debug_mode_bypass_acl_checks = 1;
267 options->blob_library_file = optarg;
270 ++(options->debug_mode_ignore_validator);
273 options->debug_mode_startup_signal = 1;
277 NaClHandleRDebug(optarg, argv[0]);
281 options->enable_exception_handling = 1;
285 * For simplicity, we treat the environment variables as a
286 * list of strings rather than a key/value mapping. We do not
287 * try to prevent duplicate keys or require the strings to be
288 * of the form "KEY=VALUE". This is in line with how execve()
291 * We expect that most callers passing "-E" will either pass
292 * in a fixed list or will construct the list using a
293 * high-level language, in which case de-duplicating keys
294 * outside of sel_ldr is easier. However, we could do
295 * de-duplication here if it proves to be worthwhile.
297 if (!DynArraySet(env_vars, env_vars->num_entries, optarg)) {
298 NaClLog(LOG_FATAL, "Adding item to env_vars failed\n");
302 options->nacl_file = optarg;
305 options->fuzzing_quit_after_load = 1;
309 options->enable_debug_stub = 1;
315 /* import host descriptor */
316 entry = malloc(sizeof *entry);
318 fprintf(stderr, "No memory for redirection queue\n");
322 entry->nacl_desc = strtol(optarg, &rest, 0);
323 entry->tag = HOST_DESC;
324 entry->u.host.d = strtol(rest+1, (char **) 0, 0);
325 entry->u.host.mode = ImportModeMap(opt);
326 *(options->redir_qend) = entry;
327 options->redir_qend = &entry->next;
330 /* import IMC handle */
331 entry = malloc(sizeof *entry);
333 fprintf(stderr, "No memory for redirection queue\n");
337 entry->nacl_desc = strtol(optarg, &rest, 0);
338 entry->tag = IMC_DESC;
339 entry->u.handle = (NaClHandle) strtol(rest+1, (char **) 0, 0);
340 *(options->redir_qend) = entry;
341 options->redir_qend = &entry->next;
344 if (NULL != optarg) {
346 * change stdout/stderr to log file now, so that subsequent error
347 * messages will go there. unfortunately, error messages that
348 * result from getopt processing -- usually out-of-memory, which
349 * shouldn't happen -- won't show up.
351 NaClLogSetFile(optarg);
359 fprintf(stderr, "PLATFORM QUALIFICATION DISABLED BY -Q - "
360 "Native Client's sandbox will be unreliable!\n");
361 options->skip_qualification = 1;
364 options->rpc_supplies_nexe = 1;
366 /* case 'r': with 'h' and 'w' above */
368 if (nap->validator->stubout_mode_implemented) {
369 nap->validator_stub_out_mode = 1;
371 NaClLog(LOG_WARNING, "stub_out_mode is not supported, disabled\n");
375 options->handle_signals = 1;
378 ++(options->verbosity);
379 NaClLogIncrVerbosity();
381 /* case 'w': with 'h' and 'r' above */
383 options->export_addr_to = strtol(optarg, (char **) 0, 0);
387 NaClHandleReservedAtZero(optarg);
391 if (nap->validator->readonly_text_implemented) {
392 NaClLog(LOG_WARNING, "Enabling Fixed-Feature CPU Mode\n");
393 nap->fixed_feature_cpu_mode = 1;
394 if (!nap->validator->FixCPUFeatures(nap->cpu_features)) {
396 "This CPU lacks features required by "
397 "fixed-function CPU mode.\n");
401 NaClLog(LOG_ERROR, "fixed_feature_cpu_mode is not supported\n");
406 fprintf(stderr, "ERROR: unknown option: [%c]\n\n", opt);
412 /* Post process the options. */
414 if (options->debug_mode_ignore_validator == 1) {
416 fprintf(stderr, "DEBUG MODE ENABLED (ignore validator)\n");
417 } else if (options->debug_mode_ignore_validator > 1) {
419 fprintf(stderr, "DEBUG MODE ENABLED (skip validator)\n");
422 if (options->verbosity) {
424 char const *separator = "";
426 fprintf(stderr, "sel_ldr argument list:\n");
427 for (ix = 0; ix < argc; ++ix) {
428 fprintf(stderr, "%s%s", separator, argv[ix]);
434 if (options->rpc_supplies_nexe) {
435 if (NULL != options->nacl_file) {
437 "sel_ldr: mutually exclusive flags -f and -R both used\n");
440 /* post: NULL == nacl_file */
441 if (options->export_addr_to < 0) {
443 "sel_ldr: -R requires -X to set up secure command channel\n");
447 if (NULL == options->nacl_file && optind < argc) {
448 options->nacl_file = argv[optind];
451 if (NULL == options->nacl_file) {
452 fprintf(stderr, "No nacl file specified\n");
455 /* post: NULL != nacl_file */
458 * post condition established by the above code (in Hoare logic
461 * NULL == nacl_file iff rpc_supplies_nexe
463 * so hence forth, testing !rpc_supplies_nexe suffices for
464 * establishing NULL != nacl_file.
466 CHECK((NULL == options->nacl_file) == options->rpc_supplies_nexe);
468 /* to be passed to NaClMain, eventually... */
469 if (NULL != options->nacl_file && options->debug_mode_bypass_acl_checks) {
470 argv[--optind] = options->nacl_file;
472 argv[--optind] = (char *) "NaClMain";
475 options->app_argc = argc - optind;
476 options->app_argv = argv + optind;
479 * NACL_DANGEROUS_SKIP_QUALIFICATION_TEST is used by tsan / memcheck
480 * (see src/third_party/valgrind/).
482 if (!options->skip_qualification &&
483 getenv("NACL_DANGEROUS_SKIP_QUALIFICATION_TEST") != NULL) {
485 fprintf(stderr, "PLATFORM QUALIFICATION DISABLED BY ENVIRONMENT - "
486 "Native Client's sandbox will be unreliable!\n");
487 options->skip_qualification = 1;
490 if (getenv("NACL_UNTRUSTED_EXCEPTION_HANDLING") != NULL) {
491 options->enable_exception_handling = 1;
495 static void RedirectIO(struct NaClApp *nap, struct redir *redir_queue){
498 * Execute additional I/O redirections. NB: since the NaClApp
499 * takes ownership of host / IMC socket descriptors, all but
500 * the first run will not get access if the NaClApp closes
501 * them. Currently a normal NaClApp process exit does not
502 * close descriptors, since the underlying host OS will do so
503 * as part of service runtime exit.
505 NaClLog(4, "Processing I/O redirection/inheritance from command line\n");
506 for (entry = redir_queue; NULL != entry; entry = entry->next) {
507 switch (entry->tag) {
509 NaClAddHostDescriptor(nap, entry->u.host.d,
510 entry->u.host.mode, entry->nacl_desc);
513 NaClAddImcHandle(nap, entry->u.handle, entry->nacl_desc);
519 int NaClSelLdrMain(int argc, char **argv) {
520 struct NaClApp *nap = NULL;
521 struct SelLdrOptions optionsImpl;
522 struct SelLdrOptions *options = &optionsImpl;
524 NaClErrorCode errcode = LOAD_INTERNAL;
525 struct NaClDesc *blob_file = NULL;
529 struct DynArray env_vars;
530 struct NaClEnvCleanser env_cleanser;
531 char const *const *envp;
533 struct NaClPerfCounter time_all_main;
538 NaClAllModulesInit();
541 * If this is a secondary process spun up to assist windows exception
542 * handling, the following function will not return. If this is a normal
543 * sel_ldr process, the following function does nothing.
545 NaClDebugExceptionHandlerStandaloneHandleArgs(argc, argv);
547 nap = NaClAppCreate();
549 NaClLog(LOG_FATAL, "NaClAppCreate() failed\n");
552 NaClBootstrapChannelErrorReporterInit();
553 NaClErrorLogHookInit(NaClBootstrapChannelErrorReporter, nap);
555 NaClPerfCounterCtor(&time_all_main, "SelMain");
557 fflush((FILE *) NULL);
559 SelLdrOptionsCtor(options);
560 if (!DynArrayCtor(&env_vars, 0)) {
561 NaClLog(LOG_FATAL, "Failed to allocate env var array\n");
563 NaClSelLdrParseArgs(argc, argv, options, &env_vars, nap);
566 * Define the environment variables for untrusted code.
568 if (!DynArraySet(&env_vars, env_vars.num_entries, NULL)) {
569 NaClLog(LOG_FATAL, "Adding env_vars NULL terminator failed\n");
571 NaClEnvCleanserCtor(&env_cleanser, 0);
572 if (!NaClEnvCleanserInit(&env_cleanser, NaClGetEnviron(),
573 (char const *const *)env_vars.ptr_array)) {
574 NaClLog(LOG_FATAL, "Failed to initialise env cleanser\n");
576 envp = NaClEnvCleanserEnvironment(&env_cleanser);
578 if (options->debug_mode_startup_signal) {
580 NaClLog(LOG_FATAL, "DEBUG startup signal not supported on Windows\n");
583 * SIGCONT is ignored by default, so this doesn't actually do anything
584 * by itself. The purpose of raising the signal is to get a debugger
585 * to stop and inspect the process before it does anything else. When
586 * sel_ldr is started via nacl_helper_bootstrap, it needs to run as far
587 * as doing its option processing and calling NaClHandleRDebug before
588 * the debugger will understand the association between the address
589 * space and the sel_ldr binary and its dependent shared libraries.
590 * When the debugger stops for the signal, the hacker can run the
591 * "sharedlibrary" command (if the debugger is GDB) and thereafter
592 * it becomes possible to set symbolic breakpoints and so forth.
594 NaClLog(LOG_ERROR, "DEBUG taking startup signal (SIGCONT) now\n");
599 if (options->debug_mode_bypass_acl_checks) {
600 NaClInsecurelyBypassAllAclChecks();
603 nap->ignore_validator_result = (options->debug_mode_ignore_validator > 0);
604 nap->skip_validator = (options->debug_mode_ignore_validator > 1);
605 nap->enable_exception_handling = options->enable_exception_handling;
608 * TODO(mseaborn): Always enable the Mach exception handler on Mac
609 * OS X, and remove handle_signals and sel_ldr's "-S" option.
611 if (nap->enable_exception_handling || options->enable_debug_stub ||
612 (options->handle_signals && NACL_OSX)) {
614 nap->attach_debug_exception_handler_func =
615 NaClDebugExceptionHandlerStandaloneAttach;
617 /* NaCl's signal handler is always enabled on Linux. */
619 if (!NaClInterceptMachExceptions()) {
620 NaClLog(LOG_ERROR, "ERROR setting up Mach exception interception.\n");
624 # error Unknown host OS
631 * in order to report load error to the browser plugin through the
632 * secure command channel, we do not immediate jump to cleanup code
633 * on error. rather, we continue processing (assuming earlier
634 * errors do not make it inappropriate) until the secure command
635 * channel is set up, and then bail out.
639 * Ensure the platform qualification checks pass.
641 if (!options->skip_qualification) {
642 NaClErrorCode pq_error = NACL_FI_VAL("pq", NaClErrorCode,
643 NaClRunSelQualificationTests());
644 if (LOAD_OK != pq_error) {
646 nap->module_load_status = pq_error;
648 NaClLog(LOG_ERROR, "Error while loading \"%s\": %s\n",
649 NULL != options->nacl_file ? options->nacl_file
650 : "(no file, to-be-supplied-via-RPC)",
651 NaClErrorString(errcode));
656 NaClSignalHandlerInit();
659 * Patch the Windows exception dispatcher to be safe in the case of
660 * faults inside x86-64 sandboxed code. The sandbox is not secure
661 * on 64-bit Windows without this.
663 #if (NACL_WINDOWS && NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && \
664 NACL_BUILD_SUBARCH == 64)
665 NaClPatchWindowsExceptionDispatcher();
667 NaClSignalTestCrashOnStartup();
670 * Open both files first because (on Mac OS X at least)
671 * NaClAppLoadFile() enables an outer sandbox.
673 if (NULL != options->blob_library_file) {
674 NaClFileNameForValgrind(options->blob_library_file);
675 blob_file = (struct NaClDesc *) NaClDescIoDescOpen(
676 options->blob_library_file, NACL_ABI_O_RDONLY, 0);
677 if (NULL == blob_file) {
679 NaClLog(LOG_FATAL, "Cannot open \"%s\".\n", options->blob_library_file);
681 NaClPerfCounterMark(&time_all_main, "SnapshotBlob");
682 NaClPerfCounterIntervalLast(&time_all_main);
685 NaClAppInitialDescriptorHookup(nap);
687 if (!options->rpc_supplies_nexe) {
688 if (LOAD_OK == errcode) {
689 NaClLog(2, "Loading nacl file %s (non-RPC)\n", options->nacl_file);
690 errcode = NaClAppLoadFileFromFilename(nap, options->nacl_file);
691 if (LOAD_OK != errcode && !options->quiet) {
692 NaClLog(LOG_ERROR, "Error while loading \"%s\": %s\n"
693 "Using the wrong type of nexe (nacl-x86-32"
694 " on an x86-64 or vice versa)\n"
695 "or a corrupt nexe file may be"
696 " responsible for this error.\n",
698 NaClErrorString(errcode));
700 NaClPerfCounterMark(&time_all_main, "AppLoadEnd");
701 NaClPerfCounterIntervalLast(&time_all_main);
704 if (options->fuzzing_quit_after_load) {
709 RedirectIO(nap, options->redir_queue);
712 * If export_addr_to is set to a non-negative integer, we create a
713 * bound socket and socket address pair and bind the former to
714 * descriptor NACL_SERVICE_PORT_DESCRIPTOR (3 [see sel_ldr.h]) and
715 * the latter to descriptor NACL_SERVICE_ADDRESS_DESCRIPTOR (4).
716 * The socket address is sent to the export_addr_to descriptor.
718 * The service runtime also accepts a connection on the bound socket
719 * and spawns a secure command channel thread to service it.
721 if (0 <= options->export_addr_to) {
722 NaClCreateServiceSocket(nap);
724 * LOG_FATAL errors that occur before NaClSetUpBootstrapChannel will
725 * not be reported via the crash log mechanism (for Chromium
726 * embedding of NaCl, shown in the JavaScript console).
728 * Some errors, such as due to NaClRunSelQualificationTests, do not
729 * trigger a LOG_FATAL but instead set module_load_status to be sent
730 * in the start_module RPC reply. Log messages associated with such
731 * errors would be seen, since NaClSetUpBootstrapChannel will get
734 NaClSetUpBootstrapChannel(nap, (NaClHandle) options->export_addr_to);
736 * NB: spawns a thread that uses the command channel. we do
737 * this after NaClAppLoadFile so that NaClApp object is more
738 * fully populated. Hereafter any changes to nap should be done
739 * while holding locks.
741 NaClSecureCommandChannel(nap);
745 * May have created a thread, so need to synchronize uses of nap
746 * contents henceforth.
749 if (options->rpc_supplies_nexe) {
750 NaClErrorCode load_error = NaClWaitForLoadModuleCommand(nap);
751 if (load_error != LOAD_OK) {
752 errcode = load_error;
754 NaClPerfCounterMark(&time_all_main, "WaitForLoad");
755 NaClPerfCounterIntervalLast(&time_all_main);
759 * Tell the debug stub to bind a TCP port before enabling the outer
760 * sandbox. This is only needed on Mac OS X since that is the only
761 * platform where we have an outer sandbox in standalone sel_ldr.
762 * In principle this call should work on all platforms, but Windows
763 * XP seems to have some problems when we do bind()/listen() on a
764 * separate thread from accept().
766 if (options->enable_debug_stub && NACL_OSX) {
767 if (!NaClDebugBindSocket()) {
773 * Enable the outer sandbox, if one is defined. Do this as soon as
776 * This must come after NaClWaitForLoadModuleCommand(), which waits
777 * for another thread to have called NaClAppLoadFile().
778 * NaClAppLoadFile() does not work inside the Mac outer sandbox in
779 * standalone sel_ldr when using a dynamic code area because it uses
780 * NaClCreateMemoryObject() which opens a file in /tmp.
782 * We cannot enable the sandbox if file access is enabled.
784 if (!NaClAclBypassChecks && g_enable_outer_sandbox_func != NULL) {
785 g_enable_outer_sandbox_func();
788 if (NULL != options->blob_library_file) {
789 if (LOAD_OK == errcode) {
790 errcode = NaClMainLoadIrt(nap, blob_file, NULL);
791 if (LOAD_OK != errcode) {
792 NaClLog(LOG_ERROR, "Error while loading \"%s\": %s\n",
793 options->blob_library_file,
794 NaClErrorString(errcode));
796 NaClPerfCounterMark(&time_all_main, "BlobLoaded");
797 NaClPerfCounterIntervalLast(&time_all_main);
800 NaClDescUnref(blob_file);
804 * Print out a marker for scripts to use to mark the start of app
807 NaClLog(1, "NACL: Application output follows\n");
810 * Make sure all the file buffers are flushed before entering
811 * the application code.
813 fflush((FILE *) NULL);
815 if (NULL != nap->secure_service) {
816 NaClErrorCode start_result;
818 * wait for start_module RPC call on secure channel thread.
820 start_result = NaClWaitForStartModuleCommand(nap);
821 NaClPerfCounterMark(&time_all_main, "WaitedForStartModuleCommand");
822 NaClPerfCounterIntervalLast(&time_all_main);
823 if (LOAD_OK == errcode) {
824 errcode = start_result;
827 NaClAppStartModule(nap, NULL, NULL);
831 * error reporting done; can quit now if there was an error earlier.
833 if (LOAD_OK != errcode) {
835 "Not running app code since errcode is %s (%d)\n",
836 NaClErrorString(errcode),
841 if (!NaClAppLaunchServiceThreads(nap)) {
844 if (options->enable_debug_stub) {
845 if (!NaClDebugInit(nap)) {
849 NACL_TEST_INJECTION(BeforeMainThreadLaunches, ());
850 if (!NaClCreateMainThread(nap,
854 NaClLog(LOG_FATAL, "creating main thread failed\n");
858 * Clean up temp storage for env vars.
860 NaClEnvCleanserDtor(&env_cleanser);
861 DynArrayDtor(&env_vars);
863 NaClPerfCounterMark(&time_all_main, "CreateMainThread");
864 NaClPerfCounterIntervalLast(&time_all_main);
866 ret_code = NaClWaitForMainThreadToExit(nap);
867 NaClPerfCounterMark(&time_all_main, "WaitForMainThread");
868 NaClPerfCounterIntervalLast(&time_all_main);
870 NaClPerfCounterMark(&time_all_main, "SelMainEnd");
871 NaClPerfCounterIntervalTotal(&time_all_main);
874 * exit_group or equiv kills any still running threads while module
875 * addr space is still valid. otherwise we'd have to kill threads
876 * before we clean up the address space.
883 if (options->verbosity) {
884 printf("Dumping vmmap.\n"); fflush(stdout);
889 * If there is a secure command channel, we sent an RPC reply with
890 * the reason that the nexe was rejected. If we exit now, that
891 * reply may still be in-flight and the various channel closure (esp
892 * reverse channel) may be detected first. This would result in a
893 * crash being reported, rather than the error in the RPC reply.
894 * Instead, we wait for the hard-shutdown on the command channel.
896 if (LOAD_OK != errcode) {
897 NaClBlockIfCommandChannelExists(nap);
900 if (options->verbosity > 0) {
906 NaClSignalHandlerFini();
908 NaClAllModulesFini();
912 /* Unreachable, but having the return prevents a compiler error. */