LCOV - code coverage report
Current view: directory - src/trusted/service_runtime - sel_main.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 328 151 46.0 %
Date: 2012-02-16 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                 : #include <errno.h>
      22                 : #include <limits.h>
      23                 : #include <stdio.h>
      24                 : #include <stdlib.h>
      25                 : #include <string.h>
      26                 : 
      27                 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_arm || NACL_SANDBOX_FIXED_AT_ZERO == 1
      28                 : /* Required for our use of mallopt -- see below. */
      29                 : #include <malloc.h>
      30                 : #endif
      31                 : 
      32                 : #include "native_client/src/shared/gio/gio.h"
      33                 : #include "native_client/src/shared/imc/nacl_imc_c.h"
      34                 : #include "native_client/src/shared/platform/nacl_check.h"
      35                 : #include "native_client/src/shared/platform/nacl_exit.h"
      36                 : #include "native_client/src/shared/platform/nacl_log.h"
      37                 : #include "native_client/src/shared/platform/nacl_sync.h"
      38                 : #include "native_client/src/shared/platform/nacl_sync_checked.h"
      39                 : #include "native_client/src/shared/srpc/nacl_srpc.h"
      40                 : 
      41                 : #include "native_client/src/trusted/fault_injection/fault_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/nacl_app.h"
      46                 : #include "native_client/src/trusted/service_runtime/nacl_all_modules.h"
      47                 : #include "native_client/src/trusted/service_runtime/nacl_config_dangerous.h"
      48                 : #include "native_client/src/trusted/service_runtime/nacl_globals.h"
      49                 : #include "native_client/src/trusted/service_runtime/nacl_signal.h"
      50                 : #include "native_client/src/trusted/service_runtime/nacl_syscall_common.h"
      51                 : #include "native_client/src/trusted/service_runtime/nacl_valgrind_hooks.h"
      52                 : #include "native_client/src/trusted/service_runtime/outer_sandbox.h"
      53                 : #include "native_client/src/trusted/service_runtime/sel_ldr.h"
      54                 : #include "native_client/src/trusted/service_runtime/sel_qualify.h"
      55                 : #include "native_client/src/trusted/service_runtime/win/exception_patch/ntdll_patch.h"
      56                 : #if NACL_WINDOWS
      57                 : #include "native_client/src/trusted/service_runtime/win/debug_exception_handler.h"
      58                 : #elif NACL_OSX
      59                 : #include "native_client/src/trusted/service_runtime/osx/mach_exception_handler.h"
      60                 : #endif
      61                 : 
      62                 : static void VmentryPrinter(void           *state,
      63               0 :                     struct NaClVmmapEntry *vmep) {
      64                 :   UNREFERENCED_PARAMETER(state);
      65               0 :   printf("page num 0x%06x\n", (uint32_t)vmep->page_num);
      66               0 :   printf("num pages %d\n", (uint32_t)vmep->npages);
      67               0 :   printf("prot bits %x\n", vmep->prot);
      68               0 :   fflush(stdout);
      69               0 : }
      70                 : 
      71               0 : static void PrintVmmap(struct NaClApp  *nap) {
      72               0 :   printf("In PrintVmmap\n");
      73               0 :   fflush(stdout);
      74               0 :   NaClXMutexLock(&nap->mu);
      75               0 :   NaClVmmapVisit(&nap->mem_map, VmentryPrinter, (void *) 0);
      76                 : 
      77               0 :   NaClXMutexUnlock(&nap->mu);
      78               0 : }
      79                 : 
      80                 : 
      81                 : struct redir {
      82                 :   struct redir  *next;
      83                 :   int           nacl_desc;
      84                 :   enum {
      85                 :     HOST_DESC,
      86                 :     IMC_DESC
      87                 :   }             tag;
      88                 :   union {
      89                 :     struct {
      90                 :       int d;
      91                 :       int mode;
      92                 :     }                         host;
      93                 :     NaClHandle                handle;
      94                 :     struct NaClSocketAddress  addr;
      95                 :   } u;
      96                 : };
      97                 : 
      98               0 : int ImportModeMap(char opt) {
      99               0 :   switch (opt) {
     100                 :     case 'h':
     101               0 :       return O_RDWR;
     102                 :     case 'r':
     103               0 :       return O_RDONLY;
     104                 :     case 'w':
     105               0 :       return O_WRONLY;
     106                 :   }
     107               0 :   fprintf(stderr, ("option %c not understood as a host descriptor"
     108                 :                    " import mode\n"),
     109                 :           opt);
     110               0 :   exit(1);
     111                 :   /* NOTREACHED */
     112                 : }
     113                 : 
     114                 : 
     115               0 : static void PrintUsage() {
     116                 :   /* NOTE: this is broken up into multiple statements to work around
     117                 :            the constant string size limit */
     118               0 :   fprintf(stderr,
     119                 :           "Usage: sel_ldr [-h d:D] [-r d:D] [-w d:D] [-i d:D]\n"
     120                 :           "               [-f nacl_file]\n"
     121                 :           "               [-l log_file]\n"
     122                 :           "               [-X d] [-acFgImMRsQv] -- [nacl_file] [args]\n"
     123                 :           "\n");
     124               0 :   fprintf(stderr,
     125                 :           " -h\n"
     126                 :           " -r\n"
     127                 :           " -w associate a host POSIX descriptor D with app desc d\n"
     128                 :           "    that was opened in O_RDWR, O_RDONLY, and O_WRONLY modes\n"
     129                 :           "    respectively\n"
     130                 :           " -i associates an IMC handle D with app desc d\n"
     131                 :           " -f file to load; if omitted, 1st arg after \"--\" is loaded\n"
     132                 :           " -B additional ELF file to load as a blob library\n"
     133                 :           " -v increases verbosity\n"
     134                 :           " -X create a bound socket and export the address via an\n"
     135                 :           "    IMC message to a corresponding NaCl app descriptor\n"
     136                 :           "    (use -1 to create the bound socket / address descriptor\n"
     137                 :           "    pair, but that no export via IMC should occur)\n");
     138               0 :   fprintf(stderr,
     139                 :           " -R an RPC supplies the NaCl module.\n"
     140                 :           "    No nacl_file argument is expected, and the -f flag cannot be\n"
     141                 :           "    used with this flag.\n"
     142                 :           "\n"
     143                 :           " (testing flags)\n"
     144                 :           " -a allow file access! dangerous!\n"
     145                 :           " -c ignore validator! dangerous! Repeating this option twice skips\n"
     146                 :           "    validation completely.\n"
     147                 :           " -F fuzz testing; quit after loading NaCl app\n"
     148                 :           " -S enable signal handling.  Not secure on x86-64 Windows.\n"
     149                 :           " -g enable gdb debug stub.  Not secure on x86-64 Windows.\n"
     150                 :           " -l <file>  write log output to the given file\n"
     151                 :           " -s safely stub out non-validating instructions\n"
     152                 :           " -Q disable platform qualification (dangerous!)\n"
     153                 :           " -E <name=value>|<name> set an environment variable\n"
     154                 :           );  /* easier to add new flags/lines */
     155               0 : }
     156                 : 
     157                 : #if NACL_LINUX
     158                 : static const struct option longopts[] = {
     159                 :   { "r_debug", required_argument, NULL, 'D' },
     160                 :   { NULL, 0, NULL, 0 }
     161                 : };
     162                 : 
     163                 : static int my_getopt(int argc, char *const *argv, const char *shortopts) {
     164                 :   return getopt_long(argc, argv, shortopts, longopts, NULL);
     165                 : }
     166                 : #else
     167                 : #define my_getopt getopt
     168                 : #endif
     169                 : 
     170                 : int main(int  argc,
     171              13 :          char **argv) {
     172                 :   int                           opt;
     173                 :   char                          *rest;
     174                 :   struct redir                  *entry;
     175                 :   struct redir                  *redir_queue;
     176                 :   struct redir                  **redir_qend;
     177                 : 
     178                 : 
     179                 :   struct NaClApp                state;
     180              13 :   char                          *nacl_file = NULL;
     181              13 :   char                          *blob_library_file = NULL;
     182              13 :   int                           rpc_supplies_nexe = 0;
     183              13 :   int                           export_addr_to = -2;
     184                 : 
     185                 :   struct NaClApp                *nap;
     186                 : 
     187                 :   struct GioFile                gout;
     188              13 :   NaClErrorCode                 errcode = LOAD_INTERNAL;
     189                 :   struct GioMemoryFileSnapshot  blob_file;
     190                 : 
     191                 :   int                           ret_code;
     192                 :   struct DynArray               env_vars;
     193                 : 
     194              13 :   char                          *log_file = NULL;
     195              13 :   int                           verbosity = 0;
     196              13 :   int                           fuzzing_quit_after_load = 0;
     197              13 :   int                           debug_mode_bypass_acl_checks = 0;
     198              13 :   int                           debug_mode_ignore_validator = 0;
     199              13 :   int                           stub_out_mode = 0;
     200              13 :   int                           skip_qualification = 0;
     201              13 :   int                           enable_debug_stub = 0;
     202              13 :   int                           handle_signals = 0;
     203              13 :   int                           exception_handling_requested = 0;
     204              13 :   int                           enable_exception_handling = 0;
     205                 :   struct NaClPerfCounter        time_all_main;
     206                 :   const char                    **envp;
     207                 :   struct NaClEnvCleanser        env_cleanser;
     208                 : 
     209                 : 
     210                 :   const char* sandbox_fd_string;
     211                 : 
     212                 : #if NACL_OSX
     213                 :   /* Mac dynamic libraries cannot access the environ variable directly. */
     214              13 :   envp = (const char **) *_NSGetEnviron();
     215                 : #else
     216                 :   /* Overzealous code style check is overzealous. */
     217                 :   /* @IGNORE_LINES_FOR_CODE_HYGIENE[1] */
     218                 :   extern char **environ;
     219                 :   envp = (const char **) environ;
     220                 : #endif
     221                 : 
     222                 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_arm || NACL_SANDBOX_FIXED_AT_ZERO == 1
     223                 :   /*
     224                 :    * Set malloc not to use mmap even for large allocations.  This is currently
     225                 :    * necessary when we must use a specific area of RAM for the sandbox.
     226                 :    *
     227                 :    * During startup, before the sandbox is set up, the sel_ldr allocates a chunk
     228                 :    * of memory to store the untrusted code.  Normally such an allocation would
     229                 :    * go into the sel_ldr's heap area, but the allocation is typically large --
     230                 :    * at least hundreds of KiB.  The default malloc configuration on Linux (at
     231                 :    * least) switches to mmap for such allocations, and mmap will select
     232                 :    * essentially any unoccupied section of the address space.  The result: the
     233                 :    * nexe is allocated in the region we use for the sandbox, we protect the
     234                 :    * address space, and then the memcpy into the sandbox (of course) fails.
     235                 :    *
     236                 :    * This is at best a temporary fix.  The proper fix is to reserve the
     237                 :    * sandbox region early enough that this isn't a problem.  Possible methods
     238                 :    * are discussed in this bug:
     239                 :    *   http://code.google.com/p/nativeclient/issues/detail?id=232
     240                 :    */
     241                 :   mallopt(M_MMAP_MAX, 0);
     242                 : #endif
     243                 : 
     244              13 :   ret_code = 1;
     245              13 :   redir_queue = NULL;
     246              13 :   redir_qend = &redir_queue;
     247                 : 
     248              13 :   NaClAllModulesInit();
     249                 : 
     250              13 :   verbosity = NaClLogGetVerbosity();
     251                 : 
     252              13 :   NaClPerfCounterCtor(&time_all_main, "SelMain");
     253                 : 
     254              13 :   fflush((FILE *) NULL);
     255                 : 
     256              13 :   if (!GioFileRefCtor(&gout, stdout)) {
     257               0 :     fprintf(stderr, "Could not create general standard output channel\n");
     258               0 :     exit(1);
     259                 :   }
     260                 : 
     261              13 :   if (!DynArrayCtor(&env_vars, 0)) {
     262               0 :     NaClLog(LOG_FATAL, "Failed to allocate env var array\n");
     263                 :   }
     264                 :   /*
     265                 :    * On platforms with glibc getopt, require POSIXLY_CORRECT behavior,
     266                 :    * viz, no reordering of the arglist -- stop argument processing as
     267                 :    * soon as an unrecognized argument is encountered, so that, for
     268                 :    * example, in the invocation
     269                 :    *
     270                 :    *   sel_ldr foo.nexe -vvv
     271                 :    *
     272                 :    * the -vvv flags are made available to the nexe, rather than being
     273                 :    * consumed by getopt.  This makes the behavior of the Linux build
     274                 :    * of sel_ldr consistent with the Windows and OSX builds.
     275                 :    */
     276              35 :   while ((opt = my_getopt(argc, argv,
     277                 : #if NACL_LINUX
     278                 :                        "+D:"
     279                 : #endif
     280                 :                        "aB:ceE:f:Fgh:i:Il:Qr:RsSvw:X:")) != -1) {
     281               9 :     switch (opt) {
     282                 :       case 'e':
     283               0 :         exception_handling_requested = 1;
     284               0 :         break;
     285                 : #if NACL_LINUX
     286                 :       case 'D':
     287                 :         handle_r_debug(optarg, argv[0]);
     288                 :         break;
     289                 : #endif
     290                 :       case 'c':
     291               0 :         ++debug_mode_ignore_validator;
     292               0 :         break;
     293                 :       case 'a':
     294               3 :         fprintf(stderr, "DEBUG MODE ENABLED (bypass acl)\n");
     295               3 :         debug_mode_bypass_acl_checks = 1;
     296               3 :         break;
     297                 :       case 'f':
     298               0 :         nacl_file = optarg;
     299               0 :         break;
     300                 :       case 'B':
     301               1 :         blob_library_file = optarg;
     302               1 :         break;
     303                 :       case 'F':
     304               0 :         fuzzing_quit_after_load = 1;
     305               0 :         break;
     306                 : 
     307                 :       case 'g':
     308               0 :         handle_signals = 1;
     309               0 :         enable_debug_stub = 1;
     310               0 :         break;
     311                 : 
     312                 :       case 'S':
     313               0 :         handle_signals = 1;
     314               0 :         break;
     315                 : 
     316                 :       case 'h':
     317                 :       case 'r':
     318                 :       case 'w':
     319                 :         /* import host descriptor */
     320               0 :         entry = malloc(sizeof *entry);
     321               0 :         if (NULL == entry) {
     322               0 :           fprintf(stderr, "No memory for redirection queue\n");
     323               0 :           exit(1);
     324                 :         }
     325               0 :         entry->next = NULL;
     326               0 :         entry->nacl_desc = strtol(optarg, &rest, 0);
     327               0 :         entry->tag = HOST_DESC;
     328               0 :         entry->u.host.d = strtol(rest+1, (char **) 0, 0);
     329               0 :         entry->u.host.mode = ImportModeMap(opt);
     330               0 :         *redir_qend = entry;
     331               0 :         redir_qend = &entry->next;
     332               0 :         break;
     333                 :       case 'i':
     334                 :         /* import IMC handle */
     335               3 :         entry = malloc(sizeof *entry);
     336               3 :         if (NULL == entry) {
     337               0 :           fprintf(stderr, "No memory for redirection queue\n");
     338               0 :           exit(1);
     339                 :         }
     340               3 :         entry->next = NULL;
     341               3 :         entry->nacl_desc = strtol(optarg, &rest, 0);
     342               3 :         entry->tag = IMC_DESC;
     343               3 :         entry->u.handle = (NaClHandle) strtol(rest+1, (char **) 0, 0);
     344               3 :         *redir_qend = entry;
     345               3 :         redir_qend = &entry->next;
     346               3 :         break;
     347                 :       case 'l':
     348               0 :         log_file = optarg;
     349               0 :         break;
     350                 :       case 'R':
     351               1 :         rpc_supplies_nexe = 1;
     352               1 :         break;
     353                 :       /* case 'r':  with 'h' and 'w' above */
     354                 :       case 'v':
     355               0 :         ++verbosity;
     356               0 :         NaClLogIncrVerbosity();
     357               0 :         break;
     358                 :       /* case 'w':  with 'h' and 'r' above */
     359                 :       case 'X':
     360               1 :         export_addr_to = strtol(optarg, (char **) 0, 0);
     361               1 :         break;
     362                 :       case 'Q':
     363               0 :         fprintf(stderr, "PLATFORM QUALIFICATION DISABLED BY -Q - "
     364                 :                 "Native Client's sandbox will be unreliable!\n");
     365               0 :         skip_qualification = 1;
     366               0 :         break;
     367                 :       case 's':
     368               0 :         stub_out_mode = 1;
     369               0 :         break;
     370                 :       case 'E':
     371                 :         /*
     372                 :          * For simplicity, we treat the environment variables as a
     373                 :          * list of strings rather than a key/value mapping.  We do not
     374                 :          * try to prevent duplicate keys or require the strings to be
     375                 :          * of the form "KEY=VALUE".  This is in line with how execve()
     376                 :          * works in Unix.
     377                 :          *
     378                 :          * We expect that most callers passing "-E" will either pass
     379                 :          * in a fixed list or will construct the list using a
     380                 :          * high-level language, in which case de-duplicating keys
     381                 :          * outside of sel_ldr is easier.  However, we could do
     382                 :          * de-duplication here if it proves to be worthwhile.
     383                 :          */
     384               0 :         if (!DynArraySet(&env_vars, env_vars.num_entries, optarg)) {
     385               0 :           NaClLog(LOG_FATAL, "Adding item to env_vars failed\n");
     386                 :         }
     387               0 :         break;
     388                 :       default:
     389               0 :         fprintf(stderr, "ERROR: unknown option: [%c]\n\n", opt);
     390               0 :         PrintUsage();
     391               0 :         exit(-1);
     392                 :     }
     393                 :   }
     394                 : 
     395              13 :   if (exception_handling_requested) {
     396                 : #if NACL_WINDOWS
     397                 :     int status;
     398                 :     DWORD exit_code;
     399                 :     enable_exception_handling = 1;
     400                 :     status = NaClLaunchAndDebugItself(argv[0], &exit_code);
     401                 :     if (status == DEBUG_EXCEPTION_HANDLER_NOT_SUPPORTED) {
     402                 :       enable_exception_handling = 0;
     403                 :     } else if (status == DEBUG_EXCEPTION_HANDLER_SUCCESS) {
     404                 :       return exit_code;
     405                 :     } else if (status == DEBUG_EXCEPTION_HANDLER_ERROR) {
     406                 :       fprintf(stderr, "ERROR in debug exception handling %d\n",
     407                 :               GetLastError());
     408                 :       return -1;
     409                 :     }
     410                 : #elif NACL_LINUX
     411                 :     handle_signals = 1;
     412                 :     enable_exception_handling = 1;
     413                 : #elif NACL_OSX
     414                 :     int status;
     415               0 :     enable_exception_handling = 1;
     416               0 :     status = NaClInterceptMachExceptions();
     417               0 :     if (!status) {
     418               0 :       fprintf(stderr, "ERROR setting up Mach exception interception.\n");
     419               0 :       return -1;
     420                 :     }
     421                 : #else
     422                 : # error Unknown host OS
     423                 : #endif
     424                 :   }
     425              13 :   if (exception_handling_requested && !enable_exception_handling) {
     426               0 :     fprintf(stderr, "WARNING: exception handling is not supported\n");
     427                 :   }
     428                 : 
     429              13 :   if (debug_mode_ignore_validator == 1)
     430               0 :     fprintf(stderr, "DEBUG MODE ENABLED (ignore validator)\n");
     431              13 :   else if (debug_mode_ignore_validator > 1)
     432               0 :     fprintf(stderr, "DEBUG MODE ENABLED (skip validator)\n");
     433                 : 
     434              13 :   if (verbosity) {
     435                 :     int         ix;
     436               0 :     char const  *separator = "";
     437                 : 
     438               0 :     fprintf(stderr, "sel_ldr argument list:\n");
     439               0 :     for (ix = 0; ix < argc; ++ix) {
     440               0 :       fprintf(stderr, "%s%s", separator, argv[ix]);
     441               0 :       separator = " ";
     442                 :     }
     443               0 :     putc('\n', stderr);
     444                 :   }
     445                 : 
     446                 :   if (NACL_DANGEROUS_STUFF_ENABLED) {
     447                 :     fprintf(stderr,
     448                 :             "WARNING WARNING WARNING WARNING"
     449                 :             " WARNING WARNING WARNING WARNING\n");
     450                 :     fprintf(stderr,
     451                 :             "WARNING\n");
     452                 :     fprintf(stderr,
     453                 :             "WARNING  Using a dangerous/debug configuration.\n");
     454                 :     fprintf(stderr,
     455                 :             "WARNING\n");
     456                 :     fprintf(stderr,
     457                 :             "WARNING WARNING WARNING WARNING"
     458                 :             " WARNING WARNING WARNING WARNING\n");
     459                 :   }
     460                 : 
     461              13 :   if (debug_mode_bypass_acl_checks) {
     462               3 :     NaClInsecurelyBypassAllAclChecks();
     463                 :   }
     464                 : 
     465                 : #if NACL_DANGEROUS_DEBUG_MODE_DISABLE_INNER_SANDBOX
     466                 :   if (debug_mode_bypass_acl_checks == 0 &&
     467                 :       debug_mode_ignore_validator == 0) {
     468                 :     fprintf(stderr,
     469                 :             "ERROR: dangerous debug version of sel_ldr can only "
     470                 :             "be invoked with -a/-c options");
     471                 :     exit(-1);
     472                 :   }
     473                 : #endif
     474                 :   /*
     475                 :    * change stdout/stderr to log file now, so that subsequent error
     476                 :    * messages will go there.  unfortunately, error messages that
     477                 :    * result from getopt processing -- usually out-of-memory, which
     478                 :    * shouldn't happen -- won't show up.
     479                 :    */
     480              13 :   if (NULL != log_file) {
     481               0 :     NaClLogSetFile(log_file);
     482                 :   }
     483                 : 
     484              13 :   if (rpc_supplies_nexe) {
     485               1 :     if (NULL != nacl_file) {
     486               0 :       fprintf(stderr,
     487                 :               "sel_ldr: mutually exclusive flags -f and -R both used\n");
     488               0 :       exit(1);
     489                 :     }
     490                 :     /* post: NULL == nacl_file */
     491               1 :     if (export_addr_to < 0) {
     492               0 :       fprintf(stderr,
     493                 :               "sel_ldr: -R requires -X to set up secure command channel\n");
     494               0 :       exit(1);
     495                 :     }
     496                 :   } else {
     497              12 :     if (NULL == nacl_file && optind < argc) {
     498              12 :       nacl_file = argv[optind];
     499              12 :       ++optind;
     500                 :     }
     501              12 :     if (NULL == nacl_file) {
     502               0 :       fprintf(stderr, "No nacl file specified\n");
     503               0 :       exit(1);
     504                 :     }
     505                 :     /* post: NULL != nacl_file */
     506                 :   }
     507                 :   /*
     508                 :    * post condition established by the above code (in Hoare logic
     509                 :    * terminology):
     510                 :    *
     511                 :    * NULL == nacl_file iff rpc_supplies_nexe
     512                 :    *
     513                 :    * so hence forth, testing !rpc_supplies_nexe suffices for
     514                 :    * establishing NULL != nacl_file.
     515                 :    */
     516              13 :   CHECK((NULL == nacl_file) == rpc_supplies_nexe);
     517                 : 
     518                 :   /* to be passed to NaClMain, eventually... */
     519              13 :   argv[--optind] = (char *) "NaClMain";
     520                 : 
     521              13 :   if (!NaClAppCtor(&state)) {
     522               0 :     fprintf(stderr, "Error while constructing app state\n");
     523               0 :     goto done_file_dtor;
     524                 :   }
     525                 : 
     526              13 :   state.ignore_validator_result = (debug_mode_ignore_validator > 0);
     527              13 :   state.skip_validator = (debug_mode_ignore_validator > 1);
     528              13 :   state.validator_stub_out_mode = stub_out_mode;
     529              13 :   state.enable_debug_stub = enable_debug_stub;
     530              13 :   state.enable_exception_handling = enable_exception_handling;
     531                 : 
     532              13 :   nap = &state;
     533              13 :   errcode = LOAD_OK;
     534                 : 
     535                 :   /*
     536                 :    * in order to report load error to the browser plugin through the
     537                 :    * secure command channel, we do not immediate jump to cleanup code
     538                 :    * on error.  rather, we continue processing (assuming earlier
     539                 :    * errors do not make it inappropriate) until the secure command
     540                 :    * channel is set up, and then bail out.
     541                 :    */
     542                 : 
     543                 :   /*
     544                 :    * Ensure the platform qualification checks pass.
     545                 :    *
     546                 :    * NACL_DANGEROUS_SKIP_QUALIFICATION_TEST is used by tsan / memcheck
     547                 :    * (see src/third_party/valgrind/).
     548                 :    */
     549              13 :   if (!skip_qualification &&
     550                 :       getenv("NACL_DANGEROUS_SKIP_QUALIFICATION_TEST") != NULL) {
     551               0 :     fprintf(stderr, "PLATFORM QUALIFICATION DISABLED BY ENVIRONMENT - "
     552                 :             "Native Client's sandbox will be unreliable!\n");
     553               0 :     skip_qualification = 1;
     554                 :   }
     555                 : 
     556                 :   /* We use the signal handler to verify a signal took place. */
     557              13 :   NaClSignalHandlerInit();
     558              12 :   if (!skip_qualification) {
     559              12 :     NaClErrorCode pq_error = NACL_FI_VAL("pq", NaClErrorCode,
     560                 :                                          NaClRunSelQualificationTests());
     561              12 :     if (LOAD_OK != pq_error) {
     562               0 :       errcode = pq_error;
     563               0 :       nap->module_load_status = pq_error;
     564               0 :       fprintf(stderr, "Error while loading \"%s\": %s\n",
     565                 :               NULL != nacl_file ? nacl_file
     566                 :                                 : "(no file, to-be-supplied-via-RPC)",
     567                 :               NaClErrorString(errcode));
     568                 :     }
     569                 :   }
     570                 : 
     571                 :   /* Remove the signal handler if we are not using it. */
     572              12 :   if (!handle_signals) {
     573              12 :     NaClSignalHandlerFini();
     574                 :     /* Sanity check. */
     575              12 :     NaClSignalAssertNoHandlers();
     576                 : 
     577                 :     /*
     578                 :      * Patch the Windows exception dispatcher to be safe in the case
     579                 :      * of faults inside x86-64 sandboxed code.  The sandbox is not
     580                 :      * secure on 64-bit Windows without this.
     581                 :      */
     582                 : #if (NACL_WINDOWS && NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && \
     583                 :      NACL_BUILD_SUBARCH == 64)
     584                 :     NaClPatchWindowsExceptionDispatcher();
     585                 : #endif
     586                 :   }
     587                 : 
     588                 :   /*
     589                 :    * Open both files first because (on Mac OS X at least)
     590                 :    * NaClAppLoadFile() enables an outer sandbox.
     591                 :    */
     592              12 :   if (NULL != blob_library_file) {
     593               0 :     NaClFileNameForValgrind(blob_library_file);
     594               0 :     if (0 == GioMemoryFileSnapshotCtor(&blob_file, blob_library_file)) {
     595               0 :       perror("sel_main");
     596               0 :       fprintf(stderr, "Cannot open \"%s\".\n", blob_library_file);
     597               0 :       exit(1);
     598                 :     }
     599               0 :     NaClPerfCounterMark(&time_all_main, "SnapshotBlob");
     600               0 :     NaClPerfCounterIntervalLast(&time_all_main);
     601                 :   }
     602                 : 
     603              12 :   NaClAppInitialDescriptorHookup(nap);
     604                 : 
     605              12 :   if (!rpc_supplies_nexe) {
     606                 :     struct GioMemoryFileSnapshot main_file;
     607                 : 
     608              12 :     NaClFileNameForValgrind(nacl_file);
     609              12 :     if (0 == GioMemoryFileSnapshotCtor(&main_file, nacl_file)) {
     610               1 :       perror("sel_main");
     611               1 :       fprintf(stderr, "Cannot open \"%s\".\n", nacl_file);
     612               1 :       exit(1);
     613                 :     }
     614              11 :     NaClPerfCounterMark(&time_all_main, "SnapshotNaclFile");
     615              11 :     NaClPerfCounterIntervalLast(&time_all_main);
     616                 : 
     617              11 :     if (LOAD_OK == errcode) {
     618              11 :       NaClLog(2, "Loading nacl file %s (non-RPC)\n", nacl_file);
     619              11 :       errcode = NaClAppLoadFile((struct Gio *) &main_file, nap);
     620              11 :       if (LOAD_OK != errcode) {
     621               8 :         fprintf(stderr, "Error while loading \"%s\": %s\n",
     622                 :                 nacl_file,
     623                 :                 NaClErrorString(errcode));
     624               8 :         fprintf(stderr,
     625                 :                 ("Using the wrong type of nexe (nacl-x86-32"
     626                 :                  " on an x86-64 or vice versa)\n"
     627                 :                  "or a corrupt nexe file may be"
     628                 :                  " responsible for this error.\n"));
     629                 :       }
     630              11 :       NaClPerfCounterMark(&time_all_main, "AppLoadEnd");
     631              11 :       NaClPerfCounterIntervalLast(&time_all_main);
     632                 : 
     633              11 :       NaClXMutexLock(&nap->mu);
     634              11 :       nap->module_load_status = errcode;
     635              11 :       NaClXCondVarBroadcast(&nap->cv);
     636              11 :       NaClXMutexUnlock(&nap->mu);
     637                 :     }
     638                 : 
     639              11 :     if (-1 == (*((struct Gio *) &main_file)->vtbl->Close)((struct Gio *)
     640                 :                                                           &main_file)) {
     641               0 :       fprintf(stderr, "Error while closing \"%s\".\n", nacl_file);
     642                 :     }
     643              11 :     (*((struct Gio *) &main_file)->vtbl->Dtor)((struct Gio *) &main_file);
     644                 : 
     645              11 :     if (fuzzing_quit_after_load) {
     646               0 :       exit(0);
     647                 :     }
     648                 :   }
     649                 : 
     650                 :   /*
     651                 :    * Execute additional I/O redirections.  NB: since the NaClApp
     652                 :    * takes ownership of host / IMC socket descriptors, all but
     653                 :    * the first run will not get access if the NaClApp closes
     654                 :    * them.  Currently a normal NaClApp process exit does not
     655                 :    * close descriptors, since the underlying host OS will do so
     656                 :    * as part of service runtime exit.
     657                 :    */
     658              11 :   NaClLog(4, "Processing I/O redirection/inheritance from command line\n");
     659              11 :   for (entry = redir_queue; NULL != entry; entry = entry->next) {
     660               0 :     switch (entry->tag) {
     661                 :       case HOST_DESC:
     662               0 :         NaClAddHostDescriptor(nap, entry->u.host.d,
     663                 :                               entry->u.host.mode, entry->nacl_desc);
     664               0 :         break;
     665                 :       case IMC_DESC:
     666               0 :         NaClAddImcHandle(nap, entry->u.handle, entry->nacl_desc);
     667                 :         break;
     668                 :     }
     669                 :   }
     670                 : 
     671                 :   /*
     672                 :    * If export_addr_to is set to a non-negative integer, we create a
     673                 :    * bound socket and socket address pair and bind the former to
     674                 :    * descriptor 3 and the latter to descriptor 4.  The socket address
     675                 :    * is written out to the export_addr_to descriptor.
     676                 :    *
     677                 :    * The service runtime also accepts a connection on the bound socket
     678                 :    * and spawns a secure command channel thread to service it.
     679                 :    *
     680                 :    * If export_addr_to is -1, we only create the bound socket and
     681                 :    * socket address pair, and we do not export to an IMC socket.  This
     682                 :    * use case is typically only used in testing, where we only "dump"
     683                 :    * the socket address to stdout or similar channel.
     684                 :    */
     685              11 :   if (-2 < export_addr_to) {
     686               0 :     NaClCreateServiceSocket(nap);
     687               0 :     if (0 <= export_addr_to) {
     688               0 :       NaClSendServiceAddressTo(nap, 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               0 :       NaClSecureCommandChannel(nap);
     696                 :     }
     697                 :   }
     698                 : 
     699                 :   /*
     700                 :    * May have created a thread, so need to synchronize uses of nap
     701                 :    * contents henceforth.
     702                 :    */
     703                 : 
     704              11 :   if (rpc_supplies_nexe) {
     705               0 :     errcode = NaClWaitForLoadModuleStatus(nap);
     706               0 :     NaClPerfCounterMark(&time_all_main, "WaitForLoad");
     707               0 :     NaClPerfCounterIntervalLast(&time_all_main);
     708                 :   } else {
     709                 :     /**************************************************************************
     710                 :      * TODO(bsy): This else block should be made unconditional and
     711                 :      * invoked after the LoadModule RPC completes, eliminating the
     712                 :      * essentially dulicated code in latter part of NaClLoadModuleRpc.
     713                 :      * This cannot be done until we have full saucer separation
     714                 :      * technology, since Chrome currently uses sel_main_chrome.c and
     715                 :      * relies on the functionality of the duplicated code.
     716                 :      *************************************************************************/
     717              11 :     if (LOAD_OK == errcode) {
     718               3 :       if (verbosity) {
     719               0 :         gprintf((struct Gio *) &gout, "printing NaClApp details\n");
     720               0 :         NaClAppPrintDetails(nap, (struct Gio *) &gout);
     721                 :       }
     722                 : 
     723                 :       /*
     724                 :        * Finish setting up the NaCl App.  On x86-32, this means
     725                 :        * allocating segment selectors.  On x86-64 and ARM, this is
     726                 :        * (currently) a no-op.
     727                 :        */
     728               3 :       errcode = NaClAppPrepareToLaunch(nap);
     729               3 :       if (LOAD_OK != errcode) {
     730               0 :         nap->module_load_status = errcode;
     731               0 :         fprintf(stderr, "NaClAppPrepareToLaunch returned %d", errcode);
     732                 :       }
     733               3 :       NaClPerfCounterMark(&time_all_main, "AppPrepLaunch");
     734               3 :       NaClPerfCounterIntervalLast(&time_all_main);
     735                 :     }
     736                 : 
     737                 :     /* Give debuggers a well known point at which xlate_base is known.  */
     738              11 :     NaClGdbHook(&state);
     739                 :   }
     740                 : 
     741                 : 
     742              11 :   if (NULL != blob_library_file) {
     743               0 :     if (LOAD_OK == errcode) {
     744               0 :       NaClLog(2, "Loading blob file %s\n", blob_library_file);
     745               0 :       errcode = NaClAppLoadFileDynamically(nap, (struct Gio *) &blob_file);
     746               0 :       if (LOAD_OK != errcode) {
     747               0 :         fprintf(stderr, "Error while loading \"%s\": %s\n",
     748                 :                 blob_library_file,
     749                 :                 NaClErrorString(errcode));
     750                 :       }
     751               0 :       NaClPerfCounterMark(&time_all_main, "BlobLoaded");
     752               0 :       NaClPerfCounterIntervalLast(&time_all_main);
     753                 :     }
     754                 : 
     755               0 :     if (-1 == (*((struct Gio *) &blob_file)->vtbl->Close)((struct Gio *)
     756                 :                                                           &blob_file)) {
     757               0 :       fprintf(stderr, "Error while closing \"%s\".\n", blob_library_file);
     758                 :     }
     759               0 :     (*((struct Gio *) &blob_file)->vtbl->Dtor)((struct Gio *) &blob_file);
     760               0 :     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              11 :   NaClLog(1, "NACL: Application output follows\n");
     771                 : 
     772                 :   /*
     773                 :    * Chroot() ourselves.  Based on agl's chrome implementation.
     774                 :    *
     775                 :    * TODO(mseaborn): This enables a SUID-based Linux outer sandbox,
     776                 :    * but it is not used now.  When we do have an outer sandbox for
     777                 :    * standalone sel_ldr, we should enable it earlier on, and merge it
     778                 :    * with NaClEnableOuterSandbox().
     779                 :    */
     780              11 :   sandbox_fd_string = getenv(NACL_SANDBOX_CHROOT_FD);
     781              11 :   if (NULL != sandbox_fd_string) {
     782                 :     static const char kChrootMe = 'C';
     783                 :     static const char kChrootSuccess = 'O';
     784                 : 
     785                 :     char* endptr;
     786                 :     char reply;
     787                 :     int fd;
     788                 :     long fd_long;
     789               0 :     errno = 0;  /* To distinguish between success/failure after call */
     790               0 :     fd_long = strtol(sandbox_fd_string, &endptr, 10);
     791                 : 
     792               0 :     NaClLog(1, "Chrooting the NaCl module\n");
     793               0 :     if ((ERANGE == errno && (LONG_MAX == fd_long || LONG_MIN == fd_long)) ||
     794                 :         (0 != errno && 0 == fd_long)) {
     795               0 :       perror("strtol");
     796               0 :       exit(1);
     797                 :     }
     798               0 :     if (endptr == sandbox_fd_string) {
     799               0 :       fprintf(stderr, "Could not initialize sandbox fd: No digits found\n");
     800               0 :       exit(1);
     801                 :     }
     802               0 :     if (*endptr) {
     803               0 :       fprintf(stderr, "Could not initialize sandbox fd: Extra digits\n");
     804               0 :       exit(1);
     805                 :     }
     806               0 :     fd = fd_long;
     807                 : 
     808                 :     /*
     809                 :      * TODO(neha): When we're more merged with chrome, use HANDLE_EINTR()
     810                 :      */
     811               0 :     if (write(fd, &kChrootMe, 1) != 1) {
     812               0 :       fprintf(stderr, "Cound not signal sandbox to chroot()\n");
     813               0 :       exit(1);
     814                 :     }
     815                 : 
     816                 :     /*
     817                 :      * TODO(neha): When we're more merged with chrome, use HANDLE_EINTR()
     818                 :      */
     819               0 :     if (read(fd, &reply, 1) != 1) {
     820               0 :       fprintf(stderr, "Could not get response to chroot() from sandbox\n");
     821               0 :       exit(1);
     822                 :     }
     823               0 :     if (kChrootSuccess != reply) {
     824               0 :       fprintf(stderr, "%s\n", &reply);
     825               0 :       fprintf(stderr, "Reply not correct\n");
     826               0 :       exit(1);
     827                 :     }
     828                 :   }
     829                 : 
     830                 :   /*
     831                 :    * Make sure all the file buffers are flushed before entering
     832                 :    * the application code.
     833                 :    */
     834              11 :   fflush((FILE *) NULL);
     835                 : 
     836              11 :   if (NULL != nap->secure_service) {
     837                 :     NaClErrorCode start_result;
     838                 :     /*
     839                 :      * wait for start_module RPC call on secure channel thread.
     840                 :      */
     841               0 :     start_result = NaClWaitForStartModuleCommand(nap);
     842               0 :     NaClPerfCounterMark(&time_all_main, "WaitedForStartModuleCommand");
     843               0 :     NaClPerfCounterIntervalLast(&time_all_main);
     844               0 :     if (LOAD_OK == errcode) {
     845               0 :       errcode = start_result;
     846                 :     }
     847                 :   }
     848                 : 
     849                 :   /*
     850                 :    * error reporting done; can quit now if there was an error earlier.
     851                 :    */
     852              11 :   if (LOAD_OK != errcode) {
     853               8 :     NaClLog(4,
     854                 :             "Not running app code since errcode is %s (%d)\n",
     855                 :             NaClErrorString(errcode),
     856                 :             errcode);
     857               8 :     goto done;
     858                 :   }
     859                 : 
     860               3 :   if (!DynArraySet(&env_vars, env_vars.num_entries, NULL)) {
     861               0 :     NaClLog(LOG_FATAL, "Adding env_vars NULL terminator failed\n");
     862                 :   }
     863                 : 
     864               3 :   NaClEnvCleanserCtor(&env_cleanser, 0);
     865               3 :   if (!NaClEnvCleanserInit(&env_cleanser, envp,
     866                 :           (char const *const *)env_vars.ptr_array)) {
     867               0 :     NaClLog(LOG_FATAL, "Failed to initialise env cleanser\n");
     868                 :   }
     869                 : 
     870               3 :   if (!NaClAppLaunchServiceThreads(nap)) {
     871               0 :     fprintf(stderr, "Launch service threads failed\n");
     872               0 :     goto done;
     873                 :   }
     874               3 :   if (!NaClCreateMainThread(nap,
     875                 :                             argc - optind,
     876                 :                             argv + optind,
     877                 :                             NaClEnvCleanserEnvironment(&env_cleanser))) {
     878               0 :     fprintf(stderr, "creating main thread failed\n");
     879               0 :     goto done;
     880                 :   }
     881                 : 
     882               3 :   NaClEnvCleanserDtor(&env_cleanser);
     883                 : 
     884               3 :   NaClPerfCounterMark(&time_all_main, "CreateMainThread");
     885               3 :   NaClPerfCounterIntervalLast(&time_all_main);
     886               3 :   DynArrayDtor(&env_vars);
     887                 : 
     888               3 :   ret_code = NaClWaitForMainThreadToExit(nap);
     889               3 :   NaClPerfCounterMark(&time_all_main, "WaitForMainThread");
     890               3 :   NaClPerfCounterIntervalLast(&time_all_main);
     891                 : 
     892               3 :   NaClPerfCounterMark(&time_all_main, "SelMainEnd");
     893               3 :   NaClPerfCounterIntervalTotal(&time_all_main);
     894                 : 
     895                 :   /*
     896                 :    * exit_group or equiv kills any still running threads while module
     897                 :    * addr space is still valid.  otherwise we'd have to kill threads
     898                 :    * before we clean up the address space.
     899                 :    */
     900               3 :   NaClExit(ret_code);
     901                 : 
     902               8 :  done:
     903               8 :   fflush(stdout);
     904                 : 
     905               8 :   if (verbosity) {
     906               0 :     gprintf((struct Gio *) &gout, "exiting -- printing NaClApp details\n");
     907               0 :     NaClAppPrintDetails(nap, (struct Gio *) &gout);
     908                 : 
     909               0 :     printf("Dumping vmmap.\n"); fflush(stdout);
     910               0 :     PrintVmmap(nap);
     911               0 :     fflush(stdout);
     912                 :   }
     913                 :   /*
     914                 :    * If there is a secure command channel, we sent an RPC reply with
     915                 :    * the reason that the nexe was rejected.  If we exit now, that
     916                 :    * reply may still be in-flight and the various channel closure (esp
     917                 :    * reverse channel) may be detected first.  This would result in a
     918                 :    * crash being reported, rather than the error in the RPC reply.
     919                 :    * Instead, we wait for the hard-shutdown on the command channel.
     920                 :    */
     921               8 :   if (LOAD_OK != errcode) {
     922               8 :     NaClBlockIfCommandChannelExists(nap);
     923                 :   }
     924                 : 
     925               8 :  done_file_dtor:
     926               8 :   if (verbosity > 0) {
     927               0 :     printf("Done.\n");
     928                 :   }
     929               8 :   fflush(stdout);
     930                 : 
     931               8 :   if (handle_signals) NaClSignalHandlerFini();
     932               8 :   NaClAllModulesFini();
     933                 : 
     934               8 :   NaClExit(ret_code);
     935                 : 
     936                 :   /* Unreachable, but having the return prevents a compiler error. */
     937               0 :   return ret_code;
     938                 : }

Generated by: LCOV version 1.7