LCOV - code coverage report
Current view: directory - src/trusted/service_runtime - sel_main.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 378 231 61.1 %
Date: 2014-06-18 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_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               0 : void NaClSetEnableOuterSandboxFunc(void (*func)(void)) {
      72               0 :   g_enable_outer_sandbox_func = func;
      73               0 : }
      74                 : 
      75               0 : static void VmentryPrinter(void           *state,
      76               0 :                     struct NaClVmmapEntry *vmep) {
      77               0 :   UNREFERENCED_PARAMETER(state);
      78               0 :   printf("page num 0x%06x\n", (uint32_t)vmep->page_num);
      79               0 :   printf("num pages %d\n", (uint32_t)vmep->npages);
      80               0 :   printf("prot bits %x\n", vmep->prot);
      81               0 :   fflush(stdout);
      82               0 : }
      83                 : 
      84               0 : static void PrintVmmap(struct NaClApp  *nap) {
      85               0 :   printf("In PrintVmmap\n");
      86               0 :   fflush(stdout);
      87               0 :   NaClXMutexLock(&nap->mu);
      88               0 :   NaClVmmapVisit(&nap->mem_map, VmentryPrinter, (void *) 0);
      89                 : 
      90               0 :   NaClXMutexUnlock(&nap->mu);
      91               0 : }
      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               0 : int ImportModeMap(char opt) {
     112               0 :   switch (opt) {
     113                 :     case 'h':
     114               0 :       return O_RDWR;
     115                 :     case 'r':
     116               0 :       return O_RDONLY;
     117                 :     case 'w':
     118               0 :       return O_WRONLY;
     119                 :   }
     120               0 :   fprintf(stderr, ("option %c not understood as a host descriptor"
     121                 :                    " import mode\n"),
     122                 :           opt);
     123               0 :   exit(1);
     124                 :   /* NOTREACHED */
     125               0 : }
     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               0 :   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               0 :   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               0 :   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               0 : }
     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             261 : int NaClSelLdrMain(int argc, char **argv) {
     189             261 :   int                           opt;
     190             261 :   char                          *rest;
     191             261 :   struct redir                  *entry;
     192             261 :   struct redir                  *redir_queue;
     193             261 :   struct redir                  **redir_qend;
     194                 : 
     195                 : 
     196             261 :   struct NaClApp                state;
     197             261 :   char                          *nacl_file = NULL;
     198             261 :   char                          *blob_library_file = NULL;
     199             261 :   int                           rpc_supplies_nexe = 0;
     200             261 :   int                           export_addr_to = -1;
     201                 : 
     202             261 :   struct NaClApp                *nap = &state;
     203                 : 
     204             261 :   struct GioFile                gout;
     205             261 :   NaClErrorCode                 errcode = LOAD_INTERNAL;
     206             261 :   struct NaClDesc               *blob_file = NULL;
     207                 : 
     208             261 :   int                           ret_code;
     209             261 :   struct DynArray               env_vars;
     210                 : 
     211             261 :   int                           verbosity = 0;
     212             261 :   int                           quiet = 0;
     213             261 :   int                           fuzzing_quit_after_load = 0;
     214             261 :   int                           debug_mode_bypass_acl_checks = 0;
     215             261 :   int                           debug_mode_ignore_validator = 0;
     216             261 :   int                           debug_mode_startup_signal = 0;
     217             261 :   int                           skip_qualification = 0;
     218             261 :   int                           handle_signals = 0;
     219             261 :   int                           enable_debug_stub = 0;
     220             261 :   struct NaClPerfCounter        time_all_main;
     221             261 :   const char                    **envp;
     222             261 :   struct NaClEnvCleanser        env_cleanser;
     223                 : 
     224                 : #if NACL_OSX
     225                 :   /* Mac dynamic libraries cannot access the environ variable directly. */
     226             261 :   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             261 :   ret_code = 1;
     235             261 :   redir_queue = NULL;
     236             261 :   redir_qend = &redir_queue;
     237                 : 
     238             261 :   memset(&state, 0, sizeof state);
     239             261 :   NaClAllModulesInit();
     240             261 :   NaClBootstrapChannelErrorReporterInit();
     241             261 :   NaClErrorLogHookInit(NaClBootstrapChannelErrorReporter, &state);
     242                 : 
     243             261 :   verbosity = NaClLogGetVerbosity();
     244                 : 
     245             261 :   NaClPerfCounterCtor(&time_all_main, "SelMain");
     246                 : 
     247             261 :   fflush((FILE *) NULL);
     248                 : 
     249             261 :   NaClDebugExceptionHandlerStandaloneHandleArgs(argc, argv);
     250                 : 
     251             261 :   if (!GioFileRefCtor(&gout, stdout)) {
     252               0 :     fprintf(stderr, "Could not create general standard output channel\n");
     253               0 :     exit(1);
     254                 :   }
     255             261 :   if (!NaClAppCtor(&state)) {
     256               0 :     NaClLog(LOG_FATAL, "NaClAppCtor() failed\n");
     257               0 :   }
     258             261 :   if (!DynArrayCtor(&env_vars, 0)) {
     259               0 :     NaClLog(LOG_FATAL, "Failed to allocate env var array\n");
     260               0 :   }
     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             858 :   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             336 :     switch (opt) {
     279                 :       case 'a':
     280             261 :         if (!quiet)
     281             261 :           fprintf(stderr, "DEBUG MODE ENABLED (bypass acl)\n");
     282             261 :         debug_mode_bypass_acl_checks = 1;
     283             261 :         break;
     284                 :       case 'B':
     285               1 :         blob_library_file = optarg;
     286               1 :         break;
     287                 :       case 'c':
     288               1 :         ++debug_mode_ignore_validator;
     289               1 :         break;
     290                 :       case 'd':
     291               0 :         debug_mode_startup_signal = 1;
     292               0 :         break;
     293                 : #if NACL_LINUX
     294                 :       case 'D':
     295                 :         NaClHandleRDebug(optarg, argv[0]);
     296                 :         break;
     297                 : #endif
     298                 :       case 'e':
     299              10 :         nap->enable_exception_handling = 1;
     300              10 :         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              12 :         if (!DynArraySet(&env_vars, env_vars.num_entries, optarg)) {
     316               0 :           NaClLog(LOG_FATAL, "Adding item to env_vars failed\n");
     317               0 :         }
     318              12 :         break;
     319                 :       case 'f':
     320               0 :         nacl_file = optarg;
     321               0 :         break;
     322                 :       case 'F':
     323               1 :         fuzzing_quit_after_load = 1;
     324               1 :         break;
     325                 : 
     326                 :       case 'g':
     327              17 :         enable_debug_stub = 1;
     328              17 :         break;
     329                 : 
     330                 :       case 'h':
     331                 :       case 'r':
     332                 :       case 'w':
     333                 :         /* import host descriptor */
     334               0 :         entry = malloc(sizeof *entry);
     335               0 :         if (NULL == entry) {
     336               0 :           fprintf(stderr, "No memory for redirection queue\n");
     337               0 :           exit(1);
     338                 :         }
     339               0 :         entry->next = NULL;
     340               0 :         entry->nacl_desc = strtol(optarg, &rest, 0);
     341               0 :         entry->tag = HOST_DESC;
     342               0 :         entry->u.host.d = strtol(rest+1, (char **) 0, 0);
     343               0 :         entry->u.host.mode = ImportModeMap(opt);
     344               0 :         *redir_qend = entry;
     345               0 :         redir_qend = &entry->next;
     346               0 :         break;
     347                 :       case 'i':
     348                 :         /* import IMC handle */
     349               0 :         entry = malloc(sizeof *entry);
     350               0 :         if (NULL == entry) {
     351               0 :           fprintf(stderr, "No memory for redirection queue\n");
     352               0 :           exit(1);
     353                 :         }
     354               0 :         entry->next = NULL;
     355               0 :         entry->nacl_desc = strtol(optarg, &rest, 0);
     356               0 :         entry->tag = IMC_DESC;
     357               0 :         entry->u.handle = (NaClHandle) strtol(rest+1, (char **) 0, 0);
     358               0 :         *redir_qend = entry;
     359               0 :         redir_qend = &entry->next;
     360               0 :         break;
     361                 :       case 'l':
     362               0 :         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               0 :           NaClLogSetFile(optarg);
     370               0 :         }
     371               0 :         break;
     372                 :       case 'q':
     373               0 :         quiet = 1;
     374               0 :         break;
     375                 :       case 'Q':
     376               0 :         if (!quiet)
     377               0 :           fprintf(stderr, "PLATFORM QUALIFICATION DISABLED BY -Q - "
     378                 :                   "Native Client's sandbox will be unreliable!\n");
     379               0 :         skip_qualification = 1;
     380               0 :         break;
     381                 :       case 'R':
     382               6 :         rpc_supplies_nexe = 1;
     383               6 :         break;
     384                 :       /* case 'r':  with 'h' and 'w' above */
     385                 :       case 's':
     386               1 :         if (nap->validator->stubout_mode_implemented) {
     387               0 :           nap->validator_stub_out_mode = 1;
     388               0 :         } else {
     389               1 :            NaClLog(LOG_WARNING,
     390                 :                    "stub_out_mode is not supported, disabled\n");
     391                 :         }
     392               1 :         break;
     393                 :       case 'S':
     394               1 :         handle_signals = 1;
     395               1 :         break;
     396                 :       case 'v':
     397              17 :         ++verbosity;
     398              17 :         NaClLogIncrVerbosity();
     399              17 :         break;
     400                 :       /* case 'w':  with 'h' and 'r' above */
     401                 :       case 'X':
     402               6 :         export_addr_to = strtol(optarg, (char **) 0, 0);
     403               6 :         break;
     404                 : #if NACL_LINUX
     405                 :       case 'z':
     406                 :         NaClHandleReservedAtZero(optarg);
     407                 :         break;
     408                 : #endif
     409                 :       case 'Z':
     410               2 :         if (nap->validator->readonly_text_implemented) {
     411               2 :           NaClLog(LOG_WARNING, "Enabling Fixed-Feature CPU Mode\n");
     412               2 :           nap->fixed_feature_cpu_mode = 1;
     413               2 :           if (!nap->validator->FixCPUFeatures(nap->cpu_features)) {
     414               0 :             NaClLog(LOG_ERROR,
     415                 :                     "This CPU lacks features required by "
     416                 :                     "fixed-function CPU mode.\n");
     417               0 :             exit(1);
     418                 :           }
     419               2 :         } else {
     420               0 :            NaClLog(LOG_ERROR,
     421                 :                    "fixed_feature_cpu_mode is not supported\n");
     422               0 :            exit(1);
     423                 :         }
     424               2 :         break;
     425                 :       default:
     426               0 :         fprintf(stderr, "ERROR: unknown option: [%c]\n\n", opt);
     427               0 :         PrintUsage();
     428               0 :         exit(-1);
     429                 :     }
     430             336 :   }
     431                 : 
     432             261 :   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               0 :     fprintf(stderr, "DEBUG taking startup signal (SIGCONT) now\n");
     450               0 :     raise(SIGCONT);
     451                 : #endif
     452               0 :   }
     453                 : 
     454             261 :   if (debug_mode_ignore_validator == 1) {
     455               1 :     if (!quiet)
     456               1 :       fprintf(stderr, "DEBUG MODE ENABLED (ignore validator)\n");
     457             261 :   } else if (debug_mode_ignore_validator > 1) {
     458               0 :     if (!quiet)
     459               0 :       fprintf(stderr, "DEBUG MODE ENABLED (skip validator)\n");
     460               0 :   }
     461                 : 
     462             261 :   if (verbosity) {
     463              19 :     int         ix;
     464              19 :     char const  *separator = "";
     465                 : 
     466              19 :     fprintf(stderr, "sel_ldr argument list:\n");
     467             318 :     for (ix = 0; ix < argc; ++ix) {
     468             140 :       fprintf(stderr, "%s%s", separator, argv[ix]);
     469             140 :       separator = " ";
     470             140 :     }
     471              19 :     putc('\n', stderr);
     472              19 :   }
     473                 : 
     474             261 :   if (debug_mode_bypass_acl_checks) {
     475             261 :     NaClInsecurelyBypassAllAclChecks();
     476             261 :   }
     477                 : 
     478             261 :   if (rpc_supplies_nexe) {
     479               6 :     if (NULL != nacl_file) {
     480               0 :       fprintf(stderr,
     481                 :               "sel_ldr: mutually exclusive flags -f and -R both used\n");
     482               0 :       exit(1);
     483                 :     }
     484                 :     /* post: NULL == nacl_file */
     485               6 :     if (export_addr_to < 0) {
     486               0 :       fprintf(stderr,
     487                 :               "sel_ldr: -R requires -X to set up secure command channel\n");
     488               0 :       exit(1);
     489                 :     }
     490               6 :   } else {
     491             510 :     if (NULL == nacl_file && optind < argc) {
     492             255 :       nacl_file = argv[optind];
     493             255 :       ++optind;
     494             255 :     }
     495             255 :     if (NULL == nacl_file) {
     496               0 :       fprintf(stderr, "No nacl file specified\n");
     497               0 :       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             783 :   CHECK((NULL == nacl_file) == rpc_supplies_nexe);
     511                 : 
     512                 :   /* to be passed to NaClMain, eventually... */
     513             261 :   argv[--optind] = (char *) "NaClMain";
     514                 : 
     515             261 :   state.ignore_validator_result = (debug_mode_ignore_validator > 0);
     516             261 :   state.skip_validator = (debug_mode_ignore_validator > 1);
     517                 : 
     518             261 :   if (getenv("NACL_UNTRUSTED_EXCEPTION_HANDLING") != NULL) {
     519               0 :     state.enable_exception_handling = 1;
     520               0 :   }
     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             746 :   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              28 :     if (!NaClInterceptMachExceptions()) {
     534               0 :       fprintf(stderr, "ERROR setting up Mach exception interception.\n");
     535               0 :       return -1;
     536                 :     }
     537                 : #else
     538                 : # error Unknown host OS
     539                 : #endif
     540              28 :   }
     541                 : 
     542             261 :   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             261 :   if (!skip_qualification &&
     559             261 :       getenv("NACL_DANGEROUS_SKIP_QUALIFICATION_TEST") != NULL) {
     560               0 :     if (!quiet)
     561               0 :       fprintf(stderr, "PLATFORM QUALIFICATION DISABLED BY ENVIRONMENT - "
     562                 :               "Native Client's sandbox will be unreliable!\n");
     563               0 :     skip_qualification = 1;
     564               0 :   }
     565                 : 
     566             261 :   if (!skip_qualification) {
     567             783 :     NaClErrorCode pq_error = NACL_FI_VAL("pq", NaClErrorCode,
     568                 :                                          NaClRunSelQualificationTests());
     569             261 :     if (LOAD_OK != pq_error) {
     570               0 :       errcode = pq_error;
     571               0 :       nap->module_load_status = pq_error;
     572               0 :       if (!quiet)
     573               0 :         fprintf(stderr, "Error while loading \"%s\": %s\n",
     574                 :                 NULL != nacl_file ? nacl_file
     575                 :                                   : "(no file, to-be-supplied-via-RPC)",
     576               0 :                 NaClErrorString(errcode));
     577               0 :     }
     578             261 :   }
     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             261 :   NaClSignalTestCrashOnStartup();
     593                 : 
     594                 :   /*
     595                 :    * Open both files first because (on Mac OS X at least)
     596                 :    * NaClAppLoadFile() enables an outer sandbox.
     597                 :    */
     598             261 :   if (NULL != blob_library_file) {
     599               1 :     NaClFileNameForValgrind(blob_library_file);
     600               1 :     blob_file = (struct NaClDesc *) NaClDescIoDescOpen(blob_library_file,
     601                 :                                                        NACL_ABI_O_RDONLY, 0);
     602               1 :     if (NULL == blob_file) {
     603               0 :       perror("sel_main");
     604               0 :       fprintf(stderr, "Cannot open \"%s\".\n", blob_library_file);
     605               0 :       exit(1);
     606                 :     }
     607               1 :     NaClPerfCounterMark(&time_all_main, "SnapshotBlob");
     608               1 :     NaClPerfCounterIntervalLast(&time_all_main);
     609               1 :   }
     610                 : 
     611             261 :   NaClAppInitialDescriptorHookup(nap);
     612                 : 
     613             261 :   if (!rpc_supplies_nexe) {
     614             255 :     if (LOAD_OK == errcode) {
     615             253 :       NaClLog(2, "Loading nacl file %s (non-RPC)\n", nacl_file);
     616             253 :       errcode = NaClAppLoadFileFromFilename(nap, nacl_file);
     617             260 :       if (LOAD_OK != errcode && !quiet) {
     618              14 :         fprintf(stderr, "Error while loading \"%s\": %s\n",
     619                 :                 nacl_file,
     620               7 :                 NaClErrorString(errcode));
     621               7 :         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               7 :       }
     627             253 :       NaClPerfCounterMark(&time_all_main, "AppLoadEnd");
     628             253 :       NaClPerfCounterIntervalLast(&time_all_main);
     629             253 :     }
     630                 : 
     631             253 :     if (fuzzing_quit_after_load) {
     632               0 :       exit(0);
     633                 :     }
     634             252 :   }
     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             258 :   NaClLog(4, "Processing I/O redirection/inheritance from command line\n");
     645             516 :   for (entry = redir_queue; NULL != entry; entry = entry->next) {
     646               0 :     switch (entry->tag) {
     647                 :       case HOST_DESC:
     648               0 :         NaClAddHostDescriptor(nap, entry->u.host.d,
     649                 :                               entry->u.host.mode, entry->nacl_desc);
     650               0 :         break;
     651                 :       case IMC_DESC:
     652               0 :         NaClAddImcHandle(nap, entry->u.handle, entry->nacl_desc);
     653               0 :         break;
     654                 :     }
     655               0 :   }
     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             258 :   if (0 <= export_addr_to) {
     668               6 :     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               6 :     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               6 :     NaClSecureCommandChannel(nap);
     688               6 :   }
     689                 : 
     690                 :   /*
     691                 :    * May have created a thread, so need to synchronize uses of nap
     692                 :    * contents henceforth.
     693                 :    */
     694                 : 
     695             258 :   if (rpc_supplies_nexe) {
     696               6 :     errcode = NaClWaitForLoadModuleCommand(nap);
     697               6 :     NaClPerfCounterMark(&time_all_main, "WaitForLoad");
     698               6 :     NaClPerfCounterIntervalLast(&time_all_main);
     699               6 :   }
     700                 : 
     701             258 :   if (LOAD_OK == errcode) {
     702             251 :     if (verbosity) {
     703              19 :       gprintf((struct Gio *) &gout, "printing NaClApp details\n");
     704              19 :       NaClAppPrintDetails(nap, (struct Gio *) &gout);
     705              19 :     }
     706             251 :   }
     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             258 :   if (enable_debug_stub && NACL_OSX) {
     717              17 :     if (!NaClDebugBindSocket()) {
     718               0 :       exit(1);
     719                 :     }
     720              17 :   }
     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             258 :   if (!NaClAclBypassChecks && g_enable_outer_sandbox_func != NULL) {
     735               0 :     g_enable_outer_sandbox_func();
     736               0 :   }
     737                 : 
     738             258 :   if (NULL != blob_library_file) {
     739               1 :     if (nap->irt_loaded) {
     740               0 :       NaClLog(LOG_INFO, "IRT loaded via command channel; ignoring -B irt\n");
     741               1 :     } else if (LOAD_OK == errcode) {
     742               1 :       NaClLog(2, "Loading blob file %s\n", blob_library_file);
     743               1 :       errcode = NaClAppLoadFileDynamically(nap, blob_file,
     744                 :                                            NULL);
     745               1 :       if (LOAD_OK == errcode) {
     746               1 :         nap->irt_loaded = 1;
     747               3 :         CHECK(NULL == nap->irt_nexe_desc);
     748               1 :         NaClDescRef(blob_file);
     749               1 :         nap->irt_nexe_desc = blob_file;
     750               1 :       } else {
     751               0 :         fprintf(stderr, "Error while loading \"%s\": %s\n",
     752                 :                 blob_library_file,
     753               0 :                 NaClErrorString(errcode));
     754                 :       }
     755               1 :       NaClPerfCounterMark(&time_all_main, "BlobLoaded");
     756               1 :       NaClPerfCounterIntervalLast(&time_all_main);
     757               1 :     }
     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               0 :     }
     764               1 :   }
     765                 : 
     766                 :   /*
     767                 :    * Print out a marker for scripts to use to mark the start of app
     768                 :    * output.
     769                 :    */
     770             258 :   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             258 :   fflush((FILE *) NULL);
     777                 : 
     778             258 :   if (NULL != nap->secure_service) {
     779               6 :     NaClErrorCode start_result;
     780                 :     /*
     781                 :      * wait for start_module RPC call on secure channel thread.
     782                 :      */
     783               6 :     start_result = NaClWaitForStartModuleCommand(nap);
     784               6 :     NaClPerfCounterMark(&time_all_main, "WaitedForStartModuleCommand");
     785               6 :     NaClPerfCounterIntervalLast(&time_all_main);
     786               6 :     if (LOAD_OK == errcode) {
     787               6 :       errcode = start_result;
     788               6 :     }
     789               6 :   } else {
     790             252 :     NaClAppStartModule(nap, NULL, NULL);
     791                 :   }
     792                 : 
     793                 :   /*
     794                 :    * error reporting done; can quit now if there was an error earlier.
     795                 :    */
     796             258 :   if (LOAD_OK != errcode) {
     797               7 :     NaClLog(4,
     798                 :             "Not running app code since errcode is %s (%d)\n",
     799               7 :             NaClErrorString(errcode),
     800                 :             errcode);
     801               7 :     goto done;
     802                 :   }
     803                 : 
     804             251 :   if (!DynArraySet(&env_vars, env_vars.num_entries, NULL)) {
     805               0 :     NaClLog(LOG_FATAL, "Adding env_vars NULL terminator failed\n");
     806               0 :   }
     807                 : 
     808             251 :   NaClEnvCleanserCtor(&env_cleanser, 0);
     809             251 :   if (!NaClEnvCleanserInit(&env_cleanser, envp,
     810                 :           (char const *const *)env_vars.ptr_array)) {
     811               0 :     NaClLog(LOG_FATAL, "Failed to initialise env cleanser\n");
     812               0 :   }
     813                 : 
     814             251 :   if (!NaClAppLaunchServiceThreads(nap)) {
     815               0 :     fprintf(stderr, "Launch service threads failed\n");
     816               0 :     goto done;
     817                 :   }
     818             251 :   if (enable_debug_stub) {
     819              17 :     if (!NaClDebugInit(nap)) {
     820               0 :       goto done;
     821                 :     }
     822              17 :   }
     823             754 :   NACL_TEST_INJECTION(BeforeMainThreadLaunches, ());
     824             502 :   if (!NaClCreateMainThread(nap,
     825                 :                             argc - optind,
     826                 :                             argv + optind,
     827             251 :                             NaClEnvCleanserEnvironment(&env_cleanser))) {
     828               0 :     fprintf(stderr, "creating main thread failed\n");
     829               0 :     goto done;
     830                 :   }
     831                 : 
     832             251 :   NaClEnvCleanserDtor(&env_cleanser);
     833                 : 
     834             251 :   NaClPerfCounterMark(&time_all_main, "CreateMainThread");
     835             251 :   NaClPerfCounterIntervalLast(&time_all_main);
     836             251 :   DynArrayDtor(&env_vars);
     837                 : 
     838             251 :   ret_code = NaClWaitForMainThreadToExit(nap);
     839             251 :   NaClPerfCounterMark(&time_all_main, "WaitForMainThread");
     840             251 :   NaClPerfCounterIntervalLast(&time_all_main);
     841                 : 
     842             251 :   NaClPerfCounterMark(&time_all_main, "SelMainEnd");
     843             251 :   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             251 :   NaClExit(ret_code);
     851                 : 
     852                 :  done:
     853               7 :   fflush(stdout);
     854                 : 
     855               7 :   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               0 :   }
     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               7 :   if (LOAD_OK != errcode) {
     872               7 :     NaClBlockIfCommandChannelExists(nap);
     873               7 :   }
     874                 : 
     875               7 :   if (verbosity > 0) {
     876               0 :     printf("Done.\n");
     877               0 :   }
     878               7 :   fflush(stdout);
     879                 : 
     880                 : #if NACL_LINUX
     881                 :   NaClSignalHandlerFini();
     882                 : #endif
     883               7 :   NaClAllModulesFini();
     884                 : 
     885               7 :   NaClExit(ret_code);
     886                 : 
     887                 :   /* Unreachable, but having the return prevents a compiler error. */
     888               7 :   return ret_code;
     889               0 : }

Generated by: LCOV version 1.7