LCOV - code coverage report
Current view: directory - src/trusted/service_runtime - sel_main_chrome.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 163 116 71.2 %
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                 : #include "native_client/src/public/chrome_main.h"
       8                 : 
       9                 : #include "native_client/src/include/portability.h"
      10                 : #include "native_client/src/include/portability_io.h"
      11                 : #include "native_client/src/include/portability_sockets.h"
      12                 : 
      13                 : #if NACL_OSX
      14                 : #include <crt_externs.h>
      15                 : #endif
      16                 : 
      17                 : #include <stdio.h>
      18                 : #include <string.h>
      19                 : 
      20                 : #include "native_client/src/include/nacl_macros.h"
      21                 : #include "native_client/src/public/nacl_app.h"
      22                 : #include "native_client/src/shared/platform/nacl_check.h"
      23                 : #include "native_client/src/shared/platform/nacl_exit.h"
      24                 : #include "native_client/src/shared/platform/nacl_log.h"
      25                 : #include "native_client/src/shared/platform/nacl_secure_random.h"
      26                 : #include "native_client/src/shared/platform/nacl_sync.h"
      27                 : #include "native_client/src/shared/platform/nacl_sync_checked.h"
      28                 : #include "native_client/src/trusted/desc/nacl_desc_io.h"
      29                 : #include "native_client/src/trusted/fault_injection/fault_injection.h"
      30                 : #include "native_client/src/trusted/gio/gio_nacl_desc.h"
      31                 : #include "native_client/src/trusted/service_runtime/env_cleanser.h"
      32                 : #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
      33                 : #include "native_client/src/trusted/service_runtime/nacl_all_modules.h"
      34                 : #include "native_client/src/trusted/service_runtime/nacl_app.h"
      35                 : #include "native_client/src/trusted/service_runtime/nacl_bootstrap_channel_error_reporter.h"
      36                 : #include "native_client/src/trusted/service_runtime/nacl_error_log_hook.h"
      37                 : #include "native_client/src/trusted/service_runtime/nacl_globals.h"
      38                 : #include "native_client/src/trusted/service_runtime/nacl_debug_init.h"
      39                 : #include "native_client/src/trusted/service_runtime/nacl_signal.h"
      40                 : #include "native_client/src/trusted/service_runtime/osx/mach_exception_handler.h"
      41                 : #include "native_client/src/trusted/service_runtime/sel_addrspace.h"
      42                 : #include "native_client/src/trusted/service_runtime/sel_ldr.h"
      43                 : #include "native_client/src/trusted/service_runtime/sel_qualify.h"
      44                 : #include "native_client/src/trusted/service_runtime/win/exception_patch/ntdll_patch.h"
      45                 : #include "native_client/src/trusted/validator/validation_metadata.h"
      46                 : 
      47                 : static int g_initialized = 0;
      48                 : 
      49                 : #if NACL_LINUX || NACL_OSX
      50               0 : void NaClChromeMainSetUrandomFd(int urandom_fd) {
      51               0 :   CHECK(!g_initialized);
      52               0 :   NaClSecureRngModuleSetUrandomFd(urandom_fd);
      53               0 : }
      54                 : #endif
      55                 : 
      56                 : void NaClChromeMainInit(void) {
      57              12 :   CHECK(!g_initialized);
      58               4 :   NaClAllModulesInit();
      59               4 :   g_initialized = 1;
      60               4 : }
      61                 : 
      62                 : struct NaClChromeMainArgs *NaClChromeMainArgsCreate(void) {
      63               4 :   struct NaClChromeMainArgs *args;
      64                 : 
      65              12 :   CHECK(g_initialized);
      66               4 :   args = malloc(sizeof(*args));
      67               4 :   if (args == NULL)
      68               0 :     return NULL;
      69               4 :   args->imc_bootstrap_handle = NACL_INVALID_HANDLE;
      70               4 :   args->irt_fd = -1;
      71               4 :   args->enable_exception_handling = 0;
      72               4 :   args->enable_debug_stub = 0;
      73               4 :   args->enable_dyncode_syscalls = 1;
      74               4 :   args->pnacl_mode = 0;
      75               4 :   args->initial_nexe_max_code_bytes = 0;  /* No limit */
      76                 : #if NACL_LINUX || NACL_OSX
      77               4 :   args->debug_stub_server_bound_socket_fd = NACL_INVALID_SOCKET;
      78                 : #endif
      79                 : #if NACL_WINDOWS
      80                 :   args->debug_stub_server_port_selected_handler_func = NULL;
      81                 : #endif
      82               4 :   args->create_memory_object_func = NULL;
      83               4 :   args->validation_cache = NULL;
      84                 : #if NACL_WINDOWS
      85                 :   args->broker_duplicate_handle_func = NULL;
      86                 :   args->attach_debug_exception_handler_func = NULL;
      87                 : #endif
      88                 : #if NACL_LINUX || NACL_OSX
      89               4 :   args->number_of_cores = -1;  /* unknown */
      90                 : #endif
      91                 : #if NACL_LINUX
      92                 :   args->prereserved_sandbox_size = 0;
      93                 : #endif
      94               4 :   args->nexe_desc = NULL;
      95               4 :   return args;
      96               4 : }
      97                 : 
      98                 : static char kFakeIrtName[] = "\0IRT";
      99                 : 
     100               4 : static void NaClLoadIrt(struct NaClApp *nap, int irt_fd) {
     101               4 :   int file_desc;
     102               4 :   struct NaClDesc *nd;
     103               4 :   struct NaClValidationMetadata metadata;
     104               4 :   NaClErrorCode errcode;
     105                 : 
     106               4 :   if (irt_fd == -1) {
     107               0 :     NaClLog(LOG_FATAL, "NaClLoadIrt: Integrated runtime (IRT) not present.\n");
     108               0 :   }
     109                 : 
     110               4 :   file_desc = DUP(irt_fd);
     111               4 :   if (file_desc < 0) {
     112               0 :     NaClLog(LOG_FATAL, "NaClLoadIrt: Failed to dup() file descriptor\n");
     113               0 :   }
     114                 : 
     115                 :   /*
     116                 :    * For the IRT use a fake file name with null characters at the begining and
     117                 :    * the end of the name.
     118                 :    */
     119                 :   /* TODO(ncbray) plumb the real filename in from Chrome. */
     120               4 :   NaClMetadataFromFDCtor(&metadata, file_desc,
     121                 :                          kFakeIrtName, sizeof(kFakeIrtName));
     122                 : 
     123               4 :   nd = NaClDescIoDescFromDescAllocCtor(file_desc, NACL_ABI_O_RDONLY);
     124               4 :   if (NULL == nd) {
     125               0 :     NaClLog(LOG_FATAL,
     126                 :             "NaClLoadIrt: failed to construct NaClDesc object from"
     127                 :             " descriptor\n");
     128               0 :   }
     129                 : 
     130               4 :   errcode = NaClAppLoadFileDynamically(nap, nd, &metadata);
     131               4 :   if (errcode != LOAD_OK) {
     132               0 :     NaClLog(LOG_FATAL,
     133                 :             "NaClLoadIrt: Failed to load the integrated runtime (IRT): %s\n",
     134               0 :             NaClErrorString(errcode));
     135               0 :   }
     136                 : 
     137              12 :   CHECK(NULL == nap->irt_nexe_desc);
     138               4 :   nap->irt_nexe_desc = nd;
     139               4 :   NaClMetadataDtor(&metadata);
     140               4 : }
     141                 : 
     142               4 : int NaClChromeMainLoad(struct NaClApp *nap,
     143               4 :                        struct NaClChromeMainArgs *args) {
     144               4 :   NaClErrorCode errcode = LOAD_OK;
     145               4 :   int skip_qualification;
     146                 : 
     147              12 :   CHECK(g_initialized);
     148                 : 
     149               4 :   NaClBootstrapChannelErrorReporterInit();
     150               4 :   NaClErrorLogHookInit(NaClBootstrapChannelErrorReporter, nap);
     151                 : 
     152                 :   /* Allow or disallow dyncode API based on args. */
     153               4 :   nap->enable_dyncode_syscalls = args->enable_dyncode_syscalls;
     154               4 :   nap->initial_nexe_max_code_bytes = args->initial_nexe_max_code_bytes;
     155               4 :   nap->pnacl_mode = args->pnacl_mode;
     156                 : 
     157                 : #if NACL_LINUX
     158                 :   g_prereserved_sandbox_size = args->prereserved_sandbox_size;
     159                 : #endif
     160                 : #if NACL_LINUX || NACL_OSX
     161                 :   /*
     162                 :    * Overwrite value of sc_nprocessors_onln set in NaClAppCtor.  In
     163                 :    * the Chrome embedding, the outer sandbox was already enabled when
     164                 :    * the NaClApp Ctor was invoked, so a bogus value was written in
     165                 :    * sc_nprocessors_onln.
     166                 :    */
     167               4 :   if (-1 != args->number_of_cores) {
     168               0 :     nap->sc_nprocessors_onln = args->number_of_cores;
     169               0 :   }
     170                 : #endif
     171                 : 
     172               4 :   if (args->create_memory_object_func != NULL)
     173               0 :     NaClSetCreateMemoryObjectFunc(args->create_memory_object_func);
     174                 : 
     175                 :   /* Inject the validation caching interface, if it exists. */
     176               4 :   nap->validation_cache = args->validation_cache;
     177                 : 
     178                 : #if NACL_WINDOWS
     179                 :   if (args->broker_duplicate_handle_func != NULL)
     180                 :     NaClSetBrokerDuplicateHandleFunc(args->broker_duplicate_handle_func);
     181                 : #endif
     182                 : 
     183               4 :   NaClAppInitialDescriptorHookup(nap);
     184                 : 
     185                 :   /*
     186                 :    * NACL_SERVICE_PORT_DESCRIPTOR and NACL_SERVICE_ADDRESS_DESCRIPTOR
     187                 :    * are 3 and 4.
     188                 :    */
     189                 : 
     190                 :   /*
     191                 :    * in order to report load error to the browser plugin through the
     192                 :    * secure command channel, we do not immediate jump to cleanup code
     193                 :    * on error.  rather, we continue processing (assuming earlier
     194                 :    * errors do not make it inappropriate) until the secure command
     195                 :    * channel is set up, and then bail out.
     196                 :    */
     197                 : 
     198                 :   /*
     199                 :    * Ensure this operating system platform is supported.
     200                 :    */
     201               4 :   skip_qualification = getenv("NACL_DANGEROUS_SKIP_QUALIFICATION_TEST") != NULL;
     202               4 :   if (skip_qualification) {
     203               0 :     fprintf(stderr, "PLATFORM QUALIFICATION DISABLED - "
     204                 :         "Native Client's sandbox will be unreliable!\n");
     205               0 :   } else {
     206              12 :     errcode = NACL_FI_VAL("pq", NaClErrorCode,
     207                 :                           NaClRunSelQualificationTests());
     208               4 :     if (LOAD_OK != errcode) {
     209               0 :       nap->module_load_status = errcode;
     210               0 :       fprintf(stderr, "Error while loading in SelMain: %s\n",
     211               0 :               NaClErrorString(errcode));
     212               0 :     }
     213                 :   }
     214                 : 
     215                 :   /*
     216                 :    * Patch the Windows exception dispatcher to be safe in the case
     217                 :    * of faults inside x86-64 sandboxed code.  The sandbox is not
     218                 :    * secure on 64-bit Windows without this.
     219                 :    */
     220                 : #if (NACL_WINDOWS && NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && \
     221                 :      NACL_BUILD_SUBARCH == 64)
     222                 :   NaClPatchWindowsExceptionDispatcher();
     223                 : #endif
     224               4 :   NaClSignalTestCrashOnStartup();
     225                 : 
     226               4 :   nap->enable_exception_handling = args->enable_exception_handling;
     227                 : 
     228               8 :   if (args->enable_exception_handling || args->enable_debug_stub) {
     229                 : #if NACL_LINUX
     230                 :     /* NaCl's signal handler is always enabled on Linux. */
     231                 : #elif NACL_OSX
     232               0 :     if (!NaClInterceptMachExceptions()) {
     233               0 :       NaClLog(LOG_FATAL, "NaClChromeMainLoad: "
     234                 :               "Failed to set up Mach exception handler\n");
     235               0 :     }
     236                 : #elif NACL_WINDOWS
     237                 :     nap->attach_debug_exception_handler_func =
     238                 :         args->attach_debug_exception_handler_func;
     239                 : #else
     240                 : # error Unknown host OS
     241                 : #endif
     242               0 :   }
     243                 : #if NACL_LINUX
     244                 :   NaClSignalHandlerInit();
     245                 : #endif
     246                 : 
     247                 :   /* Give debuggers a well known point at which xlate_base is known.  */
     248               4 :   NaClGdbHook(nap);
     249                 : 
     250               4 :   NaClCreateServiceSocket(nap);
     251                 :   /*
     252                 :    * LOG_FATAL errors that occur before NaClSetUpBootstrapChannel will
     253                 :    * not be reported via the crash log mechanism (for Chromium
     254                 :    * embedding of NaCl, shown in the JavaScript console).
     255                 :    *
     256                 :    * Some errors, such as due to NaClRunSelQualificationTests, do not
     257                 :    * trigger a LOG_FATAL but instead set module_load_status to be sent
     258                 :    * in the start_module RPC reply.  Log messages associated with such
     259                 :    * errors would be seen, since NaClSetUpBootstrapChannel will get
     260                 :    * called.
     261                 :    */
     262               4 :   NaClSetUpBootstrapChannel(nap, args->imc_bootstrap_handle);
     263                 : 
     264               4 :   if (args->nexe_desc) {
     265               2 :     NaClAppLoadModule(nap, args->nexe_desc, NULL, NULL);
     266               2 :     NaClDescUnref(args->nexe_desc);
     267               2 :     args->nexe_desc = NULL;
     268               2 :   }
     269                 : 
     270              16 :   NACL_FI_FATAL("BeforeSecureCommandChannel");
     271                 :   /*
     272                 :    * Spawns a thread that uses the command channel.
     273                 :    * Hereafter any changes to nap should be done while holding locks.
     274                 :    */
     275               4 :   NaClSecureCommandChannel(nap);
     276                 : 
     277               4 :   NaClLog(4, "NaClSecureCommandChannel has spawned channel\n");
     278                 : 
     279               4 :   NaClLog(4, "secure service = %"NACL_PRIxPTR"\n",
     280                 :           (uintptr_t) nap->secure_service);
     281              16 :   NACL_FI_FATAL("BeforeWaitForStartModule");
     282                 : 
     283               4 :   if (NULL != nap->secure_service) {
     284               4 :     NaClErrorCode start_result;
     285                 :     /*
     286                 :      * wait for start_module RPC call on secure channel thread.
     287                 :      */
     288               4 :     start_result = NaClWaitForStartModuleCommand(nap);
     289               4 :     if (LOAD_OK == errcode) {
     290               4 :       errcode = start_result;
     291               4 :     }
     292               4 :   }
     293                 : 
     294              16 :   NACL_FI_FATAL("BeforeLoadIrt");
     295                 : 
     296                 :   /*
     297                 :    * error reporting done; can quit now if there was an error earlier.
     298                 :    */
     299               4 :   if (LOAD_OK != errcode) {
     300               0 :     goto done;
     301                 :   }
     302                 : 
     303                 :   /*
     304                 :    * Load the integrated runtime (IRT) library.
     305                 :    */
     306               8 :   if (args->irt_fd != -1 && !nap->irt_loaded) {
     307               4 :     NaClLoadIrt(nap, args->irt_fd);
     308               4 :     nap->irt_loaded = 1;
     309               4 :   }
     310                 : 
     311               8 :   if (NACL_FI_ERROR_COND("LaunchServiceThreads",
     312                 :                          !NaClAppLaunchServiceThreads(nap))) {
     313               0 :     NaClLog(LOG_FATAL, "Launch service threads failed\n");
     314               0 :   }
     315                 : 
     316               4 :   if (args->enable_debug_stub) {
     317                 : #if NACL_LINUX || NACL_OSX
     318               0 :     if (args->debug_stub_server_bound_socket_fd != NACL_INVALID_SOCKET) {
     319               0 :       NaClDebugSetBoundSocket(args->debug_stub_server_bound_socket_fd);
     320               0 :     }
     321                 : #endif
     322               0 :     if (!NaClDebugInit(nap)) {
     323               0 :       goto done;
     324                 :     }
     325                 : #if NACL_WINDOWS
     326                 :     if (NULL != args->debug_stub_server_port_selected_handler_func) {
     327                 :       args->debug_stub_server_port_selected_handler_func(nap->debug_stub_port);
     328                 :     }
     329                 : #endif
     330               0 :   }
     331                 : 
     332               4 :   free(args);
     333               4 :   return LOAD_OK;
     334                 : 
     335                 : done:
     336               0 :   fflush(stdout);
     337                 : 
     338                 :   /*
     339                 :    * If there is a secure command channel, we sent an RPC reply with
     340                 :    * the reason that the nexe was rejected.  If we exit now, that
     341                 :    * reply may still be in-flight and the various channel closure (esp
     342                 :    * reverse channel) may be detected first.  This would result in a
     343                 :    * crash being reported, rather than the error in the RPC reply.
     344                 :    * Instead, we wait for the hard-shutdown on the command channel.
     345                 :    */
     346               0 :   if (LOAD_OK != errcode) {
     347               0 :     NaClBlockIfCommandChannelExists(nap);
     348               0 :   } else {
     349                 :     /*
     350                 :      * Don't return LOAD_OK if we had some failure loading.
     351                 :      */
     352               0 :     errcode = LOAD_INTERNAL;
     353                 :   }
     354               0 :   return errcode;
     355               4 : }
     356                 : 
     357               4 : void NaClChromeMainStart(struct NaClApp *nap) {
     358               4 :   int ac = 1;
     359               4 :   char *av[1];
     360               4 :   int ret_code;
     361               4 :   const char **envp;
     362               4 :   struct NaClEnvCleanser env_cleanser;
     363                 : 
     364                 : #if NACL_OSX
     365                 :   /* Mac dynamic libraries cannot access the environ variable directly. */
     366               4 :   envp = (const char **) *_NSGetEnviron();
     367                 : #else
     368                 :   /* Overzealous code style check is overzealous. */
     369                 :   /* @IGNORE_LINES_FOR_CODE_HYGIENE[1] */
     370                 :   extern char **environ;
     371                 :   envp = (const char **) environ;
     372                 : #endif
     373                 : 
     374              16 :   NACL_FI_FATAL("BeforeEnvCleanserCtor");
     375                 : 
     376               4 :   NaClEnvCleanserCtor(&env_cleanser, 1);
     377               4 :   if (!NaClEnvCleanserInit(&env_cleanser, envp, NULL)) {
     378               0 :     NaClLog(LOG_FATAL, "Failed to initialise env cleanser\n");
     379               0 :   }
     380                 : 
     381                 :   /* to be passed to NaClMain, eventually... */
     382               4 :   av[0] = "NaClMain";
     383                 : 
     384               8 :   if (NACL_FI_ERROR_COND(
     385                 :           "CreateMainThread",
     386                 :           !NaClCreateMainThread(nap, ac, av,
     387                 :                                 NaClEnvCleanserEnvironment(&env_cleanser)))) {
     388               0 :     NaClLog(LOG_FATAL, "creating main thread failed\n");
     389               0 :   }
     390              16 :   NACL_FI_FATAL("BeforeEnvCleanserDtor");
     391                 : 
     392               4 :   NaClEnvCleanserDtor(&env_cleanser);
     393                 : 
     394               4 :   ret_code = NaClWaitForMainThreadToExit(nap);
     395                 : 
     396               4 :   if (NACL_ABI_WIFEXITED(nap->exit_status)) {
     397                 :     /*
     398                 :      * Under Chrome, a call to _exit() often indicates that something
     399                 :      * has gone awry, so we report it here to aid debugging.
     400                 :      *
     401                 :      * This conditional does not run if the NaCl process was
     402                 :      * terminated forcibly, which is the normal case under Chrome.
     403                 :      * This forcible exit is triggered by the renderer closing the
     404                 :      * trusted SRPC channel, which we record as NACL_ABI_SIGKILL
     405                 :      * internally.
     406                 :      */
     407               4 :     NaClLog(LOG_INFO, "NaCl untrusted code called _exit(0x%x)\n", ret_code);
     408               4 :   }
     409                 : 
     410                 :   /*
     411                 :    * exit_group or equiv kills any still running threads while module
     412                 :    * addr space is still valid.  otherwise we'd have to kill threads
     413                 :    * before we clean up the address space.
     414                 :    */
     415               4 :   NaClExit(ret_code);
     416               4 : }
     417                 : 
     418               4 : void NaClChromeMainStartApp(struct NaClApp *nap,
     419               4 :                             struct NaClChromeMainArgs *args) {
     420               4 :   if (NaClChromeMainLoad(nap, args) != 0)
     421               0 :     NaClExit(1);
     422               4 :   NaClChromeMainStart(nap);
     423               4 : }

Generated by: LCOV version 1.7