LCOV - code coverage report
Current view: directory - src/trusted/service_runtime - sel_ldr_standard.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 358 230 64.2 %
Date: 2012-02-16 Functions: 0 0 -

       1                 : /*
       2                 :  * Copyright (c) 2011 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/manifest_name_service_proxy/manifest_proxy.h"
      29                 : #include "native_client/src/trusted/perf_counter/nacl_perf_counter.h"
      30                 : 
      31                 : #include "native_client/src/trusted/reverse_service/reverse_control_rpc.h"
      32                 : 
      33                 : #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
      34                 : #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
      35                 : 
      36                 : #include "native_client/src/trusted/service_runtime/arch/sel_ldr_arch.h"
      37                 : #include "native_client/src/trusted/service_runtime/elf_util.h"
      38                 : #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
      39                 : #include "native_client/src/trusted/service_runtime/nacl_debug_init.h"
      40                 : #include "native_client/src/trusted/service_runtime/nacl_kern_services.h"
      41                 : #include "native_client/src/trusted/service_runtime/nacl_oop_debugger_hooks.h"
      42                 : #include "native_client/src/trusted/service_runtime/nacl_switch_to_app.h"
      43                 : #include "native_client/src/trusted/service_runtime/nacl_syscall_common.h"
      44                 : #include "native_client/src/trusted/service_runtime/nacl_text.h"
      45                 : #include "native_client/src/trusted/service_runtime/outer_sandbox.h"
      46                 : #include "native_client/src/trusted/service_runtime/sel_memory.h"
      47                 : #include "native_client/src/trusted/service_runtime/sel_ldr.h"
      48                 : #include "native_client/src/trusted/service_runtime/sel_ldr_thread_interface.h"
      49                 : #include "native_client/src/trusted/service_runtime/sel_util.h"
      50                 : #include "native_client/src/trusted/service_runtime/sel_addrspace.h"
      51                 : 
      52                 : #if !defined(SIZE_T_MAX)
      53                 : # define SIZE_T_MAX     (~(size_t) 0)
      54                 : #endif
      55                 : 
      56                 : 
      57                 : /*
      58                 :  * Fill from static_text_end to end of that page with halt
      59                 :  * instruction, which is at least NACL_HALT_LEN in size when no
      60                 :  * dynamic text is present.  Does not touch dynamic text region, which
      61                 :  * should be pre-filled with HLTs.
      62                 :  *
      63                 :  * By adding NACL_HALT_SLED_SIZE, we ensure that the code region ends
      64                 :  * with HLTs, just in case the CPU has a bug in which it fails to
      65                 :  * check for running off the end of the x86 code segment.
      66                 :  */
      67               3 : void NaClFillEndOfTextRegion(struct NaClApp *nap) {
      68                 :   size_t page_pad;
      69                 : 
      70                 :   /*
      71                 :    * NOTE: make sure we are not silently overwriting data.  It is the
      72                 :    * toolchain's responsibility to ensure that a NACL_HALT_SLED_SIZE
      73                 :    * gap exists.
      74                 :    */
      75               3 :   if (0 != nap->data_start &&
      76                 :       nap->static_text_end + NACL_HALT_SLED_SIZE > nap->data_start) {
      77               0 :     NaClLog(LOG_FATAL, "Missing gap between text and data for halt_sled\n");
      78                 :   }
      79               3 :   if (0 != nap->rodata_start &&
      80                 :       nap->static_text_end + NACL_HALT_SLED_SIZE > nap->rodata_start) {
      81               0 :     NaClLog(LOG_FATAL, "Missing gap between text and rodata for halt_sled\n");
      82                 :   }
      83                 : 
      84               3 :   if (NULL == nap->text_shm) {
      85                 :     /*
      86                 :      * No dynamic text exists.  Space for NACL_HALT_SLED_SIZE must
      87                 :      * exist.
      88                 :      */
      89               0 :     page_pad = (NaClRoundAllocPage(nap->static_text_end + NACL_HALT_SLED_SIZE)
      90                 :                 - nap->static_text_end);
      91               0 :     CHECK(page_pad >= NACL_HALT_SLED_SIZE);
      92               0 :     CHECK(page_pad < NACL_MAP_PAGESIZE + NACL_HALT_SLED_SIZE);
      93                 :   } else {
      94                 :     /*
      95                 :      * Dynamic text exists; the halt sled resides in the dynamic text
      96                 :      * region, so all we need to do here is to round out the last
      97                 :      * static text page with HLT instructions.  It doesn't matter if
      98                 :      * the size of this region is smaller than NACL_HALT_SLED_SIZE --
      99                 :      * this is just to fully initialize the page, rather than (later)
     100                 :      * decoding/validating zero-filled memory as instructions.
     101                 :      */
     102               3 :     page_pad = NaClRoundAllocPage(nap->static_text_end) - nap->static_text_end;
     103                 :   }
     104                 : 
     105               3 :   NaClLog(4,
     106                 :           "Filling with halts: %08"NACL_PRIxPTR", %08"NACL_PRIxS" bytes\n",
     107                 :           nap->mem_start + nap->static_text_end,
     108                 :           page_pad);
     109                 : 
     110               3 :   NaClFillMemoryRegionWithHalt((void *)(nap->mem_start + nap->static_text_end),
     111                 :                                page_pad);
     112                 : 
     113               3 :   nap->static_text_end += page_pad;
     114               3 : }
     115                 : 
     116                 : /*
     117                 :  * Basic address space layout sanity check.
     118                 :  */
     119                 : NaClErrorCode NaClCheckAddressSpaceLayoutSanity(struct NaClApp *nap,
     120                 :                                                 uintptr_t rodata_end,
     121                 :                                                 uintptr_t data_end,
     122               8 :                                                 uintptr_t max_vaddr) {
     123               8 :   if (0 != nap->data_start) {
     124               8 :     if (data_end != max_vaddr) {
     125               1 :       NaClLog(LOG_INFO, "data segment is not last\n");
     126               1 :       return LOAD_DATA_NOT_LAST_SEGMENT;
     127                 :     }
     128               0 :   } else if (0 != nap->rodata_start) {
     129               0 :     if (NaClRoundAllocPage(rodata_end) != max_vaddr) {
     130                 :       /*
     131                 :        * This should be unreachable, but we include it just for
     132                 :        * completeness.
     133                 :        *
     134                 :        * Here is why it is unreachable:
     135                 :        *
     136                 :        * NaClPhdrChecks checks the test segment starting address.  The
     137                 :        * only allowed loaded segments are text, data, and rodata.
     138                 :        * Thus unless the rodata is in the trampoline region, it must
     139                 :        * be after the text.  And NaClElfImageValidateProgramHeaders
     140                 :        * ensures that all segments start after the trampoline region.
     141                 :        */
     142               0 :       NaClLog(LOG_INFO, "no data segment, but rodata segment is not last\n");
     143               0 :       return LOAD_NO_DATA_BUT_RODATA_NOT_LAST_SEGMENT;
     144                 :     }
     145                 :   }
     146               7 :   if (0 != nap->rodata_start && 0 != nap->data_start) {
     147               6 :     if (rodata_end > nap->data_start) {
     148               1 :       NaClLog(LOG_INFO, "rodata_overlaps data.\n");
     149               1 :       return LOAD_RODATA_OVERLAPS_DATA;
     150                 :     }
     151                 :   }
     152               6 :   if (0 != nap->rodata_start) {
     153               5 :     if (NaClRoundAllocPage(NaClEndOfStaticText(nap)) > nap->rodata_start) {
     154               1 :       return LOAD_TEXT_OVERLAPS_RODATA;
     155                 :     }
     156               1 :   } else if (0 != nap->data_start) {
     157               1 :     if (NaClRoundAllocPage(NaClEndOfStaticText(nap)) > nap->data_start) {
     158               1 :       return LOAD_TEXT_OVERLAPS_DATA;
     159                 :     }
     160                 :   }
     161               4 :   if (0 != nap->rodata_start &&
     162                 :       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               4 :   if (0 != nap->data_start &&
     167                 :       NaClRoundAllocPage(nap->data_start) != nap->data_start) {
     168               0 :     NaClLog(LOG_INFO, "data_start not a multiple of allocation size\n");
     169               0 :     return LOAD_BAD_DATA_ALIGNMENT;
     170                 :   }
     171               4 :   return LOAD_OK;
     172                 : }
     173                 : 
     174              11 : void NaClLogAddressSpaceLayout(struct NaClApp *nap) {
     175              11 :   NaClLog(2, "NaClApp addr space layout:\n");
     176              11 :   NaClLog(2, "nap->static_text_end    = 0x%016"NACL_PRIxPTR"\n",
     177                 :           nap->static_text_end);
     178              11 :   NaClLog(2, "nap->dynamic_text_start = 0x%016"NACL_PRIxPTR"\n",
     179                 :           nap->dynamic_text_start);
     180              11 :   NaClLog(2, "nap->dynamic_text_end   = 0x%016"NACL_PRIxPTR"\n",
     181                 :           nap->dynamic_text_end);
     182              11 :   NaClLog(2, "nap->rodata_start       = 0x%016"NACL_PRIxPTR"\n",
     183                 :           nap->rodata_start);
     184              11 :   NaClLog(2, "nap->data_start         = 0x%016"NACL_PRIxPTR"\n",
     185                 :           nap->data_start);
     186              11 :   NaClLog(2, "nap->data_end           = 0x%016"NACL_PRIxPTR"\n",
     187                 :           nap->data_end);
     188              11 :   NaClLog(2, "nap->break_addr         = 0x%016"NACL_PRIxPTR"\n",
     189                 :           nap->break_addr);
     190              11 :   NaClLog(2, "nap->initial_entry_pt   = 0x%016"NACL_PRIxPTR"\n",
     191                 :           nap->initial_entry_pt);
     192              11 :   NaClLog(2, "nap->user_entry_pt      = 0x%016"NACL_PRIxPTR"\n",
     193                 :           nap->user_entry_pt);
     194              11 :   NaClLog(2, "nap->bundle_size        = 0x%x\n", nap->bundle_size);
     195              11 : }
     196                 : 
     197                 : NaClErrorCode NaClAppLoadFile(struct Gio       *gp,
     198              11 :                               struct NaClApp   *nap) {
     199              11 :   NaClErrorCode       ret = LOAD_INTERNAL;
     200                 :   NaClErrorCode       subret;
     201                 :   uintptr_t           rodata_end;
     202                 :   uintptr_t           data_end;
     203                 :   uintptr_t           max_vaddr;
     204              11 :   struct NaClElfImage *image = NULL;
     205                 :   struct NaClPerfCounter  time_load_file;
     206                 : 
     207              11 :   NaClPerfCounterCtor(&time_load_file, "NaClAppLoadFile");
     208                 : 
     209                 :   /* NACL_MAX_ADDR_BITS < 32 */
     210              11 :   if (nap->addr_bits > NACL_MAX_ADDR_BITS) {
     211               0 :     ret = LOAD_ADDR_SPACE_TOO_BIG;
     212               0 :     goto done;
     213                 :   }
     214                 : 
     215              11 :   nap->stack_size = NaClRoundAllocPage(nap->stack_size);
     216                 : 
     217                 :   /* temporay object will be deleted at end of function */
     218              11 :   image = NaClElfImageNew(gp, &subret);
     219              11 :   if (NULL == image) {
     220               0 :     ret = subret;
     221               0 :     goto done;
     222                 :   }
     223                 : 
     224              11 :   subret = NaClElfImageValidateElfHeader(image);
     225              11 :   if (LOAD_OK != subret) {
     226               0 :     ret = subret;
     227               0 :     goto done;
     228                 :   }
     229                 : 
     230              11 :   subret = NaClElfImageValidateProgramHeaders(image,
     231                 :                                               nap->addr_bits,
     232                 :                                               &nap->static_text_end,
     233                 :                                               &nap->rodata_start,
     234                 :                                               &rodata_end,
     235                 :                                               &nap->data_start,
     236                 :                                               &data_end,
     237                 :                                               &max_vaddr);
     238              11 :   if (LOAD_OK != subret) {
     239               3 :     ret = subret;
     240               3 :     goto done;
     241                 :   }
     242                 : 
     243               8 :   if (0 == nap->data_start) {
     244               0 :     if (0 == nap->rodata_start) {
     245               0 :       if (NaClRoundAllocPage(max_vaddr) - max_vaddr < NACL_HALT_SLED_SIZE) {
     246                 :         /*
     247                 :          * if no rodata and no data, we make sure that there is space for
     248                 :          * the halt sled.
     249                 :          */
     250               0 :         max_vaddr += NACL_MAP_PAGESIZE;
     251                 :       }
     252                 :     } else {
     253                 :       /*
     254                 :        * no data, but there is rodata.  this means max_vaddr is just
     255                 :        * where rodata ends.  this might not be at an allocation
     256                 :        * boundary, and in this the page would not be writable.  round
     257                 :        * max_vaddr up to the next allocation boundary so that bss will
     258                 :        * be at the next writable region.
     259                 :        */
     260                 :       ;
     261                 :     }
     262               0 :     max_vaddr = NaClRoundAllocPage(max_vaddr);
     263                 :   }
     264                 :   /*
     265                 :    * max_vaddr -- the break or the boundary between data (initialized
     266                 :    * and bss) and the address space hole -- does not have to be at a
     267                 :    * page boundary.
     268                 :    */
     269               8 :   nap->break_addr = max_vaddr;
     270               8 :   nap->data_end = max_vaddr;
     271                 : 
     272               8 :   NaClLog(4, "Values from NaClElfImageValidateProgramHeaders:\n");
     273               8 :   NaClLog(4, "rodata_start = 0x%08"NACL_PRIxPTR"\n", nap->rodata_start);
     274               8 :   NaClLog(4, "rodata_end   = 0x%08"NACL_PRIxPTR"\n", rodata_end);
     275               8 :   NaClLog(4, "data_start   = 0x%08"NACL_PRIxPTR"\n", nap->data_start);
     276               8 :   NaClLog(4, "data_end     = 0x%08"NACL_PRIxPTR"\n", data_end);
     277               8 :   NaClLog(4, "max_vaddr    = 0x%08"NACL_PRIxPTR"\n", max_vaddr);
     278                 : 
     279                 :   /* We now support only one bundle size.  */
     280               8 :   nap->bundle_size = NACL_INSTR_BLOCK_SIZE;
     281                 : 
     282               8 :   nap->initial_entry_pt = NaClElfImageGetEntryPoint(image);
     283               8 :   NaClLogAddressSpaceLayout(nap);
     284                 : 
     285               8 :   if (!NaClAddrIsValidEntryPt(nap, nap->initial_entry_pt)) {
     286               0 :     ret = LOAD_BAD_ENTRY;
     287               0 :     goto done;
     288                 :   }
     289                 : 
     290               8 :   subret = NaClCheckAddressSpaceLayoutSanity(nap, rodata_end, data_end,
     291                 :                                              max_vaddr);
     292               8 :   if (LOAD_OK != subret) {
     293               4 :     ret = subret;
     294               4 :     goto done;
     295                 :   }
     296                 : 
     297               4 :   NaClLog(2, "Allocating address space\n");
     298               4 :   NaClPerfCounterMark(&time_load_file, "PreAllocAddrSpace");
     299               4 :   NaClPerfCounterIntervalLast(&time_load_file);
     300               4 :   subret = NaClAllocAddrSpace(nap);
     301               4 :   NaClPerfCounterMark(&time_load_file,
     302                 :                       NACL_PERF_IMPORTANT_PREFIX "AllocAddrSpace");
     303               4 :   NaClPerfCounterIntervalLast(&time_load_file);
     304               4 :   if (LOAD_OK != subret) {
     305               1 :     ret = subret;
     306               1 :     goto done;
     307                 :   }
     308                 : 
     309                 :   /*
     310                 :    * Make sure the static image pages are marked writable before we try
     311                 :    * to write them.
     312                 :    */
     313               3 :   NaClLog(2, "Loading into memory\n");
     314               3 :   ret = NaCl_mprotect((void *) (nap->mem_start + NACL_TRAMPOLINE_START),
     315                 :                       NaClRoundAllocPage(nap->data_end) - NACL_TRAMPOLINE_START,
     316                 :                       PROT_READ | PROT_WRITE);
     317               3 :   if (0 != ret) {
     318               0 :     NaClLog(LOG_FATAL,
     319                 :             "NaClAppLoadFile: Failed to make image pages writable. "
     320                 :             "Error code 0x%x\n",
     321                 :             ret);
     322                 :   }
     323               3 :   subret = NaClElfImageLoad(image, gp, nap->addr_bits, nap->mem_start);
     324               3 :   if (LOAD_OK != subret) {
     325               0 :     ret = subret;
     326               0 :     goto done;
     327                 :   }
     328                 : 
     329                 :   /*
     330                 :    * NB: mem_map object has been initialized, but is empty.
     331                 :    * NaClMakeDynamicTextShared does not touch it.
     332                 :    *
     333                 :    * NaClMakeDynamicTextShared also fills the dynamic memory region
     334                 :    * with the architecture-specific halt instruction.  If/when we use
     335                 :    * memory mapping to save paging space for the dynamic region and
     336                 :    * lazily halt fill the memory as the pages become
     337                 :    * readable/executable, we must make sure that the *last*
     338                 :    * NACL_MAP_PAGESIZE chunk is nonetheless mapped and written with
     339                 :    * halts.
     340                 :    */
     341               3 :   NaClLog(2,
     342                 :           ("Replacing gap between static text and"
     343                 :            " (ro)data with shareable memory\n"));
     344               3 :   subret = NaClMakeDynamicTextShared(nap);
     345               3 :   NaClPerfCounterMark(&time_load_file,
     346                 :                       NACL_PERF_IMPORTANT_PREFIX "MakeDynText");
     347               3 :   NaClPerfCounterIntervalLast(&time_load_file);
     348               3 :   if (LOAD_OK != subret) {
     349               0 :     ret = subret;
     350               0 :     goto done;
     351                 :   }
     352                 : #if NACL_OSX && defined(NACL_STANDALONE)
     353                 :   /*
     354                 :    * Enable the outer sandbox on Mac.  Do this as soon as possible.
     355                 :    *
     356                 :    * This is needed only when built for "Standalone" mode (which
     357                 :    * currently means firefox plugin, as opposed to as an built-in
     358                 :    * plugin in Chrome), since in the Chrome built-in/integrated build
     359                 :    * the sandbox is enabled earlier, in chrome's zygote process
     360                 :    * initialization / specialization when the zygote forks a copy of
     361                 :    * itself to become sel_ldr (via sel_main_chrome.c's
     362                 :    * NaClMainForChromium).
     363                 :    *
     364                 :    * It would be good to do this as soon as we have opened the
     365                 :    * executable file and log file, but nacl_text.c currently does not
     366                 :    * work in the sandbox.  See
     367                 :    * http://code.google.com/p/nativeclient/issues/detail?id=583
     368                 :    *
     369                 :    * This is needed for the test version of the ppapi plugin and post
     370                 :    * saucer separation; the integrated plugin/sel_ldr implementation
     371                 :    * that spawns from a chrome zygote image would have already enabled
     372                 :    * the sandbox.
     373                 :    *
     374                 :    * We cannot enable the sandbox if file access is enabled.
     375                 :    *
     376                 :    * OSX's sandbox has a race condition where mprotect in the address
     377                 :    * space set up code would sometimes fail, even before nacl_text.c.
     378                 :    * Ideally we would enable the OSX sandbox before examining any
     379                 :    * untrusted data (the nexe), but we have to wait until we address
     380                 :    * space setup is done, which requires reading the ELF headers.
     381                 :    */
     382               3 :   if (!NaClAclBypassChecks) {
     383               0 :     NaClEnableOuterSandbox();
     384                 :   }
     385                 : #endif
     386                 : 
     387                 :   /*
     388                 :    * NaClFillEndOfTextRegion will fill with halt instructions the
     389                 :    * padding space after the static text region.
     390                 :    *
     391                 :    * Shm-backed dynamic text space was filled with halt instructions
     392                 :    * in NaClMakeDynamicTextShared.  This extends to the rodata.  For
     393                 :    * non-shm-backed text space, this extend to the next page (and not
     394                 :    * allocation page).  static_text_end is updated to include the
     395                 :    * padding.
     396                 :    */
     397               3 :   NaClFillEndOfTextRegion(nap);
     398                 : 
     399                 : #if 0 == NACL_DANGEROUS_DEBUG_MODE_DISABLE_INNER_SANDBOX
     400               3 :   NaClLog(2, "Validating image\n");
     401               3 :   subret = NaClValidateImage(nap);
     402               3 :   NaClPerfCounterMark(&time_load_file,
     403                 :                       NACL_PERF_IMPORTANT_PREFIX "ValidateImg");
     404               3 :   NaClPerfCounterIntervalLast(&time_load_file);
     405               3 :   if (LOAD_OK != subret) {
     406               0 :     ret = subret;
     407               0 :     goto done;
     408                 :   }
     409                 : #endif
     410                 : 
     411               3 :   NaClLog(2, "Initializing arch switcher\n");
     412               3 :   NaClInitSwitchToApp(nap);
     413                 : 
     414               3 :   NaClLog(2, "Installing trampoline\n");
     415               3 :   NaClLoadTrampoline(nap);
     416                 : 
     417               3 :   NaClLog(2, "Installing springboard\n");
     418               3 :   NaClLoadSpringboard(nap);
     419                 : 
     420                 :   /*
     421                 :    * NaClMemoryProtect also initializes the mem_map w/ information
     422                 :    * about the memory pages and their current protection value.
     423                 :    *
     424                 :    * The contents of the dynamic text region will get remapped as
     425                 :    * non-writable.
     426                 :    */
     427               3 :   NaClLog(2, "Applying memory protection\n");
     428               3 :   subret = NaClMemoryProtection(nap);
     429               3 :   if (LOAD_OK != subret) {
     430               0 :     ret = subret;
     431               0 :     goto done;
     432                 :   }
     433                 : 
     434               3 :   NaClLog(2, "NaClAppLoadFile done; ");
     435               3 :   NaClLogAddressSpaceLayout(nap);
     436               3 :   ret = LOAD_OK;
     437              11 : done:
     438              11 :   NaClElfImageDelete(image);
     439                 : 
     440              11 :   NaClPerfCounterMark(&time_load_file, "EndLoadFile");
     441              11 :   NaClPerfCounterIntervalTotal(&time_load_file);
     442              11 :   return ret;
     443                 : }
     444                 : 
     445                 : NaClErrorCode NaClAppLoadFileDynamically(struct NaClApp *nap,
     446               0 :                                          struct Gio     *gio_file) {
     447               0 :   struct NaClElfImage *image = NULL;
     448               0 :   NaClErrorCode ret = LOAD_INTERNAL;
     449                 : 
     450               0 :   image = NaClElfImageNew((struct Gio *) gio_file, &ret);
     451               0 :   if (NULL == image) {
     452               0 :     goto done;
     453                 :   }
     454               0 :   ret = NaClElfImageValidateElfHeader(image);
     455               0 :   if (LOAD_OK != ret) {
     456               0 :     goto done;
     457                 :   }
     458               0 :   ret = NaClElfImageLoadDynamically(image, nap, gio_file);
     459               0 :   if (LOAD_OK != ret) {
     460               0 :     goto done;
     461                 :   }
     462               0 :   nap->user_entry_pt = nap->initial_entry_pt;
     463               0 :   nap->initial_entry_pt = NaClElfImageGetEntryPoint(image);
     464                 : 
     465               0 :  done:
     466               0 :   NaClElfImageDelete(image);
     467               0 :   return ret;
     468                 : }
     469                 : 
     470                 : int NaClAddrIsValidEntryPt(struct NaClApp *nap,
     471               8 :                            uintptr_t      addr) {
     472                 : #if defined(NACL_TARGET_ARM_THUMB2_MODE)
     473                 :   /*
     474                 :    * The entry point needs to be aligned 0xe mod 0x10.  But ARM processors need
     475                 :    * an odd target address to indicate that the target is in thumb mode.  When
     476                 :    * control is actually transferred, it is to the target address minus one.
     477                 :    */
     478                 :   if (0xf != (addr & (nap->bundle_size - 1))) {
     479                 :     return 0;
     480                 :   }
     481                 : #else
     482               8 :   if (0 != (addr & (nap->bundle_size - 1))) {
     483               0 :     return 0;
     484                 :   }
     485                 : #endif
     486                 : 
     487               8 :   return addr < nap->static_text_end;
     488                 : }
     489                 : 
     490               3 : int NaClAppLaunchServiceThreads(struct NaClApp *nap) {
     491               3 :   struct NaClManifestProxy                    *manifest_proxy = NULL;
     492               3 :   struct NaClKernService                      *kern_service = NULL;
     493               3 :   int                                         rv = 0;
     494                 :   enum NaClReverseChannelInitializationState  init_state;
     495                 : 
     496               3 :   NaClNameServiceLaunch(nap->name_service);
     497                 : 
     498               3 :   kern_service = (struct NaClKernService *) malloc(sizeof *kern_service);
     499               3 :   if (NULL == kern_service) {
     500               0 :     NaClLog(LOG_ERROR,
     501                 :             "NaClAppLaunchServiceThreads: No memory for kern service\n");
     502               0 :     goto done;
     503                 :   }
     504                 : 
     505               3 :   if (!NaClKernServiceCtor(kern_service,
     506                 :                            NaClAddrSpSquattingThreadIfFactoryFunction,
     507                 :                            (void *) nap,
     508                 :                            nap)) {
     509               0 :     NaClLog(LOG_ERROR,
     510                 :             "NaClAppLaunchServiceThreads: KernServiceCtor failed\n");
     511               0 :     free(kern_service);
     512               0 :     kern_service = NULL;
     513               0 :     goto done;
     514                 :   }
     515                 : 
     516               3 :   if (!NaClSimpleServiceStartServiceThread((struct NaClSimpleService *)
     517                 :                                            kern_service)) {
     518               0 :     NaClLog(LOG_ERROR,
     519                 :             "NaClAppLaunchServiceThreads: KernService start service failed\n");
     520               0 :     goto done;
     521                 :   }
     522                 :   /*
     523                 :    * NB: StartServiceThread grabbed another reference to kern_service,
     524                 :    * used by the service thread.  Closing the connection capability
     525                 :    * should cause the service thread to shut down and in turn release
     526                 :    * that reference.
     527                 :    */
     528                 : 
     529                 :   /*
     530                 :    * The locking here isn't really needed.  Here is why:
     531                 :    * reverse_channel_initialized is written in reverse_setup RPC
     532                 :    * handler of the secure command channel RPC handler thread.  and
     533                 :    * the RPC order requires that the plugin invoke reverse_setup prior
     534                 :    * to invoking start_module, so there will have been plenty of other
     535                 :    * synchronization operations to force cache coherency
     536                 :    * (module_may_start, for example, is set in the cache of the secure
     537                 :    * channel RPC handler (in start_module) and read by the main
     538                 :    * thread, and the synchronization operations needed to propagate
     539                 :    * its value properly suffices to propagate
     540                 :    * reverse_channel_initialized as well).  However, reading it while
     541                 :    * holding a lock is more obviously correct for tools like tsan.
     542                 :    * Due to the RPC order, it is impossible for
     543                 :    * reverse_channel_initialized to get set after the unlock and
     544                 :    * before the if test.
     545                 :    */
     546               3 :   NaClXMutexLock(&nap->mu);
     547                 :   /*
     548                 :    * If no reverse_setup RPC was made, then we do not set up a
     549                 :    * manifest proxy.  Otherwise, we make sure that the reverse channel
     550                 :    * setup is done, so that the application can actually use
     551                 :    * reverse-channel-based services such as the manifest proxy.
     552                 :    */
     553               3 :   if (NACL_REVERSE_CHANNEL_UNINITIALIZED !=
     554                 :       (init_state = nap->reverse_channel_initialization_state)) {
     555               0 :     while (NACL_REVERSE_CHANNEL_INITIALIZED !=
     556                 :       (init_state = nap->reverse_channel_initialization_state)) {
     557               0 :       NaClXCondVarWait(&nap->cv, &nap->mu);
     558                 :     }
     559                 :   }
     560               3 :   NaClXMutexUnlock(&nap->mu);
     561               3 :   if (NACL_REVERSE_CHANNEL_INITIALIZED != init_state) {
     562               3 :     NaClLog(3,
     563                 :             ("NaClAppLaunchServiceThreads: no reverse channel;"
     564                 :              " launched kernel services.\n"));
     565               3 :     NaClLog(3,
     566                 :             ("NaClAppLaunchServiceThreads: no reverse channel;"
     567                 :              " NOT launching manifest proxy.\n"));
     568               3 :     nap->kern_service = kern_service;
     569               3 :     kern_service = NULL;
     570                 : 
     571               3 :     rv = 1;
     572               3 :     goto done;
     573                 :   }
     574                 : 
     575                 :   /*
     576                 :    * Allocate/construct the manifest proxy without grabbing global
     577                 :    * locks.
     578                 :    */
     579               0 :   NaClLog(3, "NaClAppLaunchServiceThreads: launching manifest proxy\n");
     580                 : 
     581                 :   /*
     582                 :    * ReverseClientSetup RPC should be done via the command channel
     583                 :    * prior to the load_module / start_module RPCs, and
     584                 :    *  occurs after that, so checking
     585                 :    * nap->reverse_client suffices for determining whether the proxy is
     586                 :    * exporting reverse services.
     587                 :    */
     588               0 :   manifest_proxy = (struct NaClManifestProxy *) malloc(sizeof *manifest_proxy);
     589               0 :   if (NULL == manifest_proxy) {
     590               0 :     NaClLog(LOG_ERROR, "No memory for manifest proxy\n");
     591               0 :     NaClDescUnref(kern_service->base.bound_and_cap[1]);
     592               0 :     goto done;
     593                 :   }
     594               0 :   if (!NaClManifestProxyCtor(manifest_proxy,
     595                 :                              NaClAddrSpSquattingThreadIfFactoryFunction,
     596                 :                              (void *) nap,
     597                 :                              nap)) {
     598               0 :     NaClLog(LOG_ERROR, "ManifestProxyCtor failed\n");
     599                 :     /* do not leave a non-NULL pointer to a not-fully constructed object */
     600               0 :     free(manifest_proxy);
     601               0 :     manifest_proxy = NULL;
     602               0 :     NaClDescUnref(kern_service->base.bound_and_cap[1]);
     603               0 :     goto done;
     604                 :   }
     605                 : 
     606                 :   /*
     607                 :    * NaClSimpleServiceStartServiceThread requires the nap->mu lock.
     608                 :    */
     609               0 :   if (!NaClSimpleServiceStartServiceThread((struct NaClSimpleService *)
     610                 :                                            manifest_proxy)) {
     611               0 :     NaClLog(LOG_ERROR, "ManifestProxy start service failed\n");
     612               0 :     NaClDescUnref(kern_service->base.bound_and_cap[1]);
     613               0 :     goto done;
     614                 :   }
     615                 : 
     616               0 :   NaClXMutexLock(&nap->mu);
     617               0 :   CHECK(NULL == nap->manifest_proxy);
     618               0 :   CHECK(NULL == nap->kern_service);
     619                 : 
     620               0 :   nap->manifest_proxy = manifest_proxy;
     621               0 :   manifest_proxy = NULL;
     622               0 :   nap->kern_service = kern_service;
     623               0 :   kern_service = NULL;
     624               0 :   NaClXMutexUnlock(&nap->mu);
     625               0 :   rv = 1;
     626                 : 
     627               3 : done:
     628               3 :   NaClXMutexLock(&nap->mu);
     629               3 :   if (NULL != nap->manifest_proxy) {
     630               0 :     NaClLog(3,
     631                 :             ("NaClAppLaunchServiceThreads: adding manifest proxy to"
     632                 :              " name service\n"));
     633               0 :     (*NACL_VTBL(NaClNameService, nap->name_service)->
     634                 :      CreateDescEntry)(nap->name_service,
     635                 :                       "ManifestNameService", NACL_ABI_O_RDWR,
     636                 :                       NaClDescRef(nap->manifest_proxy->base.bound_and_cap[1]));
     637                 :   }
     638               3 :   if (NULL != nap->kern_service) {
     639               3 :     NaClLog(3,
     640                 :             ("NaClAppLaunchServiceThreads: adding kernel service to"
     641                 :              " name service\n"));
     642               3 :     (*NACL_VTBL(NaClNameService, nap->name_service)->
     643                 :      CreateDescEntry)(nap->name_service,
     644                 :                       "KernelService", NACL_ABI_O_RDWR,
     645                 :                       NaClDescRef(nap->kern_service->base.bound_and_cap[1]));
     646                 :   }
     647                 : 
     648               3 :   NaClXMutexUnlock(&nap->mu);
     649                 : 
     650                 :   /*
     651                 :    * Single exit path.
     652                 :    *
     653                 :    * Error cleanup invariant.  No service thread should be running
     654                 :    * (modulo asynchronous shutdown).  Automatic variables refer to
     655                 :    * fully constructed objects if non-NULL, and when ownership is
     656                 :    * transferred to the NaClApp object the corresponding automatic
     657                 :    * variable is set to NULL.
     658                 :    */
     659               3 :   NaClRefCountSafeUnref((struct NaClRefCount *) manifest_proxy);
     660               3 :   NaClRefCountSafeUnref((struct NaClRefCount *) kern_service);
     661               3 :   return rv;
     662                 : }
     663                 : 
     664               3 : int NaClReportExitStatus(struct NaClApp *nap, int exit_status) {
     665                 :   int           rv;
     666                 :   NaClSrpcError rpc_result;
     667                 : 
     668               3 :   NaClXMutexLock(&nap->mu);
     669                 : 
     670               3 :   if (NACL_REVERSE_CHANNEL_INITIALIZED !=
     671                 :       nap->reverse_channel_initialization_state) {
     672               3 :     rv = 0;
     673                 :   } else {
     674               0 :     rpc_result = NaClSrpcInvokeBySignature(&nap->reverse_channel,
     675                 :                                            NACL_REVERSE_CONTROL_REPORT_STATUS,
     676                 :                                            exit_status & 0xff);
     677               0 :     rv = NACL_SRPC_RESULT_OK == rpc_result;
     678                 :     /*
     679                 :      * Due to cross-repository checkins, the Cr-side might not yet
     680                 :      * implement this RPC.  We return whether shutdown was reported.
     681                 :      */
     682                 :   }
     683               3 :   nap->exit_status = exit_status;
     684               3 :   nap->running = 0;
     685               3 :   NaClXCondVarSignal(&nap->cv);
     686                 : 
     687               3 :   NaClXMutexUnlock(&nap->mu);
     688                 : 
     689               3 :   return rv;
     690                 : }
     691                 : 
     692                 : /*
     693                 :  * preconditions:
     694                 :  *  * argc is the length of the argv array
     695                 :  *  * envv may be NULL (this happens on MacOS/Cocoa and in tests)
     696                 :  *  * if envv is non-NULL it is 'consistent', null terminated etc.
     697                 :  */
     698                 : int NaClCreateMainThread(struct NaClApp     *nap,
     699                 :                          int                argc,
     700                 :                          char               **argv,
     701               3 :                          char const *const  *envv) {
     702                 :   /*
     703                 :    * Compute size of string tables for argv and envv
     704                 :    */
     705                 :   int                   retval;
     706                 :   int                   envc;
     707                 :   size_t                size;
     708                 :   int                   auxv_entries;
     709                 :   size_t                ptr_tbl_size;
     710                 :   int                   i;
     711                 :   uint32_t              *p;
     712                 :   char                  *strp;
     713                 :   size_t                *argv_len;
     714                 :   size_t                *envv_len;
     715                 :   struct NaClAppThread  *natp;
     716                 :   uintptr_t             stack_ptr;
     717                 : 
     718               3 :   retval = 0;  /* fail */
     719               3 :   CHECK(argc >= 0);
     720               3 :   CHECK(NULL != argv || 0 == argc);
     721                 : 
     722               3 :   envc = 0;
     723               3 :   if (NULL != envv) {
     724                 :     char const *const *pp;
     725               3 :     for (pp = envv; NULL != *pp; ++pp) {
     726               0 :       ++envc;
     727                 :     }
     728                 :   }
     729               3 :   envv_len = 0;
     730               3 :   argv_len = malloc(argc * sizeof argv_len[0]);
     731               3 :   envv_len = malloc(envc * sizeof envv_len[0]);
     732               3 :   if (NULL == argv_len) {
     733               0 :     goto cleanup;
     734                 :   }
     735               3 :   if (NULL == envv_len && 0 != envc) {
     736               0 :     goto cleanup;
     737                 :   }
     738                 : 
     739               3 :   if (nap->enable_debug_stub) {
     740                 :     /*
     741                 :      * Enable the debug stub.
     742                 :      */
     743               0 :     if (!NaClDebugInit(nap,
     744                 :                        argc, (char const * const *) argv,
     745                 :                        envc, (char const * const *) envv)) {
     746               0 :       goto cleanup;
     747                 :     }
     748                 :   }
     749                 : 
     750               3 :   size = 0;
     751                 : 
     752                 :   /*
     753                 :    * The following two loops cannot overflow.  The reason for this is
     754                 :    * that they are counting the number of bytes used to hold the
     755                 :    * NUL-terminated strings that comprise the argv and envv tables.
     756                 :    * If the entire address space consisted of just those strings, then
     757                 :    * the size variable would overflow; however, since there's the code
     758                 :    * space required to hold the code below (and we are not targetting
     759                 :    * Harvard architecture machines), at least one page holds code, not
     760                 :    * data.  We are assuming that the caller is non-adversarial and the
     761                 :    * code does not look like string data....
     762                 :    */
     763               9 :   for (i = 0; i < argc; ++i) {
     764               6 :     argv_len[i] = strlen(argv[i]) + 1;
     765               6 :     size += argv_len[i];
     766                 :   }
     767               3 :   for (i = 0; i < envc; ++i) {
     768               0 :     envv_len[i] = strlen(envv[i]) + 1;
     769               0 :     size += envv_len[i];
     770                 :   }
     771                 : 
     772                 :   /*
     773                 :    * NaCl modules are ILP32, so the argv, envv pointers, as well as
     774                 :    * the terminating NULL pointers at the end of the argv/envv tables,
     775                 :    * are 32-bit values.  We also have the auxv to take into account.
     776                 :    *
     777                 :    * The argv and envv pointer tables came from trusted code and is
     778                 :    * part of memory.  Thus, by the same argument above, adding in
     779                 :    * "ptr_tbl_size" cannot possibly overflow the "size" variable since
     780                 :    * it is a size_t object.  However, the extra pointers for auxv and
     781                 :    * the space for argv could cause an overflow.  The fact that we
     782                 :    * used stack to get here etc means that ptr_tbl_size could not have
     783                 :    * overflowed.
     784                 :    *
     785                 :    * NB: the underlying OS would have limited the amount of space used
     786                 :    * for argv and envv -- on linux, it is ARG_MAX, or 128KB -- and
     787                 :    * hence the overflow check is for obvious auditability rather than
     788                 :    * for correctness.
     789                 :    */
     790               3 :   auxv_entries = 1;
     791               3 :   if (0 != nap->user_entry_pt) {
     792               0 :     auxv_entries++;
     793                 :   }
     794               3 :   ptr_tbl_size = (((NACL_STACK_GETS_ARG ? 1 : 0) +
     795                 :                    (3 + argc + 1 + envc + 1 + auxv_entries * 2)) *
     796                 :                   sizeof(uint32_t));
     797                 : 
     798               3 :   if (SIZE_T_MAX - size < ptr_tbl_size) {
     799               0 :     NaClLog(LOG_WARNING,
     800                 :             "NaClCreateMainThread: ptr_tbl_size cause size of"
     801                 :             " argv / environment copy to overflow!?!\n");
     802               0 :     retval = 0;
     803               0 :     goto cleanup;
     804                 :   }
     805               3 :   size += ptr_tbl_size;
     806                 : 
     807               3 :   size = (size + NACL_STACK_ALIGN_MASK) & ~NACL_STACK_ALIGN_MASK;
     808                 : 
     809               3 :   if (size > nap->stack_size) {
     810               0 :     retval = 0;
     811               0 :     goto cleanup;
     812                 :   }
     813                 : 
     814                 :   /* write strings and char * arrays to stack */
     815               3 :   stack_ptr = (nap->mem_start + ((uintptr_t) 1U << nap->addr_bits) - size);
     816                 : 
     817               3 :   NaClLog(2, "setting stack to : %016"NACL_PRIxPTR"\n", stack_ptr);
     818                 : 
     819               3 :   VCHECK(0 == (stack_ptr & NACL_STACK_ALIGN_MASK),
     820                 :          ("stack_ptr not aligned: %016"NACL_PRIxPTR"\n", stack_ptr));
     821                 : 
     822               3 :   p = (uint32_t *) stack_ptr;
     823               3 :   strp = (char *) stack_ptr + ptr_tbl_size;
     824                 : 
     825                 :   /*
     826                 :    * For x86-32, we push an initial argument that is the address of
     827                 :    * the main argument block.  For other machines, this is passed
     828                 :    * in a register and that's set in NaClStartThreadInApp.
     829                 :    */
     830                 :   if (NACL_STACK_GETS_ARG) {
     831               3 :     uint32_t *argloc = p++;
     832               3 :     *argloc = (uint32_t) NaClSysToUser(nap, (uintptr_t) p);
     833                 :   }
     834                 : 
     835               3 :   *p++ = 0;  /* Cleanup function pointer, always NULL.  */
     836               3 :   *p++ = envc;
     837               3 :   *p++ = argc;
     838                 : 
     839               9 :   for (i = 0; i < argc; ++i) {
     840               6 :     *p++ = (uint32_t) NaClSysToUser(nap, (uintptr_t) strp);
     841               6 :     NaClLog(2, "copying arg %d  %p -> %p\n",
     842                 :             i, argv[i], strp);
     843               6 :     strcpy(strp, argv[i]);
     844               6 :     strp += argv_len[i];
     845                 :   }
     846               3 :   *p++ = 0;  /* argv[argc] is NULL.  */
     847                 : 
     848               3 :   for (i = 0; i < envc; ++i) {
     849               0 :     *p++ = (uint32_t) NaClSysToUser(nap, (uintptr_t) strp);
     850               0 :     NaClLog(2, "copying env %d  %p -> %p\n",
     851                 :             i, envv[i], strp);
     852               0 :     strcpy(strp, envv[i]);
     853               0 :     strp += envv_len[i];
     854                 :   }
     855               3 :   *p++ = 0;  /* envp[envc] is NULL.  */
     856                 : 
     857                 :   /* Push an auxv */
     858               3 :   if (0 != nap->user_entry_pt) {
     859               0 :     *p++ = AT_ENTRY;
     860               0 :     *p++ = (uint32_t) nap->user_entry_pt;
     861                 :   }
     862               3 :   *p++ = AT_NULL;
     863               3 :   *p++ = 0;
     864                 : 
     865               3 :   CHECK((char *) p == (char *) stack_ptr + ptr_tbl_size);
     866                 : 
     867                 :   /* now actually spawn the thread */
     868               3 :   natp = malloc(sizeof *natp);
     869               3 :   if (!natp) {
     870               0 :     goto cleanup;
     871                 :   }
     872                 : 
     873                 :   /* NaClApp initialization is completed, call OOP debugger hook. */
     874               3 :   NaClOopDebuggerAppCreateHook(nap);
     875                 : 
     876               3 :   NaClXMutexLock(&nap->mu);
     877               3 :   nap->running = 1;
     878               3 :   NaClXMutexUnlock(&nap->mu);
     879                 : 
     880               3 :   NaClVmHoleWaitToStartThread(nap);
     881                 : 
     882                 :   /*
     883                 :    * For x86, we adjust the stack pointer down to push a dummy return
     884                 :    * address.  This happens after the stack pointer alignment.
     885                 :    * We avoid the otherwise harmless call for the zero case because
     886                 :    * _FORTIFY_SOURCE memset can warn about zero-length calls.
     887                 :    */
     888                 :   if (NACL_STACK_PAD_BELOW_ALIGN != 0) {
     889               3 :     stack_ptr -= NACL_STACK_PAD_BELOW_ALIGN;
     890               3 :     memset((void *) stack_ptr, 0, NACL_STACK_PAD_BELOW_ALIGN);
     891                 :   }
     892                 : 
     893               3 :   NaClLog(2, "system stack ptr : %016"NACL_PRIxPTR"\n", stack_ptr);
     894               3 :   NaClLog(2, "  user stack ptr : %016"NACL_PRIxPTR"\n",
     895                 :           NaClSysToUserStackAddr(nap, stack_ptr));
     896                 : 
     897                 :   /* e_entry is user addr */
     898               3 :   if (!NaClAppThreadAllocSegCtor(natp,
     899                 :                                  nap,
     900                 :                                  nap->initial_entry_pt,
     901                 :                                  NaClSysToUserStackAddr(nap, stack_ptr),
     902                 :                                  NaClUserToSys(nap, nap->break_addr),
     903                 :                                  0)) {
     904               0 :     retval = 0;
     905               0 :     goto cleanup;
     906                 :   }
     907                 : 
     908               3 :   retval = 1;
     909               3 : cleanup:
     910               3 :   free(argv_len);
     911               3 :   free(envv_len);
     912                 : 
     913               3 :   return retval;
     914                 : }
     915                 : 
     916               3 : int NaClWaitForMainThreadToExit(struct NaClApp  *nap) {
     917               3 :   NaClLog(3, "NaClWaitForMainThreadToExit: taking NaClApp lock\n");
     918               3 :   NaClXMutexLock(&nap->mu);
     919               3 :   NaClLog(3, " waiting for exit status\n");
     920              16 :   while (nap->running) {
     921              10 :     NaClXCondVarWait(&nap->cv, &nap->mu);
     922              10 :     NaClLog(3, " wakeup, nap->running %d, nap->exit_status %d\n",
     923                 :             nap->running, nap->exit_status);
     924                 :   }
     925               3 :   NaClXMutexUnlock(&nap->mu);
     926                 :   /*
     927                 :    * Some thread invoked the exit (exit_group) syscall.
     928                 :    */
     929                 : 
     930               3 :   if (NULL != nap->debug_stub_callbacks) {
     931               0 :     nap->debug_stub_callbacks->process_exit_hook(nap->exit_status);
     932                 :   }
     933                 : 
     934               3 :   NaClOopDebuggerAppExitHook(nap->exit_status);
     935                 : 
     936               3 :   return (nap->exit_status);
     937                 : }
     938                 : 
     939                 : /*
     940                 :  * stack_ptr is from syscall, so a 32-bit address.
     941                 :  */
     942                 : int32_t NaClCreateAdditionalThread(struct NaClApp *nap,
     943                 :                                    uintptr_t      prog_ctr,
     944                 :                                    uintptr_t      sys_stack_ptr,
     945                 :                                    uintptr_t      sys_tls,
     946               0 :                                    uint32_t       user_tls2) {
     947                 :   struct NaClAppThread  *natp;
     948                 :   uintptr_t             stack_ptr;
     949                 : 
     950               0 :   natp = malloc(sizeof *natp);
     951               0 :   if (NULL == natp) {
     952               0 :     NaClLog(LOG_WARNING,
     953                 :             ("NaClCreateAdditionalThread: no memory for new thread context."
     954                 :              "  Returning EAGAIN per POSIX specs.\n"));
     955               0 :     return -NACL_ABI_EAGAIN;
     956                 :   }
     957                 : 
     958               0 :   stack_ptr = NaClSysToUserStackAddr(nap, sys_stack_ptr);
     959                 : 
     960               0 :   if (0 != ((stack_ptr + sizeof(nacl_reg_t)) & NACL_STACK_ALIGN_MASK)) {
     961               0 :     NaClLog(3,
     962                 :             ("NaClCreateAdditionalThread:  user thread library provided "
     963                 :              "an unaligned user stack pointer: 0x%"NACL_PRIxPTR"\n"),
     964                 :             stack_ptr);
     965                 :   }
     966                 : 
     967               0 :   if (!NaClAppThreadAllocSegCtor(natp,
     968                 :                                  nap,
     969                 :                                  prog_ctr,
     970                 :                                  stack_ptr,
     971                 :                                  sys_tls,
     972                 :                                  user_tls2)) {
     973               0 :     NaClLog(LOG_WARNING,
     974                 :             ("NaClCreateAdditionalThread: could not allocate thread index."
     975                 :              "  Returning EAGAIN per POSIX specs.\n"));
     976               0 :     free(natp);
     977               0 :     return -NACL_ABI_EAGAIN;
     978                 :   }
     979               0 :   return 0;
     980                 : }

Generated by: LCOV version 1.7