Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / native_client / src / trusted / service_runtime / sel_main.c
1 /*
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.
5  */
6
7 /*
8  * NaCl Simple/secure ELF loader (NaCl SEL).
9  */
10 #include "native_client/src/include/portability.h"
11 #include "native_client/src/include/portability_io.h"
12
13 #if NACL_OSX
14 #include <crt_externs.h>
15 #endif
16
17 #if NACL_LINUX
18 #include <getopt.h>
19 #endif
20
21 #if !NACL_WINDOWS
22 #include <signal.h>
23 #endif
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28
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"
37
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_qualify.h"
60 #include "native_client/src/trusted/service_runtime/win/exception_patch/ntdll_patch.h"
61 #include "native_client/src/trusted/service_runtime/win/debug_exception_handler.h"
62
63
64 static void (*g_enable_outer_sandbox_func)(void) =
65 #if NACL_OSX
66     NaClEnableOuterSandbox;
67 #else
68     NULL;
69 #endif
70
71 void NaClSetEnableOuterSandboxFunc(void (*func)(void)) {
72   g_enable_outer_sandbox_func = func;
73 }
74
75 static void VmentryPrinter(void           *state,
76                     struct NaClVmmapEntry *vmep) {
77   UNREFERENCED_PARAMETER(state);
78   printf("page num 0x%06x\n", (uint32_t)vmep->page_num);
79   printf("num pages %d\n", (uint32_t)vmep->npages);
80   printf("prot bits %x\n", vmep->prot);
81   fflush(stdout);
82 }
83
84 static void PrintVmmap(struct NaClApp  *nap) {
85   printf("In PrintVmmap\n");
86   fflush(stdout);
87   NaClXMutexLock(&nap->mu);
88   NaClVmmapVisit(&nap->mem_map, VmentryPrinter, (void *) 0);
89
90   NaClXMutexUnlock(&nap->mu);
91 }
92
93
94 struct redir {
95   struct redir  *next;
96   int           nacl_desc;
97   enum {
98     HOST_DESC,
99     IMC_DESC
100   }             tag;
101   union {
102     struct {
103       int d;
104       int mode;
105     }                         host;
106     NaClHandle                handle;
107     struct NaClSocketAddress  addr;
108   } u;
109 };
110
111 int ImportModeMap(char opt) {
112   switch (opt) {
113     case 'h':
114       return O_RDWR;
115     case 'r':
116       return O_RDONLY;
117     case 'w':
118       return O_WRONLY;
119   }
120   fprintf(stderr, ("option %c not understood as a host descriptor"
121                    " import mode\n"),
122           opt);
123   exit(1);
124   /* NOTREACHED */
125 }
126
127 static void PrintUsage(void) {
128   /* NOTE: this is broken up into multiple statements to work around
129            the constant string size limit */
130   fprintf(stderr,
131           "Usage: sel_ldr [-h d:D] [-r d:D] [-w d:D] [-i d:D]\n"
132           "               [-f nacl_file]\n"
133           "               [-l log_file]\n"
134           "               [-X d] [-acFglQRsSQv]\n"
135           "               -- [nacl_file] [args]\n"
136           "\n");
137   fprintf(stderr,
138           " -h\n"
139           " -r\n"
140           " -w associate a host POSIX descriptor D with app desc d\n"
141           "    that was opened in O_RDWR, O_RDONLY, and O_WRONLY modes\n"
142           "    respectively\n"
143           " -i associates an IMC handle D with app desc d\n"
144           " -f file to load; if omitted, 1st arg after \"--\" is loaded\n"
145           " -B additional ELF file to load as a blob library\n"
146           " -v increases verbosity\n"
147           " -X create a bound socket and export the address via an\n"
148           "    IMC message to a corresponding inherited IMC app descriptor\n"
149           "    (use -1 to create the bound socket / address descriptor\n"
150           "    pair, but that no export via IMC should occur)\n");
151   fprintf(stderr,
152           " -R an RPC supplies the NaCl module.\n"
153           "    No nacl_file argument is expected, and the -f flag cannot be\n"
154           "    used with this flag.\n"
155           "\n"
156           " (testing flags)\n"
157           " -a allow file access plus some other syscalls! dangerous!\n"
158           " -c ignore validator! dangerous! Repeating this option twice skips\n"
159           "    validation completely.\n"
160           " -F fuzz testing; quit after loading NaCl app\n"
161           " -g enable gdb debug stub.  Not secure on x86-64 Windows.\n"
162           " -l <file>  write log output to the given file\n"
163           " -q quiet; suppress diagnostic/warning messages at startup\n"
164           " -Q disable platform qualification (dangerous!)\n"
165           " -s safely stub out non-validating instructions\n"
166           " -S enable signal handling.  Not supported on Windows.\n"
167           " -E <name=value>|<name> set an environment variable\n"
168           " -Z use fixed feature x86 CPU mode\n"
169           "\n"
170           " (For full effect, put -l and -q at the beginning.)\n"
171           );  /* easier to add new flags/lines */
172 }
173
174 #if NACL_LINUX
175 static const struct option longopts[] = {
176   { "r_debug", required_argument, NULL, 'D' },
177   { "reserved_at_zero", required_argument, NULL, 'z' },
178   { NULL, 0, NULL, 0 }
179 };
180
181 static int my_getopt(int argc, char *const *argv, const char *shortopts) {
182   return getopt_long(argc, argv, shortopts, longopts, NULL);
183 }
184 #else
185 #define my_getopt getopt
186 #endif
187
188 int NaClSelLdrMain(int argc, char **argv) {
189   int                           opt;
190   char                          *rest;
191   struct redir                  *entry;
192   struct redir                  *redir_queue;
193   struct redir                  **redir_qend;
194
195
196   struct NaClApp                state;
197   char                          *nacl_file = NULL;
198   char                          *blob_library_file = NULL;
199   int                           rpc_supplies_nexe = 0;
200   int                           export_addr_to = -1;
201
202   struct NaClApp                *nap = &state;
203
204   struct GioFile                gout;
205   NaClErrorCode                 errcode = LOAD_INTERNAL;
206   struct NaClDesc               *blob_file = NULL;
207
208   int                           ret_code;
209   struct DynArray               env_vars;
210
211   int                           verbosity = 0;
212   int                           quiet = 0;
213   int                           fuzzing_quit_after_load = 0;
214   int                           debug_mode_bypass_acl_checks = 0;
215   int                           debug_mode_ignore_validator = 0;
216   int                           debug_mode_startup_signal = 0;
217   int                           skip_qualification = 0;
218   int                           handle_signals = 0;
219   int                           enable_debug_stub = 0;
220   struct NaClPerfCounter        time_all_main;
221   const char                    **envp;
222   struct NaClEnvCleanser        env_cleanser;
223
224 #if NACL_OSX
225   /* Mac dynamic libraries cannot access the environ variable directly. */
226   envp = (const char **) *_NSGetEnviron();
227 #else
228   /* Overzealous code style check is overzealous. */
229   /* @IGNORE_LINES_FOR_CODE_HYGIENE[1] */
230   extern char **environ;
231   envp = (const char **) environ;
232 #endif
233
234   ret_code = 1;
235   redir_queue = NULL;
236   redir_qend = &redir_queue;
237
238   memset(&state, 0, sizeof state);
239   NaClAllModulesInit();
240   NaClBootstrapChannelErrorReporterInit();
241   NaClErrorLogHookInit(NaClBootstrapChannelErrorReporter, &state);
242
243   verbosity = NaClLogGetVerbosity();
244
245   NaClPerfCounterCtor(&time_all_main, "SelMain");
246
247   fflush((FILE *) NULL);
248
249   NaClDebugExceptionHandlerStandaloneHandleArgs(argc, argv);
250
251   if (!GioFileRefCtor(&gout, stdout)) {
252     fprintf(stderr, "Could not create general standard output channel\n");
253     exit(1);
254   }
255   if (!NaClAppCtor(&state)) {
256     NaClLog(LOG_FATAL, "NaClAppCtor() failed\n");
257   }
258   if (!DynArrayCtor(&env_vars, 0)) {
259     NaClLog(LOG_FATAL, "Failed to allocate env var array\n");
260   }
261   /*
262    * On platforms with glibc getopt, require POSIXLY_CORRECT behavior,
263    * viz, no reordering of the arglist -- stop argument processing as
264    * soon as an unrecognized argument is encountered, so that, for
265    * example, in the invocation
266    *
267    *   sel_ldr foo.nexe -vvv
268    *
269    * the -vvv flags are made available to the nexe, rather than being
270    * consumed by getopt.  This makes the behavior of the Linux build
271    * of sel_ldr consistent with the Windows and OSX builds.
272    */
273   while ((opt = my_getopt(argc, argv,
274 #if NACL_LINUX
275                        "+D:z:"
276 #endif
277                        "aB:cdeE:f:Fgh:i:l:qQr:RsSvw:X:Z")) != -1) {
278     switch (opt) {
279       case 'a':
280         if (!quiet)
281           fprintf(stderr, "DEBUG MODE ENABLED (bypass acl)\n");
282         debug_mode_bypass_acl_checks = 1;
283         break;
284       case 'B':
285         blob_library_file = optarg;
286         break;
287       case 'c':
288         ++debug_mode_ignore_validator;
289         break;
290       case 'd':
291         debug_mode_startup_signal = 1;
292         break;
293 #if NACL_LINUX
294       case 'D':
295         NaClHandleRDebug(optarg, argv[0]);
296         break;
297 #endif
298       case 'e':
299         nap->enable_exception_handling = 1;
300         break;
301       case 'E':
302         /*
303          * For simplicity, we treat the environment variables as a
304          * list of strings rather than a key/value mapping.  We do not
305          * try to prevent duplicate keys or require the strings to be
306          * of the form "KEY=VALUE".  This is in line with how execve()
307          * works in Unix.
308          *
309          * We expect that most callers passing "-E" will either pass
310          * in a fixed list or will construct the list using a
311          * high-level language, in which case de-duplicating keys
312          * outside of sel_ldr is easier.  However, we could do
313          * de-duplication here if it proves to be worthwhile.
314          */
315         if (!DynArraySet(&env_vars, env_vars.num_entries, optarg)) {
316           NaClLog(LOG_FATAL, "Adding item to env_vars failed\n");
317         }
318         break;
319       case 'f':
320         nacl_file = optarg;
321         break;
322       case 'F':
323         fuzzing_quit_after_load = 1;
324         break;
325
326       case 'g':
327         enable_debug_stub = 1;
328         break;
329
330       case 'h':
331       case 'r':
332       case 'w':
333         /* import host descriptor */
334         entry = malloc(sizeof *entry);
335         if (NULL == entry) {
336           fprintf(stderr, "No memory for redirection queue\n");
337           exit(1);
338         }
339         entry->next = NULL;
340         entry->nacl_desc = strtol(optarg, &rest, 0);
341         entry->tag = HOST_DESC;
342         entry->u.host.d = strtol(rest+1, (char **) 0, 0);
343         entry->u.host.mode = ImportModeMap(opt);
344         *redir_qend = entry;
345         redir_qend = &entry->next;
346         break;
347       case 'i':
348         /* import IMC handle */
349         entry = malloc(sizeof *entry);
350         if (NULL == entry) {
351           fprintf(stderr, "No memory for redirection queue\n");
352           exit(1);
353         }
354         entry->next = NULL;
355         entry->nacl_desc = strtol(optarg, &rest, 0);
356         entry->tag = IMC_DESC;
357         entry->u.handle = (NaClHandle) strtol(rest+1, (char **) 0, 0);
358         *redir_qend = entry;
359         redir_qend = &entry->next;
360         break;
361       case 'l':
362         if (NULL != optarg) {
363           /*
364            * change stdout/stderr to log file now, so that subsequent error
365            * messages will go there.  unfortunately, error messages that
366            * result from getopt processing -- usually out-of-memory, which
367            * shouldn't happen -- won't show up.
368            */
369           NaClLogSetFile(optarg);
370         }
371         break;
372       case 'q':
373         quiet = 1;
374         break;
375       case 'Q':
376         if (!quiet)
377           fprintf(stderr, "PLATFORM QUALIFICATION DISABLED BY -Q - "
378                   "Native Client's sandbox will be unreliable!\n");
379         skip_qualification = 1;
380         break;
381       case 'R':
382         rpc_supplies_nexe = 1;
383         break;
384       /* case 'r':  with 'h' and 'w' above */
385       case 's':
386         if (nap->validator->stubout_mode_implemented) {
387           nap->validator_stub_out_mode = 1;
388         } else {
389            NaClLog(LOG_WARNING,
390                    "stub_out_mode is not supported, disabled\n");
391         }
392         break;
393       case 'S':
394         handle_signals = 1;
395         break;
396       case 'v':
397         ++verbosity;
398         NaClLogIncrVerbosity();
399         break;
400       /* case 'w':  with 'h' and 'r' above */
401       case 'X':
402         export_addr_to = strtol(optarg, (char **) 0, 0);
403         break;
404 #if NACL_LINUX
405       case 'z':
406         NaClHandleReservedAtZero(optarg);
407         break;
408 #endif
409       case 'Z':
410         if (nap->validator->readonly_text_implemented) {
411           NaClLog(LOG_WARNING, "Enabling Fixed-Feature CPU Mode\n");
412           nap->fixed_feature_cpu_mode = 1;
413           if (!nap->validator->FixCPUFeatures(nap->cpu_features)) {
414             NaClLog(LOG_ERROR,
415                     "This CPU lacks features required by "
416                     "fixed-function CPU mode.\n");
417             exit(1);
418           }
419         } else {
420            NaClLog(LOG_ERROR,
421                    "fixed_feature_cpu_mode is not supported\n");
422            exit(1);
423         }
424         break;
425       default:
426         fprintf(stderr, "ERROR: unknown option: [%c]\n\n", opt);
427         PrintUsage();
428         exit(-1);
429     }
430   }
431
432   if (debug_mode_startup_signal) {
433 #if NACL_WINDOWS
434     fprintf(stderr, "DEBUG startup signal not supported on Windows\n");
435     exit(1);
436 #else
437     /*
438      * SIGCONT is ignored by default, so this doesn't actually do anything
439      * by itself.  The purpose of raising the signal is to get a debugger
440      * to stop and inspect the process before it does anything else.  When
441      * sel_ldr is started via nacl_helper_bootstrap, it needs to run as far
442      * as doing its option processing and calling NaClHandleRDebug before
443      * the debugger will understand the association between the address
444      * space and the sel_ldr binary and its dependent shared libraries.
445      * When the debugger stops for the signal, the hacker can run the
446      * "sharedlibrary" command (if the debugger is GDB) and thereafter
447      * it becomes possible to set symbolic breakpoints and so forth.
448      */
449     fprintf(stderr, "DEBUG taking startup signal (SIGCONT) now\n");
450     raise(SIGCONT);
451 #endif
452   }
453
454   if (debug_mode_ignore_validator == 1) {
455     if (!quiet)
456       fprintf(stderr, "DEBUG MODE ENABLED (ignore validator)\n");
457   } else if (debug_mode_ignore_validator > 1) {
458     if (!quiet)
459       fprintf(stderr, "DEBUG MODE ENABLED (skip validator)\n");
460   }
461
462   if (verbosity) {
463     int         ix;
464     char const  *separator = "";
465
466     fprintf(stderr, "sel_ldr argument list:\n");
467     for (ix = 0; ix < argc; ++ix) {
468       fprintf(stderr, "%s%s", separator, argv[ix]);
469       separator = " ";
470     }
471     putc('\n', stderr);
472   }
473
474   if (debug_mode_bypass_acl_checks) {
475     NaClInsecurelyBypassAllAclChecks();
476   }
477
478   if (rpc_supplies_nexe) {
479     if (NULL != nacl_file) {
480       fprintf(stderr,
481               "sel_ldr: mutually exclusive flags -f and -R both used\n");
482       exit(1);
483     }
484     /* post: NULL == nacl_file */
485     if (export_addr_to < 0) {
486       fprintf(stderr,
487               "sel_ldr: -R requires -X to set up secure command channel\n");
488       exit(1);
489     }
490   } else {
491     if (NULL == nacl_file && optind < argc) {
492       nacl_file = argv[optind];
493       ++optind;
494     }
495     if (NULL == nacl_file) {
496       fprintf(stderr, "No nacl file specified\n");
497       exit(1);
498     }
499     /* post: NULL != nacl_file */
500   }
501   /*
502    * post condition established by the above code (in Hoare logic
503    * terminology):
504    *
505    * NULL == nacl_file iff rpc_supplies_nexe
506    *
507    * so hence forth, testing !rpc_supplies_nexe suffices for
508    * establishing NULL != nacl_file.
509    */
510   CHECK((NULL == nacl_file) == rpc_supplies_nexe);
511
512   /* to be passed to NaClMain, eventually... */
513   argv[--optind] = (char *) "NaClMain";
514
515   state.ignore_validator_result = (debug_mode_ignore_validator > 0);
516   state.skip_validator = (debug_mode_ignore_validator > 1);
517
518   if (getenv("NACL_UNTRUSTED_EXCEPTION_HANDLING") != NULL) {
519     state.enable_exception_handling = 1;
520   }
521   /*
522    * TODO(mseaborn): Always enable the Mach exception handler on Mac
523    * OS X, and remove handle_signals and sel_ldr's "-S" option.
524    */
525   if (state.enable_exception_handling || enable_debug_stub ||
526       (handle_signals && NACL_OSX)) {
527 #if NACL_WINDOWS
528     state.attach_debug_exception_handler_func =
529         NaClDebugExceptionHandlerStandaloneAttach;
530 #elif NACL_LINUX
531     /* NaCl's signal handler is always enabled on Linux. */
532 #elif NACL_OSX
533     if (!NaClInterceptMachExceptions()) {
534       fprintf(stderr, "ERROR setting up Mach exception interception.\n");
535       return -1;
536     }
537 #else
538 # error Unknown host OS
539 #endif
540   }
541
542   errcode = LOAD_OK;
543
544   /*
545    * in order to report load error to the browser plugin through the
546    * secure command channel, we do not immediate jump to cleanup code
547    * on error.  rather, we continue processing (assuming earlier
548    * errors do not make it inappropriate) until the secure command
549    * channel is set up, and then bail out.
550    */
551
552   /*
553    * Ensure the platform qualification checks pass.
554    *
555    * NACL_DANGEROUS_SKIP_QUALIFICATION_TEST is used by tsan / memcheck
556    * (see src/third_party/valgrind/).
557    */
558   if (!skip_qualification &&
559       getenv("NACL_DANGEROUS_SKIP_QUALIFICATION_TEST") != NULL) {
560     if (!quiet)
561       fprintf(stderr, "PLATFORM QUALIFICATION DISABLED BY ENVIRONMENT - "
562               "Native Client's sandbox will be unreliable!\n");
563     skip_qualification = 1;
564   }
565
566   if (!skip_qualification) {
567     NaClErrorCode pq_error = NACL_FI_VAL("pq", NaClErrorCode,
568                                          NaClRunSelQualificationTests());
569     if (LOAD_OK != pq_error) {
570       errcode = pq_error;
571       nap->module_load_status = pq_error;
572       if (!quiet)
573         fprintf(stderr, "Error while loading \"%s\": %s\n",
574                 NULL != nacl_file ? nacl_file
575                                   : "(no file, to-be-supplied-via-RPC)",
576                 NaClErrorString(errcode));
577     }
578   }
579
580 #if NACL_LINUX
581   NaClSignalHandlerInit();
582 #endif
583   /*
584    * Patch the Windows exception dispatcher to be safe in the case of
585    * faults inside x86-64 sandboxed code.  The sandbox is not secure
586    * on 64-bit Windows without this.
587    */
588 #if (NACL_WINDOWS && NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && \
589      NACL_BUILD_SUBARCH == 64)
590   NaClPatchWindowsExceptionDispatcher();
591 #endif
592   NaClSignalTestCrashOnStartup();
593
594   /*
595    * Open both files first because (on Mac OS X at least)
596    * NaClAppLoadFile() enables an outer sandbox.
597    */
598   if (NULL != blob_library_file) {
599     NaClFileNameForValgrind(blob_library_file);
600     blob_file = (struct NaClDesc *) NaClDescIoDescOpen(blob_library_file,
601                                                        NACL_ABI_O_RDONLY, 0);
602     if (NULL == blob_file) {
603       perror("sel_main");
604       fprintf(stderr, "Cannot open \"%s\".\n", blob_library_file);
605       exit(1);
606     }
607     NaClPerfCounterMark(&time_all_main, "SnapshotBlob");
608     NaClPerfCounterIntervalLast(&time_all_main);
609   }
610
611   NaClAppInitialDescriptorHookup(nap);
612
613   if (!rpc_supplies_nexe) {
614     if (LOAD_OK == errcode) {
615       NaClLog(2, "Loading nacl file %s (non-RPC)\n", nacl_file);
616       errcode = NaClAppLoadFileFromFilename(nap, nacl_file);
617       if (LOAD_OK != errcode && !quiet) {
618         fprintf(stderr, "Error while loading \"%s\": %s\n",
619                 nacl_file,
620                 NaClErrorString(errcode));
621         fprintf(stderr,
622                 ("Using the wrong type of nexe (nacl-x86-32"
623                  " on an x86-64 or vice versa)\n"
624                  "or a corrupt nexe file may be"
625                  " responsible for this error.\n"));
626       }
627       NaClPerfCounterMark(&time_all_main, "AppLoadEnd");
628       NaClPerfCounterIntervalLast(&time_all_main);
629     }
630
631     if (fuzzing_quit_after_load) {
632       exit(0);
633     }
634   }
635
636   /*
637    * Execute additional I/O redirections.  NB: since the NaClApp
638    * takes ownership of host / IMC socket descriptors, all but
639    * the first run will not get access if the NaClApp closes
640    * them.  Currently a normal NaClApp process exit does not
641    * close descriptors, since the underlying host OS will do so
642    * as part of service runtime exit.
643    */
644   NaClLog(4, "Processing I/O redirection/inheritance from command line\n");
645   for (entry = redir_queue; NULL != entry; entry = entry->next) {
646     switch (entry->tag) {
647       case HOST_DESC:
648         NaClAddHostDescriptor(nap, entry->u.host.d,
649                               entry->u.host.mode, entry->nacl_desc);
650         break;
651       case IMC_DESC:
652         NaClAddImcHandle(nap, entry->u.handle, entry->nacl_desc);
653         break;
654     }
655   }
656
657   /*
658    * If export_addr_to is set to a non-negative integer, we create a
659    * bound socket and socket address pair and bind the former to
660    * descriptor NACL_SERVICE_PORT_DESCRIPTOR (3 [see sel_ldr.h]) and
661    * the latter to descriptor NACL_SERVICE_ADDRESS_DESCRIPTOR (4).
662    * The socket address is sent to the export_addr_to descriptor.
663    *
664    * The service runtime also accepts a connection on the bound socket
665    * and spawns a secure command channel thread to service it.
666    */
667   if (0 <= export_addr_to) {
668     NaClCreateServiceSocket(nap);
669     /*
670      * LOG_FATAL errors that occur before NaClSetUpBootstrapChannel will
671      * not be reported via the crash log mechanism (for Chromium
672      * embedding of NaCl, shown in the JavaScript console).
673      *
674      * Some errors, such as due to NaClRunSelQualificationTests, do not
675      * trigger a LOG_FATAL but instead set module_load_status to be sent
676      * in the start_module RPC reply.  Log messages associated with such
677      * errors would be seen, since NaClSetUpBootstrapChannel will get
678      * called.
679      */
680     NaClSetUpBootstrapChannel(nap, (NaClHandle) export_addr_to);
681     /*
682      * NB: spawns a thread that uses the command channel.  we do
683      * this after NaClAppLoadFile so that NaClApp object is more
684      * fully populated.  Hereafter any changes to nap should be done
685      * while holding locks.
686      */
687     NaClSecureCommandChannel(nap);
688   }
689
690   /*
691    * May have created a thread, so need to synchronize uses of nap
692    * contents henceforth.
693    */
694
695   if (rpc_supplies_nexe) {
696     errcode = NaClWaitForLoadModuleCommand(nap);
697     NaClPerfCounterMark(&time_all_main, "WaitForLoad");
698     NaClPerfCounterIntervalLast(&time_all_main);
699   }
700
701   if (LOAD_OK == errcode) {
702     if (verbosity) {
703       gprintf((struct Gio *) &gout, "printing NaClApp details\n");
704       NaClAppPrintDetails(nap, (struct Gio *) &gout);
705     }
706   }
707
708   /*
709    * Tell the debug stub to bind a TCP port before enabling the outer
710    * sandbox.  This is only needed on Mac OS X since that is the only
711    * platform where we have an outer sandbox in standalone sel_ldr.
712    * In principle this call should work on all platforms, but Windows
713    * XP seems to have some problems when we do bind()/listen() on a
714    * separate thread from accept().
715    */
716   if (enable_debug_stub && NACL_OSX) {
717     if (!NaClDebugBindSocket()) {
718       exit(1);
719     }
720   }
721
722   /*
723    * Enable the outer sandbox, if one is defined.  Do this as soon as
724    * possible.
725    *
726    * This must come after NaClWaitForLoadModuleCommand(), which waits
727    * for another thread to have called NaClAppLoadFile().
728    * NaClAppLoadFile() does not work inside the Mac outer sandbox in
729    * standalone sel_ldr when using a dynamic code area because it uses
730    * NaClCreateMemoryObject() which opens a file in /tmp.
731    *
732    * We cannot enable the sandbox if file access is enabled.
733    */
734   if (!NaClAclBypassChecks && g_enable_outer_sandbox_func != NULL) {
735     g_enable_outer_sandbox_func();
736   }
737
738   if (NULL != blob_library_file) {
739     if (nap->irt_loaded) {
740       NaClLog(LOG_INFO, "IRT loaded via command channel; ignoring -B irt\n");
741     } else if (LOAD_OK == errcode) {
742       NaClLog(2, "Loading blob file %s\n", blob_library_file);
743       errcode = NaClAppLoadFileDynamically(nap, blob_file,
744                                            NULL);
745       if (LOAD_OK == errcode) {
746         nap->irt_loaded = 1;
747       } else {
748         fprintf(stderr, "Error while loading \"%s\": %s\n",
749                 blob_library_file,
750                 NaClErrorString(errcode));
751       }
752       NaClPerfCounterMark(&time_all_main, "BlobLoaded");
753       NaClPerfCounterIntervalLast(&time_all_main);
754     }
755
756     NaClDescUnref(blob_file);
757     if (verbosity) {
758       gprintf((struct Gio *) &gout, "printing post-IRT NaClApp details\n");
759       NaClAppPrintDetails(nap, (struct Gio *) &gout);
760     }
761   }
762
763   /*
764    * Print out a marker for scripts to use to mark the start of app
765    * output.
766    */
767   NaClLog(1, "NACL: Application output follows\n");
768
769   /*
770    * Make sure all the file buffers are flushed before entering
771    * the application code.
772    */
773   fflush((FILE *) NULL);
774
775   if (NULL != nap->secure_service) {
776     NaClErrorCode start_result;
777     /*
778      * wait for start_module RPC call on secure channel thread.
779      */
780     start_result = NaClWaitForStartModuleCommand(nap);
781     NaClPerfCounterMark(&time_all_main, "WaitedForStartModuleCommand");
782     NaClPerfCounterIntervalLast(&time_all_main);
783     if (LOAD_OK == errcode) {
784       errcode = start_result;
785     }
786   } else {
787     NaClAppStartModule(nap, NULL, NULL);
788   }
789
790   /*
791    * error reporting done; can quit now if there was an error earlier.
792    */
793   if (LOAD_OK != errcode) {
794     NaClLog(4,
795             "Not running app code since errcode is %s (%d)\n",
796             NaClErrorString(errcode),
797             errcode);
798     goto done;
799   }
800
801   if (!DynArraySet(&env_vars, env_vars.num_entries, NULL)) {
802     NaClLog(LOG_FATAL, "Adding env_vars NULL terminator failed\n");
803   }
804
805   NaClEnvCleanserCtor(&env_cleanser, 0);
806   if (!NaClEnvCleanserInit(&env_cleanser, envp,
807           (char const *const *)env_vars.ptr_array)) {
808     NaClLog(LOG_FATAL, "Failed to initialise env cleanser\n");
809   }
810
811   if (!NaClAppLaunchServiceThreads(nap)) {
812     fprintf(stderr, "Launch service threads failed\n");
813     goto done;
814   }
815   if (enable_debug_stub) {
816     if (!NaClDebugInit(nap)) {
817       goto done;
818     }
819   }
820   NACL_TEST_INJECTION(BeforeMainThreadLaunches, ());
821   if (!NaClCreateMainThread(nap,
822                             argc - optind,
823                             argv + optind,
824                             NaClEnvCleanserEnvironment(&env_cleanser))) {
825     fprintf(stderr, "creating main thread failed\n");
826     goto done;
827   }
828
829   NaClEnvCleanserDtor(&env_cleanser);
830
831   NaClPerfCounterMark(&time_all_main, "CreateMainThread");
832   NaClPerfCounterIntervalLast(&time_all_main);
833   DynArrayDtor(&env_vars);
834
835   ret_code = NaClWaitForMainThreadToExit(nap);
836   NaClPerfCounterMark(&time_all_main, "WaitForMainThread");
837   NaClPerfCounterIntervalLast(&time_all_main);
838
839   NaClPerfCounterMark(&time_all_main, "SelMainEnd");
840   NaClPerfCounterIntervalTotal(&time_all_main);
841
842   /*
843    * exit_group or equiv kills any still running threads while module
844    * addr space is still valid.  otherwise we'd have to kill threads
845    * before we clean up the address space.
846    */
847   NaClExit(ret_code);
848
849  done:
850   fflush(stdout);
851
852   if (verbosity) {
853     gprintf((struct Gio *) &gout, "exiting -- printing NaClApp details\n");
854     NaClAppPrintDetails(nap, (struct Gio *) &gout);
855
856     printf("Dumping vmmap.\n"); fflush(stdout);
857     PrintVmmap(nap);
858     fflush(stdout);
859   }
860   /*
861    * If there is a secure command channel, we sent an RPC reply with
862    * the reason that the nexe was rejected.  If we exit now, that
863    * reply may still be in-flight and the various channel closure (esp
864    * reverse channel) may be detected first.  This would result in a
865    * crash being reported, rather than the error in the RPC reply.
866    * Instead, we wait for the hard-shutdown on the command channel.
867    */
868   if (LOAD_OK != errcode) {
869     NaClBlockIfCommandChannelExists(nap);
870   }
871
872   if (verbosity > 0) {
873     printf("Done.\n");
874   }
875   fflush(stdout);
876
877 #if NACL_LINUX
878   NaClSignalHandlerFini();
879 #endif
880   NaClAllModulesFini();
881
882   NaClExit(ret_code);
883
884   /* Unreachable, but having the return prevents a compiler error. */
885   return ret_code;
886 }