LCOV - code coverage report
Current view: directory - src/trusted/service_runtime - sel_main.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 313 193 61.7 %
Date: 2014-07-02 Functions: 0 0 -

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

Generated by: LCOV version 1.7