Upstream version 9.38.198.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_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"
63
64
65 static void (*g_enable_outer_sandbox_func)(void) =
66 #if NACL_OSX
67     NaClEnableOuterSandbox;
68 #else
69     NULL;
70 #endif
71
72 void NaClSetEnableOuterSandboxFunc(void (*func)(void)) {
73   g_enable_outer_sandbox_func = func;
74 }
75
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);
82   fflush(stdout);
83 }
84
85 static void PrintVmmap(struct NaClApp  *nap) {
86   printf("In PrintVmmap\n");
87   fflush(stdout);
88   NaClXMutexLock(&nap->mu);
89   NaClVmmapVisit(&nap->mem_map, VmentryPrinter, (void *) 0);
90
91   NaClXMutexUnlock(&nap->mu);
92 }
93
94
95 struct redir {
96   struct redir  *next;
97   int           nacl_desc;
98   enum {
99     HOST_DESC,
100     IMC_DESC
101   }             tag;
102   union {
103     struct {
104       int d;
105       int mode;
106     }                         host;
107     NaClHandle                handle;
108     struct NaClSocketAddress  addr;
109   } u;
110 };
111
112 int ImportModeMap(char opt) {
113   switch (opt) {
114     case 'h':
115       return O_RDWR;
116     case 'r':
117       return O_RDONLY;
118     case 'w':
119       return O_WRONLY;
120   }
121   fprintf(stderr, ("option %c not understood as a host descriptor"
122                    " import mode\n"),
123           opt);
124   exit(1);
125   /* NOTREACHED */
126 }
127
128 static void PrintUsage(void) {
129   /* NOTE: this is broken up into multiple statements to work around
130            the constant string size limit */
131   fprintf(stderr,
132           "Usage: sel_ldr [-h d:D] [-r d:D] [-w d:D] [-i d:D]\n"
133           "               [-f nacl_file]\n"
134           "               [-l log_file]\n"
135           "               [-X d] [-acFglQRsSQv]\n"
136           "               -- [nacl_file] [args]\n"
137           "\n");
138   fprintf(stderr,
139           " -h\n"
140           " -r\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"
143           "    respectively\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");
152   fprintf(stderr,
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"
156           "\n"
157           " (testing flags)\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"
170           "\n"
171           " (For full effect, put -l and -q at the beginning.)\n"
172           );  /* easier to add new flags/lines */
173 }
174
175 #if NACL_LINUX
176 static const struct option longopts[] = {
177   { "r_debug", required_argument, NULL, 'D' },
178   { "reserved_at_zero", required_argument, NULL, 'z' },
179   { NULL, 0, NULL, 0 }
180 };
181
182 static int my_getopt(int argc, char *const *argv, const char *shortopts) {
183   return getopt_long(argc, argv, shortopts, longopts, NULL);
184 }
185 #else
186 #define my_getopt getopt
187 #endif
188
189 struct SelLdrOptions {
190   char *nacl_file;
191   char *blob_library_file;
192   int app_argc;
193   char **app_argv;
194
195   int quiet;
196   int verbosity;
197   int fuzzing_quit_after_load;
198   int skip_qualification;
199   int handle_signals;
200   int enable_exception_handling;
201   int enable_debug_stub;
202   int rpc_supplies_nexe;
203   int export_addr_to;
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;
209 };
210
211 static void SelLdrOptionsCtor(struct SelLdrOptions *options) {
212   /* Just to be safe. */
213   memset(options, 0, sizeof(*options));
214
215   options->nacl_file = NULL;
216   options->blob_library_file = NULL;
217   options->app_argc = 0;
218   options->app_argv = NULL;
219
220   options->quiet = 0;
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);
234 }
235
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) {
241   int opt;
242   char *rest;
243   struct redir *entry;
244
245   options->verbosity = NaClLogGetVerbosity();
246
247   /*
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
252    *
253    *   sel_ldr foo.nexe -vvv
254    *
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.
258    */
259   while ((opt = my_getopt(argc, argv,
260 #if NACL_LINUX
261                        "+D:z:"
262 #endif
263                        "aB:cdeE:f:Fgh:i:l:qQr:RsSvw:X:Z")) != -1) {
264     switch (opt) {
265       case 'a':
266         if (!options->quiet)
267           fprintf(stderr, "DEBUG MODE ENABLED (bypass acl)\n");
268         options->debug_mode_bypass_acl_checks = 1;
269         break;
270       case 'B':
271         options->blob_library_file = optarg;
272         break;
273       case 'c':
274         ++(options->debug_mode_ignore_validator);
275         break;
276       case 'd':
277         options->debug_mode_startup_signal = 1;
278         break;
279 #if NACL_LINUX
280       case 'D':
281         NaClHandleRDebug(optarg, argv[0]);
282         break;
283 #endif
284       case 'e':
285         options->enable_exception_handling = 1;
286         break;
287       case 'E':
288         /*
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()
293          * works in Unix.
294          *
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.
300          */
301         if (!DynArraySet(env_vars, env_vars->num_entries, optarg)) {
302           NaClLog(LOG_FATAL, "Adding item to env_vars failed\n");
303         }
304         break;
305       case 'f':
306         options->nacl_file = optarg;
307         break;
308       case 'F':
309         options->fuzzing_quit_after_load = 1;
310         break;
311
312       case 'g':
313         options->enable_debug_stub = 1;
314         break;
315
316       case 'h':
317       case 'r':
318       case 'w':
319         /* import host descriptor */
320         entry = malloc(sizeof *entry);
321         if (NULL == entry) {
322           fprintf(stderr, "No memory for redirection queue\n");
323           exit(1);
324         }
325         entry->next = NULL;
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;
332         break;
333       case 'i':
334         /* import IMC handle */
335         entry = malloc(sizeof *entry);
336         if (NULL == entry) {
337           fprintf(stderr, "No memory for redirection queue\n");
338           exit(1);
339         }
340         entry->next = NULL;
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;
346         break;
347       case 'l':
348         if (NULL != optarg) {
349           /*
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.
354            */
355           NaClLogSetFile(optarg);
356         }
357         break;
358       case 'q':
359         options->quiet = 1;
360         break;
361       case 'Q':
362         if (!options->quiet)
363           fprintf(stderr, "PLATFORM QUALIFICATION DISABLED BY -Q - "
364                   "Native Client's sandbox will be unreliable!\n");
365         options->skip_qualification = 1;
366         break;
367       case 'R':
368         options->rpc_supplies_nexe = 1;
369         break;
370       /* case 'r':  with 'h' and 'w' above */
371       case 's':
372         if (nap->validator->stubout_mode_implemented) {
373           nap->validator_stub_out_mode = 1;
374         } else {
375            NaClLog(LOG_WARNING, "stub_out_mode is not supported, disabled\n");
376         }
377         break;
378       case 'S':
379         options->handle_signals = 1;
380         break;
381       case 'v':
382         ++(options->verbosity);
383         NaClLogIncrVerbosity();
384         break;
385       /* case 'w':  with 'h' and 'r' above */
386       case 'X':
387         options->export_addr_to = strtol(optarg, (char **) 0, 0);
388         break;
389 #if NACL_LINUX
390       case 'z':
391         NaClHandleReservedAtZero(optarg);
392         break;
393 #endif
394       case 'Z':
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)) {
399             NaClLog(LOG_ERROR,
400                     "This CPU lacks features required by "
401                     "fixed-function CPU mode.\n");
402             exit(1);
403           }
404         } else {
405            NaClLog(LOG_ERROR, "fixed_feature_cpu_mode is not supported\n");
406            exit(1);
407         }
408         break;
409       default:
410         fprintf(stderr, "ERROR: unknown option: [%c]\n\n", opt);
411         PrintUsage();
412         exit(-1);
413     }
414   }
415
416   /* Post process the options. */
417
418   if (options->debug_mode_ignore_validator == 1) {
419     if (!options->quiet)
420       fprintf(stderr, "DEBUG MODE ENABLED (ignore validator)\n");
421   } else if (options->debug_mode_ignore_validator > 1) {
422     if (!options->quiet)
423       fprintf(stderr, "DEBUG MODE ENABLED (skip validator)\n");
424   }
425
426   if (options->verbosity) {
427     int         ix;
428     char const  *separator = "";
429
430     fprintf(stderr, "sel_ldr argument list:\n");
431     for (ix = 0; ix < argc; ++ix) {
432       fprintf(stderr, "%s%s", separator, argv[ix]);
433       separator = " ";
434     }
435     putc('\n', stderr);
436   }
437
438   if (options->rpc_supplies_nexe) {
439     if (NULL != options->nacl_file) {
440       fprintf(stderr,
441               "sel_ldr: mutually exclusive flags -f and -R both used\n");
442       exit(1);
443     }
444     /* post: NULL == nacl_file */
445     if (options->export_addr_to < 0) {
446       fprintf(stderr,
447               "sel_ldr: -R requires -X to set up secure command channel\n");
448       exit(1);
449     }
450   } else {
451     if (NULL == options->nacl_file && optind < argc) {
452       options->nacl_file = argv[optind];
453       ++optind;
454     }
455     if (NULL == options->nacl_file) {
456       fprintf(stderr, "No nacl file specified\n");
457       exit(1);
458     }
459     /* post: NULL != nacl_file */
460   }
461   /*
462    * post condition established by the above code (in Hoare logic
463    * terminology):
464    *
465    * NULL == nacl_file iff rpc_supplies_nexe
466    *
467    * so hence forth, testing !rpc_supplies_nexe suffices for
468    * establishing NULL != nacl_file.
469    */
470   CHECK((NULL == options->nacl_file) == options->rpc_supplies_nexe);
471
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;
475   } else {
476     argv[--optind] = (char *) "NaClMain";
477   }
478
479   options->app_argc = argc - optind;
480   options->app_argv = argv + optind;
481
482   /*
483    * NACL_DANGEROUS_SKIP_QUALIFICATION_TEST is used by tsan / memcheck
484    * (see src/third_party/valgrind/).
485    */
486   if (!options->skip_qualification &&
487       getenv("NACL_DANGEROUS_SKIP_QUALIFICATION_TEST") != NULL) {
488     if (!options->quiet)
489       fprintf(stderr, "PLATFORM QUALIFICATION DISABLED BY ENVIRONMENT - "
490               "Native Client's sandbox will be unreliable!\n");
491     options->skip_qualification = 1;
492   }
493
494   if (getenv("NACL_UNTRUSTED_EXCEPTION_HANDLING") != NULL) {
495     options->enable_exception_handling = 1;
496   }
497 }
498
499 static void RedirectIO(struct NaClApp *nap, struct redir *redir_queue){
500   struct redir *entry;
501   /*
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.
508    */
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) {
512       case HOST_DESC:
513         NaClAddHostDescriptor(nap, entry->u.host.d,
514                               entry->u.host.mode, entry->nacl_desc);
515         break;
516       case IMC_DESC:
517         NaClAddImcHandle(nap, entry->u.handle, entry->nacl_desc);
518         break;
519     }
520   }
521 }
522
523 int NaClSelLdrMain(int argc, char **argv) {
524   struct NaClApp                *nap = NULL;
525   struct SelLdrOptions          optionsImpl;
526   struct SelLdrOptions          *options = &optionsImpl;
527
528   struct GioFile                gout;
529   NaClErrorCode                 errcode = LOAD_INTERNAL;
530   struct NaClDesc               *blob_file = NULL;
531
532   int                           ret_code;
533   struct DynArray               env_vars;
534
535   struct NaClPerfCounter        time_all_main;
536   const char                    **envp;
537   struct NaClEnvCleanser        env_cleanser;
538
539 #if NACL_OSX
540   /* Mac dynamic libraries cannot access the environ variable directly. */
541   envp = (const char **) *_NSGetEnviron();
542 #else
543   /* Overzealous code style check is overzealous. */
544   /* @IGNORE_LINES_FOR_CODE_HYGIENE[1] */
545   extern char **environ;
546   envp = (const char **) environ;
547 #endif
548
549   ret_code = 1;
550
551   NaClAllModulesInit();
552
553   /*
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.
557    */
558   NaClDebugExceptionHandlerStandaloneHandleArgs(argc, argv);
559
560   nap = NaClAppCreate();
561   if (nap == NULL) {
562     fprintf(stderr, "NaClAppCreate() failed\n");
563     exit(1);
564   }
565
566   NaClBootstrapChannelErrorReporterInit();
567   NaClErrorLogHookInit(NaClBootstrapChannelErrorReporter, nap);
568
569   NaClPerfCounterCtor(&time_all_main, "SelMain");
570
571   fflush((FILE *) NULL);
572
573   if (!GioFileRefCtor(&gout, stdout)) {
574     fprintf(stderr, "Could not create general standard output channel\n");
575     exit(1);
576   }
577
578   SelLdrOptionsCtor(options);
579   if (!DynArrayCtor(&env_vars, 0)) {
580     NaClLog(LOG_FATAL, "Failed to allocate env var array\n");
581   }
582   NaClSelLdrParseArgs(argc, argv, options, &env_vars, nap);
583
584   if (options->debug_mode_startup_signal) {
585 #if NACL_WINDOWS
586     fprintf(stderr, "DEBUG startup signal not supported on Windows\n");
587     exit(1);
588 #else
589     /*
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.
600      */
601     fprintf(stderr, "DEBUG taking startup signal (SIGCONT) now\n");
602     raise(SIGCONT);
603 #endif
604   }
605
606   if (options->debug_mode_bypass_acl_checks) {
607     NaClInsecurelyBypassAllAclChecks();
608   }
609
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;
613
614   /*
615    * TODO(mseaborn): Always enable the Mach exception handler on Mac
616    * OS X, and remove handle_signals and sel_ldr's "-S" option.
617    */
618   if (nap->enable_exception_handling || options->enable_debug_stub ||
619       (options->handle_signals && NACL_OSX)) {
620 #if NACL_WINDOWS
621     nap->attach_debug_exception_handler_func =
622         NaClDebugExceptionHandlerStandaloneAttach;
623 #elif NACL_LINUX
624     /* NaCl's signal handler is always enabled on Linux. */
625 #elif NACL_OSX
626     if (!NaClInterceptMachExceptions()) {
627       fprintf(stderr, "ERROR setting up Mach exception interception.\n");
628       return -1;
629     }
630 #else
631 # error Unknown host OS
632 #endif
633   }
634
635   errcode = LOAD_OK;
636
637   /*
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.
643    */
644
645   /*
646    * Ensure the platform qualification checks pass.
647    */
648   if (!options->skip_qualification) {
649     NaClErrorCode pq_error = NACL_FI_VAL("pq", NaClErrorCode,
650                                          NaClRunSelQualificationTests());
651     if (LOAD_OK != pq_error) {
652       errcode = pq_error;
653       nap->module_load_status = pq_error;
654       if (!options->quiet)
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));
659     }
660   }
661
662 #if NACL_LINUX
663   NaClSignalHandlerInit();
664 #endif
665   /*
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.
669    */
670 #if (NACL_WINDOWS && NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && \
671      NACL_BUILD_SUBARCH == 64)
672   NaClPatchWindowsExceptionDispatcher();
673 #endif
674   NaClSignalTestCrashOnStartup();
675
676   /*
677    * Open both files first because (on Mac OS X at least)
678    * NaClAppLoadFile() enables an outer sandbox.
679    */
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) {
685       perror("sel_main");
686       fprintf(stderr, "Cannot open \"%s\".\n", options->blob_library_file);
687       exit(1);
688     }
689     NaClPerfCounterMark(&time_all_main, "SnapshotBlob");
690     NaClPerfCounterIntervalLast(&time_all_main);
691   }
692
693   NaClAppInitialDescriptorHookup(nap);
694
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",
701                 options->nacl_file,
702                 NaClErrorString(errcode));
703         fprintf(stderr,
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"));
708       }
709       NaClPerfCounterMark(&time_all_main, "AppLoadEnd");
710       NaClPerfCounterIntervalLast(&time_all_main);
711     }
712
713     if (options->fuzzing_quit_after_load) {
714       exit(0);
715     }
716   }
717
718   RedirectIO(nap, options->redir_queue);
719
720   /*
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.
726    *
727    * The service runtime also accepts a connection on the bound socket
728    * and spawns a secure command channel thread to service it.
729    */
730   if (0 <= options->export_addr_to) {
731     NaClCreateServiceSocket(nap);
732     /*
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).
736      *
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
741      * called.
742      */
743     NaClSetUpBootstrapChannel(nap, (NaClHandle) options->export_addr_to);
744     /*
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.
749      */
750     NaClSecureCommandChannel(nap);
751   }
752
753   /*
754    * May have created a thread, so need to synchronize uses of nap
755    * contents henceforth.
756    */
757
758   if (options->rpc_supplies_nexe) {
759     errcode = NaClWaitForLoadModuleCommand(nap);
760     NaClPerfCounterMark(&time_all_main, "WaitForLoad");
761     NaClPerfCounterIntervalLast(&time_all_main);
762   }
763
764   if (LOAD_OK == errcode) {
765     if (options->verbosity) {
766       gprintf((struct Gio *) &gout, "printing NaClApp details\n");
767       NaClAppPrintDetails(nap, (struct Gio *) &gout);
768     }
769   }
770
771   /*
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().
778    */
779   if (options->enable_debug_stub && NACL_OSX) {
780     if (!NaClDebugBindSocket()) {
781       exit(1);
782     }
783   }
784
785   /*
786    * Enable the outer sandbox, if one is defined.  Do this as soon as
787    * possible.
788    *
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.
794    *
795    * We cannot enable the sandbox if file access is enabled.
796    */
797   if (!NaClAclBypassChecks && g_enable_outer_sandbox_func != NULL) {
798     g_enable_outer_sandbox_func();
799   }
800
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));
809       }
810       NaClPerfCounterMark(&time_all_main, "BlobLoaded");
811       NaClPerfCounterIntervalLast(&time_all_main);
812     }
813
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);
818     }
819   }
820
821   /*
822    * Print out a marker for scripts to use to mark the start of app
823    * output.
824    */
825   NaClLog(1, "NACL: Application output follows\n");
826
827   /*
828    * Make sure all the file buffers are flushed before entering
829    * the application code.
830    */
831   fflush((FILE *) NULL);
832
833   if (NULL != nap->secure_service) {
834     NaClErrorCode start_result;
835     /*
836      * wait for start_module RPC call on secure channel thread.
837      */
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;
843     }
844   } else {
845     NaClAppStartModule(nap, NULL, NULL);
846   }
847
848   /*
849    * error reporting done; can quit now if there was an error earlier.
850    */
851   if (LOAD_OK != errcode) {
852     NaClLog(4,
853             "Not running app code since errcode is %s (%d)\n",
854             NaClErrorString(errcode),
855             errcode);
856     goto done;
857   }
858
859   if (!DynArraySet(&env_vars, env_vars.num_entries, NULL)) {
860     NaClLog(LOG_FATAL, "Adding env_vars NULL terminator failed\n");
861   }
862
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");
867   }
868
869   if (!NaClAppLaunchServiceThreads(nap)) {
870     fprintf(stderr, "Launch service threads failed\n");
871     goto done;
872   }
873   if (options->enable_debug_stub) {
874     if (!NaClDebugInit(nap)) {
875       goto done;
876     }
877   }
878   NACL_TEST_INJECTION(BeforeMainThreadLaunches, ());
879   if (!NaClCreateMainThread(nap,
880                             options->app_argc,
881                             options->app_argv,
882                             NaClEnvCleanserEnvironment(&env_cleanser))) {
883     fprintf(stderr, "creating main thread failed\n");
884     goto done;
885   }
886
887   NaClEnvCleanserDtor(&env_cleanser);
888
889   NaClPerfCounterMark(&time_all_main, "CreateMainThread");
890   NaClPerfCounterIntervalLast(&time_all_main);
891   DynArrayDtor(&env_vars);
892
893   ret_code = NaClWaitForMainThreadToExit(nap);
894   NaClPerfCounterMark(&time_all_main, "WaitForMainThread");
895   NaClPerfCounterIntervalLast(&time_all_main);
896
897   NaClPerfCounterMark(&time_all_main, "SelMainEnd");
898   NaClPerfCounterIntervalTotal(&time_all_main);
899
900   /*
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.
904    */
905   NaClExit(ret_code);
906
907  done:
908   fflush(stdout);
909
910   if (options->verbosity) {
911     gprintf((struct Gio *) &gout, "exiting -- printing NaClApp details\n");
912     NaClAppPrintDetails(nap, (struct Gio *) &gout);
913
914     printf("Dumping vmmap.\n"); fflush(stdout);
915     PrintVmmap(nap);
916     fflush(stdout);
917   }
918   /*
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.
925    */
926   if (LOAD_OK != errcode) {
927     NaClBlockIfCommandChannelExists(nap);
928   }
929
930   if (options->verbosity > 0) {
931     printf("Done.\n");
932   }
933   fflush(stdout);
934
935 #if NACL_LINUX
936   NaClSignalHandlerFini();
937 #endif
938   NaClAllModulesFini();
939
940   NaClExit(ret_code);
941
942   /* Unreachable, but having the return prevents a compiler error. */
943   return ret_code;
944 }