LCOV - code coverage report
Current view: directory - src/trusted/service_runtime - sel_ldr_standard.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 414 356 86.0 %
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                 : 
      11                 : #include "native_client/src/include/portability.h"
      12                 : 
      13                 : #include <stdio.h>
      14                 : #include <stdlib.h>
      15                 : #include <string.h>
      16                 : 
      17                 : #include "native_client/src/include/elf_constants.h"
      18                 : #include "native_client/src/include/elf.h"
      19                 : #include "native_client/src/include/nacl_macros.h"
      20                 : #include "native_client/src/include/win/mman.h"
      21                 : #include "native_client/src/shared/platform/nacl_check.h"
      22                 : #include "native_client/src/shared/platform/nacl_log.h"
      23                 : #include "native_client/src/shared/platform/nacl_sync_checked.h"
      24                 : #include "native_client/src/shared/platform/nacl_time.h"
      25                 : 
      26                 : #include "native_client/src/shared/srpc/nacl_srpc.h"
      27                 : 
      28                 : #include "native_client/src/trusted/perf_counter/nacl_perf_counter.h"
      29                 : 
      30                 : #include "native_client/src/trusted/reverse_service/reverse_control_rpc.h"
      31                 : 
      32                 : #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
      33                 : #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
      34                 : 
      35                 : #include "native_client/src/trusted/service_runtime/arch/sel_ldr_arch.h"
      36                 : #include "native_client/src/trusted/service_runtime/elf_util.h"
      37                 : #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
      38                 : #include "native_client/src/trusted/service_runtime/nacl_kernel_service.h"
      39                 : #include "native_client/src/trusted/service_runtime/nacl_runtime_host_interface.h"
      40                 : #include "native_client/src/trusted/service_runtime/nacl_signal.h"
      41                 : #include "native_client/src/trusted/service_runtime/nacl_switch_to_app.h"
      42                 : #include "native_client/src/trusted/service_runtime/nacl_syscall_common.h"
      43                 : #include "native_client/src/trusted/service_runtime/nacl_text.h"
      44                 : #include "native_client/src/trusted/service_runtime/sel_memory.h"
      45                 : #include "native_client/src/trusted/service_runtime/sel_ldr.h"
      46                 : #include "native_client/src/trusted/service_runtime/sel_ldr_thread_interface.h"
      47                 : #include "native_client/src/trusted/service_runtime/sel_util.h"
      48                 : #include "native_client/src/trusted/service_runtime/sel_addrspace.h"
      49                 : 
      50                 : #if !defined(SIZE_T_MAX)
      51                 : # define SIZE_T_MAX     (~(size_t) 0)
      52                 : #endif
      53                 : 
      54                 : 
      55                 : /*
      56                 :  * Fill from static_text_end to end of that page with halt
      57                 :  * instruction, which is at least NACL_HALT_LEN in size when no
      58                 :  * dynamic text is present.  Does not touch dynamic text region, which
      59                 :  * should be pre-filled with HLTs.
      60                 :  *
      61                 :  * By adding NACL_HALT_SLED_SIZE, we ensure that the code region ends
      62                 :  * with HLTs, just in case the CPU has a bug in which it fails to
      63                 :  * check for running off the end of the x86 code segment.
      64                 :  */
      65             268 : void NaClFillEndOfTextRegion(struct NaClApp *nap) {
      66             268 :   size_t page_pad;
      67                 : 
      68                 :   /*
      69                 :    * NOTE: make sure we are not silently overwriting data.  It is the
      70                 :    * toolchain's responsibility to ensure that a NACL_HALT_SLED_SIZE
      71                 :    * gap exists.
      72                 :    */
      73             520 :   if (0 != nap->data_start &&
      74                 :       nap->static_text_end + NACL_HALT_SLED_SIZE >
      75             252 :       NaClTruncAllocPage(nap->data_start)) {
      76               0 :     NaClLog(LOG_FATAL, "Missing gap between text and data for halt_sled\n");
      77               0 :   }
      78             532 :   if (0 != nap->rodata_start &&
      79                 :       nap->static_text_end + NACL_HALT_SLED_SIZE > nap->rodata_start) {
      80               2 :     NaClLog(LOG_FATAL, "Missing gap between text and rodata for halt_sled\n");
      81               2 :   }
      82                 : 
      83             266 :   if (NULL == nap->text_shm) {
      84                 :     /*
      85                 :      * No dynamic text exists.  Space for NACL_HALT_SLED_SIZE must
      86                 :      * exist.
      87                 :      */
      88               6 :     page_pad = (NaClRoundAllocPage(nap->static_text_end + NACL_HALT_SLED_SIZE)
      89                 :                 - nap->static_text_end);
      90              18 :     CHECK(page_pad >= NACL_HALT_SLED_SIZE);
      91              18 :     CHECK(page_pad < NACL_MAP_PAGESIZE + NACL_HALT_SLED_SIZE);
      92               6 :   } else {
      93                 :     /*
      94                 :      * Dynamic text exists; the halt sled resides in the dynamic text
      95                 :      * region, so all we need to do here is to round out the last
      96                 :      * static text page with HLT instructions.  It doesn't matter if
      97                 :      * the size of this region is smaller than NACL_HALT_SLED_SIZE --
      98                 :      * this is just to fully initialize the page, rather than (later)
      99                 :      * decoding/validating zero-filled memory as instructions.
     100                 :      */
     101             260 :     page_pad = NaClRoundAllocPage(nap->static_text_end) - nap->static_text_end;
     102                 :   }
     103                 : 
     104             266 :   NaClLog(4,
     105                 :           "Filling with halts: %08"NACL_PRIxPTR", %08"NACL_PRIxS" bytes\n",
     106                 :           nap->mem_start + nap->static_text_end,
     107                 :           page_pad);
     108                 : 
     109             266 :   NaClFillMemoryRegionWithHalt((void *)(nap->mem_start + nap->static_text_end),
     110                 :                                page_pad);
     111                 : 
     112             266 :   nap->static_text_end += page_pad;
     113             266 : }
     114                 : 
     115                 : /*
     116                 :  * Basic address space layout sanity check.
     117                 :  */
     118             271 : NaClErrorCode NaClCheckAddressSpaceLayoutSanity(struct NaClApp *nap,
     119             271 :                                                 uintptr_t rodata_end,
     120             271 :                                                 uintptr_t data_end,
     121             271 :                                                 uintptr_t max_vaddr) {
     122             271 :   if (0 != nap->data_start) {
     123             255 :     if (data_end != max_vaddr) {
     124               1 :       NaClLog(LOG_INFO, "data segment is not last\n");
     125               1 :       return LOAD_DATA_NOT_LAST_SEGMENT;
     126                 :     }
     127             270 :   } else if (0 != nap->rodata_start) {
     128              12 :     if (NaClRoundAllocPage(rodata_end) != max_vaddr) {
     129                 :       /*
     130                 :        * This should be unreachable, but we include it just for
     131                 :        * completeness.
     132                 :        *
     133                 :        * Here is why it is unreachable:
     134                 :        *
     135                 :        * NaClPhdrChecks checks the test segment starting address.  The
     136                 :        * only allowed loaded segments are text, data, and rodata.
     137                 :        * Thus unless the rodata is in the trampoline region, it must
     138                 :        * be after the text.  And NaClElfImageValidateProgramHeaders
     139                 :        * ensures that all segments start after the trampoline region.
     140                 :        */
     141               0 :       NaClLog(LOG_INFO, "no data segment, but rodata segment is not last\n");
     142               0 :       return LOAD_NO_DATA_BUT_RODATA_NOT_LAST_SEGMENT;
     143                 :     }
     144              12 :   }
     145             536 :   if (0 != nap->rodata_start && 0 != nap->data_start) {
     146             254 :     if (rodata_end > NaClTruncAllocPage(nap->data_start)) {
     147               1 :       NaClLog(LOG_INFO, "rodata_overlaps data.\n");
     148               1 :       return LOAD_RODATA_OVERLAPS_DATA;
     149                 :     }
     150             253 :   }
     151             269 :   if (0 != nap->rodata_start) {
     152             265 :     if (NaClRoundAllocPage(NaClEndOfStaticText(nap)) > nap->rodata_start) {
     153               0 :       return LOAD_TEXT_OVERLAPS_RODATA;
     154                 :     }
     155             269 :   } else if (0 != nap->data_start) {
     156               0 :     if (NaClRoundAllocPage(NaClEndOfStaticText(nap)) >
     157               0 :         NaClTruncAllocPage(nap->data_start)) {
     158               0 :       return LOAD_TEXT_OVERLAPS_DATA;
     159                 :     }
     160               0 :   }
     161             269 :   if (0 != nap->rodata_start &&
     162             265 :       NaClRoundAllocPage(nap->rodata_start) != nap->rodata_start) {
     163               0 :     NaClLog(LOG_INFO, "rodata_start not a multiple of allocation size\n");
     164               0 :     return LOAD_BAD_RODATA_ALIGNMENT;
     165                 :   }
     166                 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_mips
     167                 :   /*
     168                 :    * This check is necessary to make MIPS sandbox secure, as there is no NX page
     169                 :    * protection support on MIPS.
     170                 :    */
     171                 :   if (nap->rodata_start < NACL_DATA_SEGMENT_START) {
     172                 :     NaClLog(LOG_INFO,
     173                 :             "rodata_start is below NACL_DATA_SEGMENT_START (0x%X) address\n",
     174                 :             NACL_DATA_SEGMENT_START);
     175                 :     return LOAD_SEGMENT_BAD_LOC;
     176                 :   }
     177                 : #endif
     178             269 :   return LOAD_OK;
     179             271 : }
     180                 : 
     181             536 : void NaClLogAddressSpaceLayout(struct NaClApp *nap) {
     182             536 :   NaClLog(2, "NaClApp addr space layout:\n");
     183             536 :   NaClLog(2, "nap->static_text_end    = 0x%016"NACL_PRIxPTR"\n",
     184                 :           nap->static_text_end);
     185             536 :   NaClLog(2, "nap->dynamic_text_start = 0x%016"NACL_PRIxPTR"\n",
     186                 :           nap->dynamic_text_start);
     187             536 :   NaClLog(2, "nap->dynamic_text_end   = 0x%016"NACL_PRIxPTR"\n",
     188                 :           nap->dynamic_text_end);
     189             536 :   NaClLog(2, "nap->rodata_start       = 0x%016"NACL_PRIxPTR"\n",
     190                 :           nap->rodata_start);
     191             536 :   NaClLog(2, "nap->data_start         = 0x%016"NACL_PRIxPTR"\n",
     192                 :           nap->data_start);
     193             536 :   NaClLog(2, "nap->data_end           = 0x%016"NACL_PRIxPTR"\n",
     194                 :           nap->data_end);
     195             536 :   NaClLog(2, "nap->break_addr         = 0x%016"NACL_PRIxPTR"\n",
     196                 :           nap->break_addr);
     197             536 :   NaClLog(2, "nap->initial_entry_pt   = 0x%016"NACL_PRIxPTR"\n",
     198                 :           nap->initial_entry_pt);
     199             536 :   NaClLog(2, "nap->user_entry_pt      = 0x%016"NACL_PRIxPTR"\n",
     200                 :           nap->user_entry_pt);
     201             536 :   NaClLog(2, "nap->bundle_size        = 0x%x\n", nap->bundle_size);
     202             536 : }
     203                 : 
     204                 : 
     205             273 : NaClErrorCode NaClAppLoadFileAslr(struct NaClDesc *ndp,
     206             273 :                                   struct NaClApp *nap,
     207             273 :                                   enum NaClAslrMode aslr_mode) {
     208             273 :   NaClErrorCode       ret = LOAD_INTERNAL;
     209             273 :   NaClErrorCode       subret = LOAD_INTERNAL;
     210             273 :   uintptr_t           rodata_end;
     211             273 :   uintptr_t           data_end;
     212             273 :   uintptr_t           max_vaddr;
     213             273 :   struct NaClElfImage *image = NULL;
     214             273 :   struct NaClPerfCounter  time_load_file;
     215             273 :   struct NaClElfImageInfo info;
     216                 : 
     217             273 :   NaClPerfCounterCtor(&time_load_file, "NaClAppLoadFile");
     218                 : 
     219                 :   /* NACL_MAX_ADDR_BITS < 32 */
     220             273 :   if (nap->addr_bits > NACL_MAX_ADDR_BITS) {
     221               0 :     ret = LOAD_ADDR_SPACE_TOO_BIG;
     222               0 :     goto done;
     223                 :   }
     224                 : 
     225             273 :   nap->stack_size = NaClRoundAllocPage(nap->stack_size);
     226                 : 
     227                 :   /* temporay object will be deleted at end of function */
     228             273 :   image = NaClElfImageNew(ndp, &subret);
     229             544 :   if (NULL == image || LOAD_OK != subret) {
     230               2 :     ret = subret;
     231               2 :     goto done;
     232                 :   }
     233                 : 
     234             271 :   subret = NaClElfImageValidateProgramHeaders(image,
     235                 :                                               nap->addr_bits,
     236                 :                                               &info);
     237             271 :   if (LOAD_OK != subret) {
     238               0 :     ret = subret;
     239               0 :     goto done;
     240                 :   }
     241                 : 
     242             271 :   if (nap->initial_nexe_max_code_bytes != 0) {
     243               0 :     size_t code_segment_size = info.static_text_end - NACL_TRAMPOLINE_END;
     244               0 :     if (code_segment_size > nap->initial_nexe_max_code_bytes) {
     245               0 :       NaClLog(LOG_ERROR, "NaClAppLoadFileAslr: "
     246                 :               "Code segment size (%"NACL_PRIuS" bytes) exceeds limit (%"
     247                 :               NACL_PRId32" bytes)\n",
     248                 :               code_segment_size, nap->initial_nexe_max_code_bytes);
     249               0 :       ret = LOAD_CODE_SEGMENT_TOO_LARGE;
     250               0 :       goto done;
     251                 :     }
     252               0 :   }
     253                 : 
     254             271 :   nap->static_text_end = info.static_text_end;
     255             271 :   nap->rodata_start = info.rodata_start;
     256             271 :   rodata_end = info.rodata_end;
     257             271 :   nap->data_start = info.data_start;
     258             271 :   data_end = info.data_end;
     259             271 :   max_vaddr = info.max_vaddr;
     260                 : 
     261             271 :   if (0 == nap->data_start) {
     262              16 :     if (0 == nap->rodata_start) {
     263               4 :       if (NaClRoundAllocPage(max_vaddr) - max_vaddr < NACL_HALT_SLED_SIZE) {
     264                 :         /*
     265                 :          * if no rodata and no data, we make sure that there is space for
     266                 :          * the halt sled.
     267                 :          */
     268               4 :         max_vaddr += NACL_MAP_PAGESIZE;
     269               4 :       }
     270               4 :     } else {
     271                 :       /*
     272                 :        * no data, but there is rodata.  this means max_vaddr is just
     273                 :        * where rodata ends.  this might not be at an allocation
     274                 :        * boundary, and in this the page would not be writable.  round
     275                 :        * max_vaddr up to the next allocation boundary so that bss will
     276                 :        * be at the next writable region.
     277                 :        */
     278                 :       ;
     279                 :     }
     280              16 :     max_vaddr = NaClRoundAllocPage(max_vaddr);
     281              16 :   }
     282                 :   /*
     283                 :    * max_vaddr -- the break or the boundary between data (initialized
     284                 :    * and bss) and the address space hole -- does not have to be at a
     285                 :    * page boundary.
     286                 :    *
     287                 :    * Memory allocation will use NaClRoundPage(nap->break_addr), but
     288                 :    * the system notion of break is always an exact address.  Even
     289                 :    * though we must allocate and make accessible multiples of pages,
     290                 :    * the linux-style brk system call (which returns current break on
     291                 :    * failure) permits a non-aligned address as argument.
     292                 :    */
     293             271 :   nap->break_addr = max_vaddr;
     294             271 :   nap->data_end = max_vaddr;
     295                 : 
     296             271 :   NaClLog(4, "Values from NaClElfImageValidateProgramHeaders:\n");
     297             271 :   NaClLog(4, "rodata_start = 0x%08"NACL_PRIxPTR"\n", nap->rodata_start);
     298             271 :   NaClLog(4, "rodata_end   = 0x%08"NACL_PRIxPTR"\n", rodata_end);
     299             271 :   NaClLog(4, "data_start   = 0x%08"NACL_PRIxPTR"\n", nap->data_start);
     300             271 :   NaClLog(4, "data_end     = 0x%08"NACL_PRIxPTR"\n", data_end);
     301             271 :   NaClLog(4, "max_vaddr    = 0x%08"NACL_PRIxPTR"\n", max_vaddr);
     302                 : 
     303                 :   /* We now support only one bundle size.  */
     304             271 :   nap->bundle_size = NACL_INSTR_BLOCK_SIZE;
     305                 : 
     306             271 :   nap->initial_entry_pt = NaClElfImageGetEntryPoint(image);
     307             271 :   NaClLogAddressSpaceLayout(nap);
     308                 : 
     309             271 :   if (!NaClAddrIsValidEntryPt(nap, nap->initial_entry_pt)) {
     310               0 :     ret = LOAD_BAD_ENTRY;
     311               0 :     goto done;
     312                 :   }
     313                 : 
     314             271 :   subret = NaClCheckAddressSpaceLayoutSanity(nap, rodata_end, data_end,
     315                 :                                              max_vaddr);
     316             271 :   if (LOAD_OK != subret) {
     317               2 :     ret = subret;
     318               2 :     goto done;
     319                 :   }
     320                 : 
     321             269 :   NaClLog(2, "Allocating address space\n");
     322             269 :   NaClPerfCounterMark(&time_load_file, "PreAllocAddrSpace");
     323             269 :   NaClPerfCounterIntervalLast(&time_load_file);
     324             269 :   subret = NaClAllocAddrSpaceAslr(nap, aslr_mode);
     325             269 :   NaClPerfCounterMark(&time_load_file,
     326                 :                       NACL_PERF_IMPORTANT_PREFIX "AllocAddrSpace");
     327             269 :   NaClPerfCounterIntervalLast(&time_load_file);
     328             269 :   if (LOAD_OK != subret) {
     329               1 :     ret = subret;
     330               1 :     goto done;
     331                 :   }
     332                 : 
     333                 :   /*
     334                 :    * Make sure the static image pages are marked writable before we try
     335                 :    * to write them.
     336                 :    */
     337             268 :   NaClLog(2, "Loading into memory\n");
     338             536 :   ret = NaClMprotect((void *) (nap->mem_start + NACL_TRAMPOLINE_START),
     339             268 :                      NaClRoundAllocPage(nap->data_end) - NACL_TRAMPOLINE_START,
     340                 :                      PROT_READ | PROT_WRITE);
     341             268 :   if (0 != ret) {
     342               0 :     NaClLog(LOG_FATAL,
     343                 :             "NaClAppLoadFile: Failed to make image pages writable. "
     344                 :             "Error code 0x%x\n",
     345                 :             ret);
     346               0 :   }
     347             268 :   subret = NaClElfImageLoad(image, ndp, nap);
     348             268 :   NaClPerfCounterMark(&time_load_file,
     349                 :                       NACL_PERF_IMPORTANT_PREFIX "NaClElfImageLoad");
     350             268 :   NaClPerfCounterIntervalLast(&time_load_file);
     351             268 :   if (LOAD_OK != subret) {
     352               0 :     ret = subret;
     353               0 :     goto done;
     354                 :   }
     355                 : 
     356                 :   /*
     357                 :    * NB: mem_map object has been initialized, but is empty.
     358                 :    * NaClMakeDynamicTextShared does not touch it.
     359                 :    *
     360                 :    * NaClMakeDynamicTextShared also fills the dynamic memory region
     361                 :    * with the architecture-specific halt instruction.  If/when we use
     362                 :    * memory mapping to save paging space for the dynamic region and
     363                 :    * lazily halt fill the memory as the pages become
     364                 :    * readable/executable, we must make sure that the *last*
     365                 :    * NACL_MAP_PAGESIZE chunk is nonetheless mapped and written with
     366                 :    * halts.
     367                 :    */
     368             268 :   NaClLog(2,
     369                 :           ("Replacing gap between static text and"
     370                 :            " (ro)data with shareable memory\n"));
     371             268 :   subret = NaClMakeDynamicTextShared(nap);
     372             268 :   NaClPerfCounterMark(&time_load_file,
     373                 :                       NACL_PERF_IMPORTANT_PREFIX "MakeDynText");
     374             268 :   NaClPerfCounterIntervalLast(&time_load_file);
     375             268 :   if (LOAD_OK != subret) {
     376               0 :     ret = subret;
     377               0 :     goto done;
     378                 :   }
     379                 : 
     380                 :   /*
     381                 :    * NaClFillEndOfTextRegion will fill with halt instructions the
     382                 :    * padding space after the static text region.
     383                 :    *
     384                 :    * Shm-backed dynamic text space was filled with halt instructions
     385                 :    * in NaClMakeDynamicTextShared.  This extends to the rodata.  For
     386                 :    * non-shm-backed text space, this extend to the next page (and not
     387                 :    * allocation page).  static_text_end is updated to include the
     388                 :    * padding.
     389                 :    */
     390             266 :   NaClFillEndOfTextRegion(nap);
     391                 : 
     392             266 :   if (nap->main_exe_prevalidated) {
     393               3 :     NaClLog(2, "Main executable segment hit validation cache and mapped in,"
     394                 :             " skipping validation.\n");
     395               3 :     subret = LOAD_OK;
     396               3 :   } else {
     397             263 :     NaClLog(2, "Validating image\n");
     398             263 :     subret = NaClValidateImage(nap);
     399                 :   }
     400             266 :   NaClPerfCounterMark(&time_load_file,
     401                 :                       NACL_PERF_IMPORTANT_PREFIX "ValidateImg");
     402             266 :   NaClPerfCounterIntervalLast(&time_load_file);
     403             266 :   if (LOAD_OK != subret) {
     404               1 :     ret = subret;
     405               1 :     goto done;
     406                 :   }
     407                 : 
     408             265 :   NaClLog(2, "Initializing arch switcher\n");
     409             265 :   NaClInitSwitchToApp(nap);
     410                 : 
     411             265 :   NaClLog(2, "Installing trampoline\n");
     412             265 :   NaClLoadTrampoline(nap, aslr_mode);
     413                 : 
     414             265 :   NaClLog(2, "Installing springboard\n");
     415             265 :   NaClLoadSpringboard(nap);
     416                 : 
     417                 :   /*
     418                 :    * NaClMemoryProtection also initializes the mem_map w/ information
     419                 :    * about the memory pages and their current protection value.
     420                 :    *
     421                 :    * The contents of the dynamic text region will get remapped as
     422                 :    * non-writable.
     423                 :    */
     424             265 :   NaClLog(2, "Applying memory protection\n");
     425             265 :   subret = NaClMemoryProtection(nap);
     426             265 :   if (LOAD_OK != subret) {
     427               0 :     ret = subret;
     428               0 :     goto done;
     429                 :   }
     430                 : 
     431             265 :   NaClLog(2, "NaClAppLoadFile done; ");
     432             265 :   NaClLogAddressSpaceLayout(nap);
     433             265 :   ret = LOAD_OK;
     434                 : done:
     435             271 :   NaClElfImageDelete(image);
     436                 : 
     437             271 :   NaClPerfCounterMark(&time_load_file, "EndLoadFile");
     438             271 :   NaClPerfCounterIntervalTotal(&time_load_file);
     439             271 :   return ret;
     440                 : }
     441                 : 
     442             271 : NaClErrorCode NaClAppLoadFile(struct NaClDesc *ndp,
     443             271 :                               struct NaClApp *nap) {
     444             271 :   return NaClAppLoadFileAslr(ndp, nap, NACL_ENABLE_ASLR);
     445                 : }
     446                 : 
     447                 : NaClErrorCode NaClAppLoadFileDynamically(
     448               5 :     struct NaClApp *nap,
     449               5 :     struct NaClDesc *ndp,
     450               5 :     struct NaClValidationMetadata *metadata) {
     451               5 :   struct NaClElfImage *image = NULL;
     452               5 :   NaClErrorCode ret = LOAD_INTERNAL;
     453                 : 
     454               5 :   image = NaClElfImageNew(ndp, &ret);
     455              10 :   if (NULL == image || LOAD_OK != ret) {
     456               0 :     goto done;
     457                 :   }
     458               5 :   ret = NaClElfImageLoadDynamically(image, nap, ndp, metadata);
     459               5 :   if (LOAD_OK != ret) {
     460               0 :     goto done;
     461                 :   }
     462               5 :   nap->user_entry_pt = nap->initial_entry_pt;
     463               5 :   nap->initial_entry_pt = NaClElfImageGetEntryPoint(image);
     464                 : 
     465                 :  done:
     466               5 :   NaClElfImageDelete(image);
     467               5 :   return ret;
     468                 : }
     469                 : 
     470             271 : int NaClAddrIsValidEntryPt(struct NaClApp *nap,
     471             271 :                            uintptr_t      addr) {
     472             271 :   if (0 != (addr & (nap->bundle_size - 1))) {
     473               0 :     return 0;
     474                 :   }
     475                 : 
     476             271 :   return addr < nap->static_text_end;
     477             271 : }
     478                 : 
     479             255 : int NaClAppLaunchServiceThreads(struct NaClApp *nap) {
     480             255 :   struct NaClKernelService  *kernel_service = NULL;
     481             255 :   int                       rv = 0;
     482                 : 
     483             255 :   NaClLog(4, "NaClAppLaunchServiceThreads: Entered, nap 0x%"NACL_PRIxPTR"\n",
     484                 :           (uintptr_t) nap);
     485                 : 
     486             255 :   NaClNameServiceLaunch(nap->name_service);
     487                 : 
     488             255 :   if (LOAD_OK != NaClWaitForStartModuleCommand(nap)) {
     489               0 :     return rv;
     490                 :   }
     491                 : 
     492             255 :   NaClXMutexLock(&nap->mu);
     493             255 :   if (NULL == nap->runtime_host_interface) {
     494             252 :     nap->runtime_host_interface = malloc(sizeof *nap->runtime_host_interface);
     495             252 :     if (NULL == nap->runtime_host_interface ||
     496             252 :         !NaClRuntimeHostInterfaceCtor_protected(nap->runtime_host_interface)) {
     497               0 :       NaClLog(LOG_ERROR, "NaClAppLaunchServiceThreads:"
     498                 :               " Failed to initialise runtime host interface\n");
     499               0 :       goto done;
     500                 :     }
     501             252 :   }
     502             255 :   NaClXMutexUnlock(&nap->mu);
     503                 : 
     504             255 :   kernel_service = (struct NaClKernelService *) malloc(sizeof *kernel_service);
     505             255 :   if (NULL == kernel_service) {
     506               0 :     NaClLog(LOG_ERROR,
     507                 :             "NaClAppLaunchServiceThreads: No memory for kern service\n");
     508               0 :     goto done;
     509                 :   }
     510                 : 
     511             255 :   if (!NaClKernelServiceCtor(kernel_service,
     512                 :                              NaClAddrSpSquattingThreadIfFactoryFunction,
     513                 :                              (void *) nap,
     514                 :                              nap->runtime_host_interface)) {
     515               0 :     NaClLog(LOG_ERROR,
     516                 :             "NaClAppLaunchServiceThreads: KernServiceCtor failed\n");
     517               0 :     free(kernel_service);
     518               0 :     kernel_service = NULL;
     519               0 :     goto done;
     520                 :   }
     521                 : 
     522             255 :   if (!NaClSimpleServiceStartServiceThread((struct NaClSimpleService *)
     523                 :                                            kernel_service)) {
     524               0 :     NaClLog(LOG_ERROR,
     525                 :             "NaClAppLaunchServiceThreads: KernService start service failed\n");
     526               0 :     goto done;
     527                 :   }
     528                 :   /*
     529                 :    * NB: StartServiceThread grabbed another reference to kernel_service,
     530                 :    * used by the service thread.  Closing the connection capability
     531                 :    * should cause the service thread to shut down and in turn release
     532                 :    * that reference.
     533                 :    */
     534                 : 
     535             255 :   NaClXMutexLock(&nap->mu);
     536             765 :   CHECK(NULL == nap->kernel_service);
     537                 : 
     538             255 :   nap->kernel_service = kernel_service;
     539             255 :   kernel_service = NULL;
     540             255 :   NaClXMutexUnlock(&nap->mu);
     541             255 :   rv = 1;
     542                 : 
     543                 : done:
     544             255 :   NaClXMutexLock(&nap->mu);
     545             255 :   if (NULL != nap->kernel_service) {
     546             255 :     NaClLog(3,
     547                 :             ("NaClAppLaunchServiceThreads: adding kernel service to"
     548                 :              " name service\n"));
     549             510 :     (*NACL_VTBL(NaClNameService, nap->name_service)->
     550                 :      CreateDescEntry)(nap->name_service,
     551                 :                       "KernelService", NACL_ABI_O_RDWR,
     552             255 :                       NaClDescRef(nap->kernel_service->base.bound_and_cap[1]));
     553             255 :   }
     554             255 :   NaClXMutexUnlock(&nap->mu);
     555                 : 
     556                 :   /*
     557                 :    * Single exit path.
     558                 :    *
     559                 :    * Error cleanup invariant.  No service thread should be running
     560                 :    * (modulo asynchronous shutdown).  Automatic variables refer to
     561                 :    * fully constructed objects if non-NULL, and when ownership is
     562                 :    * transferred to the NaClApp object the corresponding automatic
     563                 :    * variable is set to NULL.
     564                 :    */
     565             255 :   NaClRefCountSafeUnref((struct NaClRefCount *) kernel_service);
     566             255 :   return rv;
     567             255 : }
     568                 : 
     569             243 : int NaClReportExitStatus(struct NaClApp *nap, int exit_status) {
     570             243 :   int rv = 0;
     571                 : 
     572             243 :   NaClXMutexLock(&nap->mu);
     573                 :   /*
     574                 :    * If several threads are exiting/reporting signals at once, we should
     575                 :    * let only one thread to pass through. This way we can use exit code
     576                 :    * without synchronization once we know that running==0.
     577                 :    */
     578             243 :   if (!nap->running) {
     579               0 :     NaClXMutexUnlock(&nap->mu);
     580               0 :     return 0;
     581                 :   }
     582                 : 
     583             243 :   if (NULL != nap->runtime_host_interface) {
     584                 :     /* TODO(halyavin) update NaCl plugin to accept full exit_status value */
     585             232 :     if (NACL_ABI_WIFEXITED(exit_status)) {
     586             232 :     rv = (*NACL_VTBL(NaClRuntimeHostInterface, nap->runtime_host_interface)->
     587                 :           ReportExitStatus)(nap->runtime_host_interface,
     588                 :                             NACL_ABI_WEXITSTATUS(exit_status));
     589             232 :     }
     590                 :     /*
     591                 :      * Due to cross-repository checkins, the Cr-side might not yet
     592                 :      * implement this RPC.  We return whether shutdown was reported.
     593                 :      */
     594             232 :   }
     595             243 :   nap->exit_status = exit_status;
     596             243 :   nap->running = 0;
     597             243 :   NaClXCondVarSignal(&nap->cv);
     598                 : 
     599             243 :   NaClXMutexUnlock(&nap->mu);
     600                 : 
     601             243 :   return rv;
     602             243 : }
     603                 : 
     604             270 : uintptr_t NaClGetInitialStackTop(struct NaClApp *nap) {
     605                 :   /*
     606                 :    * We keep the top of useful memory a page below the top of the
     607                 :    * sandbox region so that compilers can do tricks like computing a
     608                 :    * base register of sp + constant and then using a
     609                 :    * register-minus-constant addressing mode, which comes up at least
     610                 :    * on ARM where the compiler is trying to optimize given the limited
     611                 :    * size of immediate offsets available.  The maximum such negative
     612                 :    * constant on ARM will be -4095, but we use page size (64k) for
     613                 :    * good measure and do it on all machines just for uniformity.
     614                 :    */
     615             270 :   return ((uintptr_t) 1U << nap->addr_bits) - NACL_MAP_PAGESIZE;
     616                 : }
     617                 : 
     618                 : /*
     619                 :  * preconditions:
     620                 :  *  * argc is the length of the argv array
     621                 :  *  * envv may be NULL (this happens on MacOS/Cocoa and in tests)
     622                 :  *  * if envv is non-NULL it is 'consistent', null terminated etc.
     623                 :  */
     624             270 : int NaClCreateMainThread(struct NaClApp     *nap,
     625             270 :                          int                argc,
     626             270 :                          char               **argv,
     627             270 :                          char const *const  *envv) {
     628                 :   /*
     629                 :    * Compute size of string tables for argv and envv
     630                 :    */
     631             270 :   int                   retval;
     632             270 :   int                   envc;
     633             270 :   size_t                size;
     634             270 :   int                   auxv_entries;
     635             270 :   size_t                ptr_tbl_size;
     636             270 :   int                   i;
     637             270 :   uint32_t              *p;
     638             270 :   char                  *strp;
     639             270 :   size_t                *argv_len;
     640             270 :   size_t                *envv_len;
     641             270 :   uintptr_t             stack_ptr;
     642                 : 
     643             270 :   retval = 0;  /* fail */
     644             810 :   CHECK(argc >= 0);
     645             814 :   CHECK(NULL != argv || 0 == argc);
     646                 : 
     647             270 :   envc = 0;
     648             270 :   if (NULL != envv) {
     649             255 :     char const *const *pp;
     650             538 :     for (pp = envv; NULL != *pp; ++pp) {
     651              14 :       ++envc;
     652              14 :     }
     653             255 :   }
     654             270 :   envv_len = 0;
     655             270 :   argv_len = malloc(argc * sizeof argv_len[0]);
     656             270 :   envv_len = malloc(envc * sizeof envv_len[0]);
     657             270 :   if (NULL == argv_len) {
     658               0 :     goto cleanup;
     659                 :   }
     660             270 :   if (NULL == envv_len && 0 != envc) {
     661               0 :     goto cleanup;
     662                 :   }
     663                 : 
     664             270 :   size = 0;
     665                 : 
     666                 :   /*
     667                 :    * The following two loops cannot overflow.  The reason for this is
     668                 :    * that they are counting the number of bytes used to hold the
     669                 :    * NUL-terminated strings that comprise the argv and envv tables.
     670                 :    * If the entire address space consisted of just those strings, then
     671                 :    * the size variable would overflow; however, since there's the code
     672                 :    * space required to hold the code below (and we are not targetting
     673                 :    * Harvard architecture machines), at least one page holds code, not
     674                 :    * data.  We are assuming that the caller is non-adversarial and the
     675                 :    * code does not look like string data....
     676                 :    */
     677            1340 :   for (i = 0; i < argc; ++i) {
     678             400 :     argv_len[i] = strlen(argv[i]) + 1;
     679             400 :     size += argv_len[i];
     680             400 :   }
     681             568 :   for (i = 0; i < envc; ++i) {
     682              14 :     envv_len[i] = strlen(envv[i]) + 1;
     683              14 :     size += envv_len[i];
     684              14 :   }
     685                 : 
     686                 :   /*
     687                 :    * NaCl modules are ILP32, so the argv, envv pointers, as well as
     688                 :    * the terminating NULL pointers at the end of the argv/envv tables,
     689                 :    * are 32-bit values.  We also have the auxv to take into account.
     690                 :    *
     691                 :    * The argv and envv pointer tables came from trusted code and is
     692                 :    * part of memory.  Thus, by the same argument above, adding in
     693                 :    * "ptr_tbl_size" cannot possibly overflow the "size" variable since
     694                 :    * it is a size_t object.  However, the extra pointers for auxv and
     695                 :    * the space for argv could cause an overflow.  The fact that we
     696                 :    * used stack to get here etc means that ptr_tbl_size could not have
     697                 :    * overflowed.
     698                 :    *
     699                 :    * NB: the underlying OS would have limited the amount of space used
     700                 :    * for argv and envv -- on linux, it is ARG_MAX, or 128KB -- and
     701                 :    * hence the overflow check is for obvious auditability rather than
     702                 :    * for correctness.
     703                 :    */
     704             270 :   auxv_entries = 1;
     705             270 :   if (0 != nap->user_entry_pt) {
     706               5 :     auxv_entries++;
     707               5 :   }
     708             270 :   if (0 != nap->dynamic_text_start) {
     709             270 :     auxv_entries++;
     710             270 :   }
     711             270 :   ptr_tbl_size = (((NACL_STACK_GETS_ARG ? 1 : 0) +
     712                 :                    (3 + argc + 1 + envc + 1 + auxv_entries * 2)) *
     713                 :                   sizeof(uint32_t));
     714                 : 
     715             270 :   if (SIZE_T_MAX - size < ptr_tbl_size) {
     716               0 :     NaClLog(LOG_WARNING,
     717                 :             "NaClCreateMainThread: ptr_tbl_size cause size of"
     718                 :             " argv / environment copy to overflow!?!\n");
     719               0 :     retval = 0;
     720               0 :     goto cleanup;
     721                 :   }
     722             270 :   size += ptr_tbl_size;
     723                 : 
     724             270 :   size = (size + NACL_STACK_ALIGN_MASK) & ~NACL_STACK_ALIGN_MASK;
     725                 : 
     726             270 :   if (size > nap->stack_size) {
     727               0 :     retval = 0;
     728               0 :     goto cleanup;
     729                 :   }
     730                 : 
     731                 :   /*
     732                 :    * Write strings and char * arrays to stack.
     733                 :    */
     734             270 :   stack_ptr = NaClUserToSysAddrRange(nap, NaClGetInitialStackTop(nap) - size,
     735                 :                                      size);
     736             270 :   if (stack_ptr == kNaClBadAddress) {
     737               0 :     retval = 0;
     738               0 :     goto cleanup;
     739                 :   }
     740                 : 
     741             270 :   NaClLog(2, "setting stack to : %016"NACL_PRIxPTR"\n", stack_ptr);
     742                 : 
     743             810 :   VCHECK(0 == (stack_ptr & NACL_STACK_ALIGN_MASK),
     744                 :          ("stack_ptr not aligned: %016"NACL_PRIxPTR"\n", stack_ptr));
     745                 : 
     746             270 :   p = (uint32_t *) stack_ptr;
     747             270 :   strp = (char *) stack_ptr + ptr_tbl_size;
     748                 : 
     749                 :   /*
     750                 :    * For x86-32, we push an initial argument that is the address of
     751                 :    * the main argument block.  For other machines, this is passed
     752                 :    * in a register and that's set in NaClStartThreadInApp.
     753                 :    */
     754                 :   if (NACL_STACK_GETS_ARG) {
     755                 :     uint32_t *argloc = p++;
     756                 :     *argloc = (uint32_t) NaClSysToUser(nap, (uintptr_t) p);
     757                 :   }
     758                 : 
     759             270 :   *p++ = 0;  /* Cleanup function pointer, always NULL.  */
     760             270 :   *p++ = envc;
     761             270 :   *p++ = argc;
     762                 : 
     763            1340 :   for (i = 0; i < argc; ++i) {
     764             400 :     *p++ = (uint32_t) NaClSysToUser(nap, (uintptr_t) strp);
     765             400 :     NaClLog(2, "copying arg %d  %p -> %p\n",
     766                 :             i, argv[i], strp);
     767            1200 :     strcpy(strp, argv[i]);
     768             400 :     strp += argv_len[i];
     769             400 :   }
     770             270 :   *p++ = 0;  /* argv[argc] is NULL.  */
     771                 : 
     772             568 :   for (i = 0; i < envc; ++i) {
     773              14 :     *p++ = (uint32_t) NaClSysToUser(nap, (uintptr_t) strp);
     774              14 :     NaClLog(2, "copying env %d  %p -> %p\n",
     775                 :             i, envv[i], strp);
     776              42 :     strcpy(strp, envv[i]);
     777              14 :     strp += envv_len[i];
     778              14 :   }
     779             270 :   *p++ = 0;  /* envp[envc] is NULL.  */
     780                 : 
     781                 :   /* Push an auxv */
     782             270 :   if (0 != nap->user_entry_pt) {
     783               5 :     *p++ = AT_ENTRY;
     784               5 :     *p++ = (uint32_t) nap->user_entry_pt;
     785               5 :   }
     786             270 :   if (0 != nap->dynamic_text_start) {
     787             270 :     *p++ = AT_BASE;
     788             270 :     *p++ = (uint32_t) nap->dynamic_text_start;
     789             270 :   }
     790             270 :   *p++ = AT_NULL;
     791             270 :   *p++ = 0;
     792                 : 
     793             810 :   CHECK((char *) p == (char *) stack_ptr + ptr_tbl_size);
     794                 : 
     795                 :   /* now actually spawn the thread */
     796             270 :   NaClXMutexLock(&nap->mu);
     797                 :   /*
     798                 :    * Unreference the main nexe and irt at this point if no debug stub callbacks
     799                 :    * have been registered, as these references to the main nexe and irt
     800                 :    * descriptors are only used when providing file access to the debugger.
     801                 :    * In the debug case, let shutdown take care of cleanup.
     802                 :    */
     803             270 :   if (NULL == nap->debug_stub_callbacks) {
     804             253 :     if (NULL != nap->main_nexe_desc) {
     805             244 :       NaClDescUnref(nap->main_nexe_desc);
     806             244 :       nap->main_nexe_desc = NULL;
     807             244 :     }
     808             253 :     if (NULL != nap->irt_nexe_desc) {
     809               5 :       NaClDescUnref(nap->irt_nexe_desc);
     810               5 :       nap->irt_nexe_desc = NULL;
     811               5 :     }
     812             253 :   }
     813             270 :   nap->running = 1;
     814             270 :   NaClXMutexUnlock(&nap->mu);
     815                 : 
     816             270 :   NaClVmHoleWaitToStartThread(nap);
     817                 : 
     818                 :   /*
     819                 :    * For x86, we adjust the stack pointer down to push a dummy return
     820                 :    * address.  This happens after the stack pointer alignment.
     821                 :    * We avoid the otherwise harmless call for the zero case because
     822                 :    * _FORTIFY_SOURCE memset can warn about zero-length calls.
     823                 :    */
     824                 :   if (NACL_STACK_PAD_BELOW_ALIGN != 0) {
     825             270 :     stack_ptr -= NACL_STACK_PAD_BELOW_ALIGN;
     826             810 :     memset((void *) stack_ptr, 0, NACL_STACK_PAD_BELOW_ALIGN);
     827                 :   }
     828                 : 
     829             270 :   NaClLog(2, "system stack ptr : %016"NACL_PRIxPTR"\n", stack_ptr);
     830             270 :   NaClLog(2, "  user stack ptr : %016"NACL_PRIxPTR"\n",
     831             270 :           NaClSysToUserStackAddr(nap, stack_ptr));
     832                 : 
     833                 :   /* e_entry is user addr */
     834             540 :   retval = NaClAppThreadSpawn(nap,
     835                 :                               nap->initial_entry_pt,
     836             270 :                               NaClSysToUserStackAddr(nap, stack_ptr),
     837                 :                               /* user_tls1= */ (uint32_t) nap->break_addr,
     838                 :                               /* user_tls2= */ 0);
     839                 : 
     840                 : cleanup:
     841             270 :   free(argv_len);
     842             270 :   free(envv_len);
     843                 : 
     844             270 :   return retval;
     845                 : }
     846                 : 
     847             268 : int NaClWaitForMainThreadToExit(struct NaClApp  *nap) {
     848             268 :   NaClLog(3, "NaClWaitForMainThreadToExit: taking NaClApp lock\n");
     849             268 :   NaClXMutexLock(&nap->mu);
     850             268 :   NaClLog(3, " waiting for exit status\n");
     851             778 :   while (nap->running) {
     852             268 :     NaClXCondVarWait(&nap->cv, &nap->mu);
     853             268 :     NaClLog(3, " wakeup, nap->running %d, nap->exit_status %d\n",
     854                 :             nap->running, nap->exit_status);
     855             268 :   }
     856             242 :   NaClXMutexUnlock(&nap->mu);
     857                 :   /*
     858                 :    * Some thread invoked the exit (exit_group) syscall.
     859                 :    */
     860                 : 
     861             242 :   if (NULL != nap->debug_stub_callbacks) {
     862               2 :     nap->debug_stub_callbacks->process_exit_hook();
     863               2 :   }
     864                 : 
     865             242 :   return NACL_ABI_WEXITSTATUS(nap->exit_status);
     866                 : }
     867                 : 
     868                 : /*
     869                 :  * stack_ptr is from syscall, so a 32-bit address.
     870                 :  */
     871           20611 : int32_t NaClCreateAdditionalThread(struct NaClApp *nap,
     872           20611 :                                    uintptr_t      prog_ctr,
     873           20611 :                                    uintptr_t      sys_stack_ptr,
     874           20611 :                                    uint32_t       user_tls1,
     875           20611 :                                    uint32_t       user_tls2) {
     876           41222 :   if (!NaClAppThreadSpawn(nap,
     877                 :                           prog_ctr,
     878           20611 :                           NaClSysToUserStackAddr(nap, sys_stack_ptr),
     879                 :                           user_tls1,
     880                 :                           user_tls2)) {
     881               0 :     NaClLog(LOG_WARNING,
     882                 :             ("NaClCreateAdditionalThread: could not allocate thread."
     883                 :              "  Returning EAGAIN per POSIX specs.\n"));
     884               0 :     return -NACL_ABI_EAGAIN;
     885                 :   }
     886           20611 :   return 0;
     887           20611 : }

Generated by: LCOV version 1.7