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"
14 #include <crt_externs.h>
29 #include "native_client/src/shared/gio/gio.h"
30 #include "native_client/src/shared/imc/nacl_imc_c.h"
31 #include "native_client/src/shared/platform/nacl_check.h"
32 #include "native_client/src/shared/platform/nacl_exit.h"
33 #include "native_client/src/shared/platform/nacl_log.h"
34 #include "native_client/src/shared/platform/nacl_sync.h"
35 #include "native_client/src/shared/platform/nacl_sync_checked.h"
36 #include "native_client/src/shared/srpc/nacl_srpc.h"
38 #include "native_client/src/trusted/desc/nacl_desc_base.h"
39 #include "native_client/src/trusted/desc/nacl_desc_io.h"
40 #include "native_client/src/trusted/fault_injection/fault_injection.h"
41 #include "native_client/src/trusted/fault_injection/test_injection.h"
42 #include "native_client/src/trusted/perf_counter/nacl_perf_counter.h"
43 #include "native_client/src/trusted/service_runtime/env_cleanser.h"
44 #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
45 #include "native_client/src/trusted/service_runtime/load_file.h"
46 #include "native_client/src/trusted/service_runtime/nacl_app.h"
47 #include "native_client/src/trusted/service_runtime/nacl_all_modules.h"
48 #include "native_client/src/trusted/service_runtime/nacl_bootstrap_channel_error_reporter.h"
49 #include "native_client/src/trusted/service_runtime/nacl_debug_init.h"
50 #include "native_client/src/trusted/service_runtime/nacl_error_log_hook.h"
51 #include "native_client/src/trusted/service_runtime/nacl_globals.h"
52 #include "native_client/src/trusted/service_runtime/nacl_runtime_host_interface.h"
53 #include "native_client/src/trusted/service_runtime/nacl_signal.h"
54 #include "native_client/src/trusted/service_runtime/nacl_syscall_common.h"
55 #include "native_client/src/trusted/service_runtime/nacl_valgrind_hooks.h"
56 #include "native_client/src/trusted/service_runtime/osx/mach_exception_handler.h"
57 #include "native_client/src/trusted/service_runtime/outer_sandbox.h"
58 #include "native_client/src/trusted/service_runtime/sel_ldr.h"
59 #include "native_client/src/trusted/service_runtime/sel_main_common.h"
60 #include "native_client/src/trusted/service_runtime/sel_qualify.h"
61 #include "native_client/src/trusted/service_runtime/win/exception_patch/ntdll_patch.h"
62 #include "native_client/src/trusted/service_runtime/win/debug_exception_handler.h"
65 static void (*g_enable_outer_sandbox_func)(void) =
67 NaClEnableOuterSandbox;
72 void NaClSetEnableOuterSandboxFunc(void (*func)(void)) {
73 g_enable_outer_sandbox_func = func;
76 static void VmentryPrinter(void *state,
77 struct NaClVmmapEntry *vmep) {
78 UNREFERENCED_PARAMETER(state);
79 printf("page num 0x%06x\n", (uint32_t)vmep->page_num);
80 printf("num pages %d\n", (uint32_t)vmep->npages);
81 printf("prot bits %x\n", vmep->prot);
85 static void PrintVmmap(struct NaClApp *nap) {
86 printf("In PrintVmmap\n");
88 NaClXMutexLock(&nap->mu);
89 NaClVmmapVisit(&nap->mem_map, VmentryPrinter, (void *) 0);
91 NaClXMutexUnlock(&nap->mu);
108 struct NaClSocketAddress addr;
112 int ImportModeMap(char opt) {
121 fprintf(stderr, ("option %c not understood as a host descriptor"
128 static void PrintUsage(void) {
129 /* NOTE: this is broken up into multiple statements to work around
130 the constant string size limit */
132 "Usage: sel_ldr [-h d:D] [-r d:D] [-w d:D] [-i d:D]\n"
135 " [-X d] [-acFglQRsSQv]\n"
136 " -- [nacl_file] [args]\n"
141 " -w associate a host POSIX descriptor D with app desc d\n"
142 " that was opened in O_RDWR, O_RDONLY, and O_WRONLY modes\n"
144 " -i associates an IMC handle D with app desc d\n"
145 " -f file to load; if omitted, 1st arg after \"--\" is loaded\n"
146 " -B additional ELF file to load as a blob library\n"
147 " -v increases verbosity\n"
148 " -X create a bound socket and export the address via an\n"
149 " IMC message to a corresponding inherited IMC app descriptor\n"
150 " (use -1 to create the bound socket / address descriptor\n"
151 " pair, but that no export via IMC should occur)\n");
153 " -R an RPC supplies the NaCl module.\n"
154 " No nacl_file argument is expected, and the -f flag cannot be\n"
155 " used with this flag.\n"
158 " -a allow file access plus some other syscalls! dangerous!\n"
159 " -c ignore validator! dangerous! Repeating this option twice skips\n"
160 " validation completely.\n"
161 " -F fuzz testing; quit after loading NaCl app\n"
162 " -g enable gdb debug stub. Not secure on x86-64 Windows.\n"
163 " -l <file> write log output to the given file\n"
164 " -q quiet; suppress diagnostic/warning messages at startup\n"
165 " -Q disable platform qualification (dangerous!)\n"
166 " -s safely stub out non-validating instructions\n"
167 " -S enable signal handling. Not supported on Windows.\n"
168 " -E <name=value>|<name> set an environment variable\n"
169 " -Z use fixed feature x86 CPU mode\n"
171 " (For full effect, put -l and -q at the beginning.)\n"
172 ); /* easier to add new flags/lines */
176 static const struct option longopts[] = {
177 { "r_debug", required_argument, NULL, 'D' },
178 { "reserved_at_zero", required_argument, NULL, 'z' },
182 static int my_getopt(int argc, char *const *argv, const char *shortopts) {
183 return getopt_long(argc, argv, shortopts, longopts, NULL);
186 #define my_getopt getopt
189 struct SelLdrOptions {
191 char *blob_library_file;
197 int fuzzing_quit_after_load;
198 int skip_qualification;
200 int enable_exception_handling;
201 int enable_debug_stub;
202 int rpc_supplies_nexe;
204 int debug_mode_bypass_acl_checks;
205 int debug_mode_ignore_validator;
206 int debug_mode_startup_signal;
207 struct redir *redir_queue;
208 struct redir **redir_qend;
211 static void SelLdrOptionsCtor(struct SelLdrOptions *options) {
212 /* Just to be safe. */
213 memset(options, 0, sizeof(*options));
215 options->nacl_file = NULL;
216 options->blob_library_file = NULL;
217 options->app_argc = 0;
218 options->app_argv = NULL;
221 options->verbosity = 0;
222 options->fuzzing_quit_after_load = 0;
223 options->skip_qualification = 0;
224 options->handle_signals = 0;
225 options->enable_exception_handling = 0;
226 options->enable_debug_stub = 0;
227 options->rpc_supplies_nexe = 0;
228 options->export_addr_to = -1;
229 options->debug_mode_bypass_acl_checks = 0;
230 options->debug_mode_ignore_validator = 0;
231 options->debug_mode_startup_signal = 0;
232 options->redir_queue = NULL;
233 options->redir_qend = &(options->redir_queue);
236 /* TODO(ncbray): do not directly set fields on NaClApp. */
237 static void NaClSelLdrParseArgs(int argc, char **argv,
238 struct SelLdrOptions *options,
239 struct DynArray *env_vars,
240 struct NaClApp *nap) {
245 options->verbosity = NaClLogGetVerbosity();
248 * On platforms with glibc getopt, require POSIXLY_CORRECT behavior,
249 * viz, no reordering of the arglist -- stop argument processing as
250 * soon as an unrecognized argument is encountered, so that, for
251 * example, in the invocation
253 * sel_ldr foo.nexe -vvv
255 * the -vvv flags are made available to the nexe, rather than being
256 * consumed by getopt. This makes the behavior of the Linux build
257 * of sel_ldr consistent with the Windows and OSX builds.
259 while ((opt = my_getopt(argc, argv,
263 "aB:cdeE:f:Fgh:i:l:qQr:RsSvw:X:Z")) != -1) {
267 fprintf(stderr, "DEBUG MODE ENABLED (bypass acl)\n");
268 options->debug_mode_bypass_acl_checks = 1;
271 options->blob_library_file = optarg;
274 ++(options->debug_mode_ignore_validator);
277 options->debug_mode_startup_signal = 1;
281 NaClHandleRDebug(optarg, argv[0]);
285 options->enable_exception_handling = 1;
289 * For simplicity, we treat the environment variables as a
290 * list of strings rather than a key/value mapping. We do not
291 * try to prevent duplicate keys or require the strings to be
292 * of the form "KEY=VALUE". This is in line with how execve()
295 * We expect that most callers passing "-E" will either pass
296 * in a fixed list or will construct the list using a
297 * high-level language, in which case de-duplicating keys
298 * outside of sel_ldr is easier. However, we could do
299 * de-duplication here if it proves to be worthwhile.
301 if (!DynArraySet(env_vars, env_vars->num_entries, optarg)) {
302 NaClLog(LOG_FATAL, "Adding item to env_vars failed\n");
306 options->nacl_file = optarg;
309 options->fuzzing_quit_after_load = 1;
313 options->enable_debug_stub = 1;
319 /* import host descriptor */
320 entry = malloc(sizeof *entry);
322 fprintf(stderr, "No memory for redirection queue\n");
326 entry->nacl_desc = strtol(optarg, &rest, 0);
327 entry->tag = HOST_DESC;
328 entry->u.host.d = strtol(rest+1, (char **) 0, 0);
329 entry->u.host.mode = ImportModeMap(opt);
330 *(options->redir_qend) = entry;
331 options->redir_qend = &entry->next;
334 /* import IMC handle */
335 entry = malloc(sizeof *entry);
337 fprintf(stderr, "No memory for redirection queue\n");
341 entry->nacl_desc = strtol(optarg, &rest, 0);
342 entry->tag = IMC_DESC;
343 entry->u.handle = (NaClHandle) strtol(rest+1, (char **) 0, 0);
344 *(options->redir_qend) = entry;
345 options->redir_qend = &entry->next;
348 if (NULL != optarg) {
350 * change stdout/stderr to log file now, so that subsequent error
351 * messages will go there. unfortunately, error messages that
352 * result from getopt processing -- usually out-of-memory, which
353 * shouldn't happen -- won't show up.
355 NaClLogSetFile(optarg);
363 fprintf(stderr, "PLATFORM QUALIFICATION DISABLED BY -Q - "
364 "Native Client's sandbox will be unreliable!\n");
365 options->skip_qualification = 1;
368 options->rpc_supplies_nexe = 1;
370 /* case 'r': with 'h' and 'w' above */
372 if (nap->validator->stubout_mode_implemented) {
373 nap->validator_stub_out_mode = 1;
375 NaClLog(LOG_WARNING, "stub_out_mode is not supported, disabled\n");
379 options->handle_signals = 1;
382 ++(options->verbosity);
383 NaClLogIncrVerbosity();
385 /* case 'w': with 'h' and 'r' above */
387 options->export_addr_to = strtol(optarg, (char **) 0, 0);
391 NaClHandleReservedAtZero(optarg);
395 if (nap->validator->readonly_text_implemented) {
396 NaClLog(LOG_WARNING, "Enabling Fixed-Feature CPU Mode\n");
397 nap->fixed_feature_cpu_mode = 1;
398 if (!nap->validator->FixCPUFeatures(nap->cpu_features)) {
400 "This CPU lacks features required by "
401 "fixed-function CPU mode.\n");
405 NaClLog(LOG_ERROR, "fixed_feature_cpu_mode is not supported\n");
410 fprintf(stderr, "ERROR: unknown option: [%c]\n\n", opt);
416 /* Post process the options. */
418 if (options->debug_mode_ignore_validator == 1) {
420 fprintf(stderr, "DEBUG MODE ENABLED (ignore validator)\n");
421 } else if (options->debug_mode_ignore_validator > 1) {
423 fprintf(stderr, "DEBUG MODE ENABLED (skip validator)\n");
426 if (options->verbosity) {
428 char const *separator = "";
430 fprintf(stderr, "sel_ldr argument list:\n");
431 for (ix = 0; ix < argc; ++ix) {
432 fprintf(stderr, "%s%s", separator, argv[ix]);
438 if (options->rpc_supplies_nexe) {
439 if (NULL != options->nacl_file) {
441 "sel_ldr: mutually exclusive flags -f and -R both used\n");
444 /* post: NULL == nacl_file */
445 if (options->export_addr_to < 0) {
447 "sel_ldr: -R requires -X to set up secure command channel\n");
451 if (NULL == options->nacl_file && optind < argc) {
452 options->nacl_file = argv[optind];
455 if (NULL == options->nacl_file) {
456 fprintf(stderr, "No nacl file specified\n");
459 /* post: NULL != nacl_file */
462 * post condition established by the above code (in Hoare logic
465 * NULL == nacl_file iff rpc_supplies_nexe
467 * so hence forth, testing !rpc_supplies_nexe suffices for
468 * establishing NULL != nacl_file.
470 CHECK((NULL == options->nacl_file) == options->rpc_supplies_nexe);
472 /* to be passed to NaClMain, eventually... */
473 if (NULL != options->nacl_file && options->debug_mode_bypass_acl_checks) {
474 argv[--optind] = options->nacl_file;
476 argv[--optind] = (char *) "NaClMain";
479 options->app_argc = argc - optind;
480 options->app_argv = argv + optind;
483 * NACL_DANGEROUS_SKIP_QUALIFICATION_TEST is used by tsan / memcheck
484 * (see src/third_party/valgrind/).
486 if (!options->skip_qualification &&
487 getenv("NACL_DANGEROUS_SKIP_QUALIFICATION_TEST") != NULL) {
489 fprintf(stderr, "PLATFORM QUALIFICATION DISABLED BY ENVIRONMENT - "
490 "Native Client's sandbox will be unreliable!\n");
491 options->skip_qualification = 1;
494 if (getenv("NACL_UNTRUSTED_EXCEPTION_HANDLING") != NULL) {
495 options->enable_exception_handling = 1;
499 static void RedirectIO(struct NaClApp *nap, struct redir *redir_queue){
502 * Execute additional I/O redirections. NB: since the NaClApp
503 * takes ownership of host / IMC socket descriptors, all but
504 * the first run will not get access if the NaClApp closes
505 * them. Currently a normal NaClApp process exit does not
506 * close descriptors, since the underlying host OS will do so
507 * as part of service runtime exit.
509 NaClLog(4, "Processing I/O redirection/inheritance from command line\n");
510 for (entry = redir_queue; NULL != entry; entry = entry->next) {
511 switch (entry->tag) {
513 NaClAddHostDescriptor(nap, entry->u.host.d,
514 entry->u.host.mode, entry->nacl_desc);
517 NaClAddImcHandle(nap, entry->u.handle, entry->nacl_desc);
523 int NaClSelLdrMain(int argc, char **argv) {
524 struct NaClApp *nap = NULL;
525 struct SelLdrOptions optionsImpl;
526 struct SelLdrOptions *options = &optionsImpl;
529 NaClErrorCode errcode = LOAD_INTERNAL;
530 struct NaClDesc *blob_file = NULL;
533 struct DynArray env_vars;
535 struct NaClPerfCounter time_all_main;
537 struct NaClEnvCleanser env_cleanser;
540 /* Mac dynamic libraries cannot access the environ variable directly. */
541 envp = (const char **) *_NSGetEnviron();
543 /* Overzealous code style check is overzealous. */
544 /* @IGNORE_LINES_FOR_CODE_HYGIENE[1] */
545 extern char **environ;
546 envp = (const char **) environ;
551 NaClAllModulesInit();
554 * If this is a secondary process spun up to assist windows exception
555 * handling, the following function will not return. If this is a normal
556 * sel_ldr process, the following function does nothing.
558 NaClDebugExceptionHandlerStandaloneHandleArgs(argc, argv);
560 nap = NaClAppCreate();
562 fprintf(stderr, "NaClAppCreate() failed\n");
566 NaClBootstrapChannelErrorReporterInit();
567 NaClErrorLogHookInit(NaClBootstrapChannelErrorReporter, nap);
569 NaClPerfCounterCtor(&time_all_main, "SelMain");
571 fflush((FILE *) NULL);
573 if (!GioFileRefCtor(&gout, stdout)) {
574 fprintf(stderr, "Could not create general standard output channel\n");
578 SelLdrOptionsCtor(options);
579 if (!DynArrayCtor(&env_vars, 0)) {
580 NaClLog(LOG_FATAL, "Failed to allocate env var array\n");
582 NaClSelLdrParseArgs(argc, argv, options, &env_vars, nap);
584 if (options->debug_mode_startup_signal) {
586 fprintf(stderr, "DEBUG startup signal not supported on Windows\n");
590 * SIGCONT is ignored by default, so this doesn't actually do anything
591 * by itself. The purpose of raising the signal is to get a debugger
592 * to stop and inspect the process before it does anything else. When
593 * sel_ldr is started via nacl_helper_bootstrap, it needs to run as far
594 * as doing its option processing and calling NaClHandleRDebug before
595 * the debugger will understand the association between the address
596 * space and the sel_ldr binary and its dependent shared libraries.
597 * When the debugger stops for the signal, the hacker can run the
598 * "sharedlibrary" command (if the debugger is GDB) and thereafter
599 * it becomes possible to set symbolic breakpoints and so forth.
601 fprintf(stderr, "DEBUG taking startup signal (SIGCONT) now\n");
606 if (options->debug_mode_bypass_acl_checks) {
607 NaClInsecurelyBypassAllAclChecks();
610 nap->ignore_validator_result = (options->debug_mode_ignore_validator > 0);
611 nap->skip_validator = (options->debug_mode_ignore_validator > 1);
612 nap->enable_exception_handling = options->enable_exception_handling;
615 * TODO(mseaborn): Always enable the Mach exception handler on Mac
616 * OS X, and remove handle_signals and sel_ldr's "-S" option.
618 if (nap->enable_exception_handling || options->enable_debug_stub ||
619 (options->handle_signals && NACL_OSX)) {
621 nap->attach_debug_exception_handler_func =
622 NaClDebugExceptionHandlerStandaloneAttach;
624 /* NaCl's signal handler is always enabled on Linux. */
626 if (!NaClInterceptMachExceptions()) {
627 fprintf(stderr, "ERROR setting up Mach exception interception.\n");
631 # error Unknown host OS
638 * in order to report load error to the browser plugin through the
639 * secure command channel, we do not immediate jump to cleanup code
640 * on error. rather, we continue processing (assuming earlier
641 * errors do not make it inappropriate) until the secure command
642 * channel is set up, and then bail out.
646 * Ensure the platform qualification checks pass.
648 if (!options->skip_qualification) {
649 NaClErrorCode pq_error = NACL_FI_VAL("pq", NaClErrorCode,
650 NaClRunSelQualificationTests());
651 if (LOAD_OK != pq_error) {
653 nap->module_load_status = pq_error;
655 fprintf(stderr, "Error while loading \"%s\": %s\n",
656 NULL != options->nacl_file ? options->nacl_file
657 : "(no file, to-be-supplied-via-RPC)",
658 NaClErrorString(errcode));
663 NaClSignalHandlerInit();
666 * Patch the Windows exception dispatcher to be safe in the case of
667 * faults inside x86-64 sandboxed code. The sandbox is not secure
668 * on 64-bit Windows without this.
670 #if (NACL_WINDOWS && NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && \
671 NACL_BUILD_SUBARCH == 64)
672 NaClPatchWindowsExceptionDispatcher();
674 NaClSignalTestCrashOnStartup();
677 * Open both files first because (on Mac OS X at least)
678 * NaClAppLoadFile() enables an outer sandbox.
680 if (NULL != options->blob_library_file) {
681 NaClFileNameForValgrind(options->blob_library_file);
682 blob_file = (struct NaClDesc *) NaClDescIoDescOpen(
683 options->blob_library_file, NACL_ABI_O_RDONLY, 0);
684 if (NULL == blob_file) {
686 fprintf(stderr, "Cannot open \"%s\".\n", options->blob_library_file);
689 NaClPerfCounterMark(&time_all_main, "SnapshotBlob");
690 NaClPerfCounterIntervalLast(&time_all_main);
693 NaClAppInitialDescriptorHookup(nap);
695 if (!options->rpc_supplies_nexe) {
696 if (LOAD_OK == errcode) {
697 NaClLog(2, "Loading nacl file %s (non-RPC)\n", options->nacl_file);
698 errcode = NaClAppLoadFileFromFilename(nap, options->nacl_file);
699 if (LOAD_OK != errcode && !options->quiet) {
700 fprintf(stderr, "Error while loading \"%s\": %s\n",
702 NaClErrorString(errcode));
704 ("Using the wrong type of nexe (nacl-x86-32"
705 " on an x86-64 or vice versa)\n"
706 "or a corrupt nexe file may be"
707 " responsible for this error.\n"));
709 NaClPerfCounterMark(&time_all_main, "AppLoadEnd");
710 NaClPerfCounterIntervalLast(&time_all_main);
713 if (options->fuzzing_quit_after_load) {
718 RedirectIO(nap, options->redir_queue);
721 * If export_addr_to is set to a non-negative integer, we create a
722 * bound socket and socket address pair and bind the former to
723 * descriptor NACL_SERVICE_PORT_DESCRIPTOR (3 [see sel_ldr.h]) and
724 * the latter to descriptor NACL_SERVICE_ADDRESS_DESCRIPTOR (4).
725 * The socket address is sent to the export_addr_to descriptor.
727 * The service runtime also accepts a connection on the bound socket
728 * and spawns a secure command channel thread to service it.
730 if (0 <= options->export_addr_to) {
731 NaClCreateServiceSocket(nap);
733 * LOG_FATAL errors that occur before NaClSetUpBootstrapChannel will
734 * not be reported via the crash log mechanism (for Chromium
735 * embedding of NaCl, shown in the JavaScript console).
737 * Some errors, such as due to NaClRunSelQualificationTests, do not
738 * trigger a LOG_FATAL but instead set module_load_status to be sent
739 * in the start_module RPC reply. Log messages associated with such
740 * errors would be seen, since NaClSetUpBootstrapChannel will get
743 NaClSetUpBootstrapChannel(nap, (NaClHandle) options->export_addr_to);
745 * NB: spawns a thread that uses the command channel. we do
746 * this after NaClAppLoadFile so that NaClApp object is more
747 * fully populated. Hereafter any changes to nap should be done
748 * while holding locks.
750 NaClSecureCommandChannel(nap);
754 * May have created a thread, so need to synchronize uses of nap
755 * contents henceforth.
758 if (options->rpc_supplies_nexe) {
759 errcode = NaClWaitForLoadModuleCommand(nap);
760 NaClPerfCounterMark(&time_all_main, "WaitForLoad");
761 NaClPerfCounterIntervalLast(&time_all_main);
764 if (LOAD_OK == errcode) {
765 if (options->verbosity) {
766 gprintf((struct Gio *) &gout, "printing NaClApp details\n");
767 NaClAppPrintDetails(nap, (struct Gio *) &gout);
772 * Tell the debug stub to bind a TCP port before enabling the outer
773 * sandbox. This is only needed on Mac OS X since that is the only
774 * platform where we have an outer sandbox in standalone sel_ldr.
775 * In principle this call should work on all platforms, but Windows
776 * XP seems to have some problems when we do bind()/listen() on a
777 * separate thread from accept().
779 if (options->enable_debug_stub && NACL_OSX) {
780 if (!NaClDebugBindSocket()) {
786 * Enable the outer sandbox, if one is defined. Do this as soon as
789 * This must come after NaClWaitForLoadModuleCommand(), which waits
790 * for another thread to have called NaClAppLoadFile().
791 * NaClAppLoadFile() does not work inside the Mac outer sandbox in
792 * standalone sel_ldr when using a dynamic code area because it uses
793 * NaClCreateMemoryObject() which opens a file in /tmp.
795 * We cannot enable the sandbox if file access is enabled.
797 if (!NaClAclBypassChecks && g_enable_outer_sandbox_func != NULL) {
798 g_enable_outer_sandbox_func();
801 if (NULL != options->blob_library_file) {
802 if (LOAD_OK == errcode) {
803 NaClLog(2, "Loading blob file %s\n", options->blob_library_file);
804 errcode = NaClMainLoadIrt(nap, blob_file, NULL);
805 if (LOAD_OK != errcode) {
806 fprintf(stderr, "Error while loading \"%s\": %s\n",
807 options->blob_library_file,
808 NaClErrorString(errcode));
810 NaClPerfCounterMark(&time_all_main, "BlobLoaded");
811 NaClPerfCounterIntervalLast(&time_all_main);
814 NaClDescUnref(blob_file);
815 if (options->verbosity) {
816 gprintf((struct Gio *) &gout, "printing post-IRT NaClApp details\n");
817 NaClAppPrintDetails(nap, (struct Gio *) &gout);
822 * Print out a marker for scripts to use to mark the start of app
825 NaClLog(1, "NACL: Application output follows\n");
828 * Make sure all the file buffers are flushed before entering
829 * the application code.
831 fflush((FILE *) NULL);
833 if (NULL != nap->secure_service) {
834 NaClErrorCode start_result;
836 * wait for start_module RPC call on secure channel thread.
838 start_result = NaClWaitForStartModuleCommand(nap);
839 NaClPerfCounterMark(&time_all_main, "WaitedForStartModuleCommand");
840 NaClPerfCounterIntervalLast(&time_all_main);
841 if (LOAD_OK == errcode) {
842 errcode = start_result;
845 NaClAppStartModule(nap, NULL, NULL);
849 * error reporting done; can quit now if there was an error earlier.
851 if (LOAD_OK != errcode) {
853 "Not running app code since errcode is %s (%d)\n",
854 NaClErrorString(errcode),
859 if (!DynArraySet(&env_vars, env_vars.num_entries, NULL)) {
860 NaClLog(LOG_FATAL, "Adding env_vars NULL terminator failed\n");
863 NaClEnvCleanserCtor(&env_cleanser, 0);
864 if (!NaClEnvCleanserInit(&env_cleanser, envp,
865 (char const *const *)env_vars.ptr_array)) {
866 NaClLog(LOG_FATAL, "Failed to initialise env cleanser\n");
869 if (!NaClAppLaunchServiceThreads(nap)) {
870 fprintf(stderr, "Launch service threads failed\n");
873 if (options->enable_debug_stub) {
874 if (!NaClDebugInit(nap)) {
878 NACL_TEST_INJECTION(BeforeMainThreadLaunches, ());
879 if (!NaClCreateMainThread(nap,
882 NaClEnvCleanserEnvironment(&env_cleanser))) {
883 fprintf(stderr, "creating main thread failed\n");
887 NaClEnvCleanserDtor(&env_cleanser);
889 NaClPerfCounterMark(&time_all_main, "CreateMainThread");
890 NaClPerfCounterIntervalLast(&time_all_main);
891 DynArrayDtor(&env_vars);
893 ret_code = NaClWaitForMainThreadToExit(nap);
894 NaClPerfCounterMark(&time_all_main, "WaitForMainThread");
895 NaClPerfCounterIntervalLast(&time_all_main);
897 NaClPerfCounterMark(&time_all_main, "SelMainEnd");
898 NaClPerfCounterIntervalTotal(&time_all_main);
901 * exit_group or equiv kills any still running threads while module
902 * addr space is still valid. otherwise we'd have to kill threads
903 * before we clean up the address space.
910 if (options->verbosity) {
911 gprintf((struct Gio *) &gout, "exiting -- printing NaClApp details\n");
912 NaClAppPrintDetails(nap, (struct Gio *) &gout);
914 printf("Dumping vmmap.\n"); fflush(stdout);
919 * If there is a secure command channel, we sent an RPC reply with
920 * the reason that the nexe was rejected. If we exit now, that
921 * reply may still be in-flight and the various channel closure (esp
922 * reverse channel) may be detected first. This would result in a
923 * crash being reported, rather than the error in the RPC reply.
924 * Instead, we wait for the hard-shutdown on the command channel.
926 if (LOAD_OK != errcode) {
927 NaClBlockIfCommandChannelExists(nap);
930 if (options->verbosity > 0) {
936 NaClSignalHandlerFini();
938 NaClAllModulesFini();
942 /* Unreachable, but having the return prevents a compiler error. */