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

       1                 : /*
       2                 :  * Copyright (c) 2012 The Native Client Authors. All rights reserved.
       3                 :  * Use of this source code is governed by a BSD-style license that can be
       4                 :  * found in the LICENSE file.
       5                 :  */
       6                 : 
       7                 : /*
       8                 :  * NaCl service run-time, non-platform specific system call helper routines.
       9                 :  */
      10                 : #include <sys/types.h>
      11                 : #include <sys/stat.h>
      12                 : 
      13                 : #include <stdio.h>
      14                 : 
      15                 : #include "native_client/src/trusted/service_runtime/nacl_syscall_common.h"
      16                 : 
      17                 : #include "native_client/src/include/nacl_assert.h"
      18                 : #include "native_client/src/include/nacl_macros.h"
      19                 : #include "native_client/src/include/nacl_platform.h"
      20                 : #include "native_client/src/include/portability_string.h"
      21                 : 
      22                 : #include "native_client/src/shared/platform/nacl_clock.h"
      23                 : #include "native_client/src/shared/platform/nacl_exit.h"
      24                 : #include "native_client/src/shared/platform/nacl_host_desc.h"
      25                 : #include "native_client/src/shared/platform/nacl_host_dir.h"
      26                 : #include "native_client/src/shared/platform/nacl_sync_checked.h"
      27                 : 
      28                 : #include "native_client/src/trusted/desc/nacl_desc_base.h"
      29                 : #include "native_client/src/trusted/desc/nacl_desc_cond.h"
      30                 : #include "native_client/src/trusted/desc/nacl_desc_dir.h"
      31                 : #include "native_client/src/trusted/desc/nacl_desc_imc.h"
      32                 : #include "native_client/src/trusted/desc/nacl_desc_imc_shm.h"
      33                 : #include "native_client/src/trusted/desc/nacl_desc_invalid.h"
      34                 : #include "native_client/src/trusted/desc/nacl_desc_io.h"
      35                 : #include "native_client/src/trusted/desc/nacl_desc_mutex.h"
      36                 : #include "native_client/src/trusted/desc/nacl_desc_semaphore.h"
      37                 : #include "native_client/src/trusted/desc/nrd_xfer.h"
      38                 : 
      39                 : #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
      40                 : #include "native_client/src/trusted/service_runtime/include/sys/stat.h"
      41                 : #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
      42                 : #include "native_client/src/trusted/service_runtime/nacl_thread_nice.h"
      43                 : #include "native_client/src/trusted/service_runtime/nacl_globals.h"
      44                 : #include "native_client/src/trusted/service_runtime/nacl_tls.h"
      45                 : #include "native_client/src/trusted/service_runtime/sel_ldr.h"
      46                 : #include "native_client/src/trusted/service_runtime/sel_memory.h"
      47                 : 
      48                 : #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
      49                 : #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
      50                 : #include "native_client/src/trusted/service_runtime/include/sys/mman.h"
      51                 : #include "native_client/src/trusted/service_runtime/include/sys/stat.h"
      52                 : 
      53                 : 
      54                 : struct NaClDescQuotaInterface;
      55                 : 
      56                 : /*
      57                 :  * OSX defines SIZE_T_MAX in i386/limits.h; Linux has SIZE_MAX;
      58                 :  * Windows has none.
      59                 :  *
      60                 :  * TODO(bsy): remove when we put SIZE_T_MAX in a common header file.
      61                 :  */
      62                 : #if !defined(SIZE_T_MAX)
      63                 : # define SIZE_T_MAX   (~(size_t) 0)
      64                 : #endif
      65                 : 
      66                 : static const size_t kMaxUsableFileSize = (SIZE_T_MAX >> 1);
      67                 : 
      68               9 : static INLINE size_t  size_min(size_t a, size_t b) {
      69               9 :   return (a < b) ? a : b;
      70                 : }
      71                 : 
      72                 : static int const kKnownInvalidDescNumber = -1;
      73                 : 
      74             251 : void NaClSysCommonThreadSyscallEnter(struct NaClAppThread *natp) {
      75                 :   UNREFERENCED_PARAMETER(natp);
      76             251 : }
      77                 : 
      78             248 : void NaClSysCommonThreadSyscallLeave(struct NaClAppThread *natp) {
      79             248 :   NaClXMutexLock(&natp->mu);
      80             248 :   switch (natp->state) {
      81                 :     case NACL_APP_THREAD_ALIVE:
      82             248 :       break;
      83                 :     case NACL_APP_THREAD_SUICIDE_PENDING:
      84               0 :       NaClXMutexUnlock(&natp->mu);
      85               0 :       NaClAppThreadTeardown(natp);
      86                 :       /* NOTREACHED */
      87               0 :       break;
      88                 :     case NACL_APP_THREAD_DEAD:
      89               0 :       NaClLog(LOG_FATAL, "Dead thread at NaClSysCommonThreadSyscallLeave\n");
      90                 :       /* NOTREACHED */
      91                 :       break;
      92                 :   }
      93             248 :   NaClXMutexUnlock(&natp->mu);
      94             248 : }
      95                 : 
      96                 : int32_t NaClSetBreak(struct NaClAppThread *natp,
      97              10 :                      uintptr_t            new_break) {
      98                 :   struct NaClApp        *nap;
      99                 :   uintptr_t             break_addr;
     100              10 :   int32_t               rv = -NACL_ABI_EINVAL;
     101                 :   struct NaClVmmapIter  iter;
     102                 :   struct NaClVmmapEntry *ent;
     103                 :   struct NaClVmmapEntry *next_ent;
     104                 :   uintptr_t             sys_break;
     105                 :   uintptr_t             sys_new_break;
     106                 :   uintptr_t             usr_last_data_page;
     107                 :   uintptr_t             usr_new_last_data_page;
     108                 :   uintptr_t             last_internal_data_addr;
     109                 :   uintptr_t             last_internal_page;
     110                 :   uintptr_t             start_new_region;
     111                 :   uintptr_t             region_size;
     112                 : 
     113              10 :   nap = natp->nap;
     114              10 :   break_addr = nap->break_addr;
     115                 : 
     116              10 :   NaClLog(3, "Entered NaClSetBreak(new_break 0x%08"NACL_PRIxPTR")\n",
     117                 :           new_break);
     118                 : 
     119              10 :   NaClSysCommonThreadSyscallEnter(natp);
     120                 : 
     121              10 :   sys_new_break = NaClUserToSysAddr(natp->nap, new_break);
     122              10 :   NaClLog(3, "sys_new_break 0x%08"NACL_PRIxPTR"\n", sys_new_break);
     123                 : 
     124              10 :   if (kNaClBadAddress == sys_new_break) {
     125               3 :     goto cleanup_no_lock;
     126                 :   }
     127               7 :   if (NACL_SYNC_OK != NaClMutexLock(&nap->mu)) {
     128               0 :     NaClLog(LOG_ERROR, "Could not get app lock for 0x%08"NACL_PRIxPTR"\n",
     129                 :             (uintptr_t) nap);
     130               0 :     goto cleanup_no_lock;
     131                 :   }
     132               7 :   if (new_break < nap->data_end) {
     133               0 :     NaClLog(4, "new_break before data_end (0x%"NACL_PRIxPTR")\n",
     134                 :             nap->data_end);
     135               0 :     goto cleanup;
     136                 :   }
     137               7 :   if (new_break <= nap->break_addr) {
     138                 :     /* freeing memory */
     139               0 :     NaClLog(4, "new_break before break (0x%"NACL_PRIxPTR"); freeing\n",
     140                 :             nap->break_addr);
     141               0 :     nap->break_addr = new_break;
     142               0 :     break_addr = new_break;
     143                 :   } else {
     144                 :     /*
     145                 :      * See if page containing new_break is in mem_map; if so, we are
     146                 :      * essentially done -- just update break_addr.  Otherwise, we
     147                 :      * extend the VM map entry from the page containing the current
     148                 :      * break to the page containing new_break.
     149                 :      */
     150                 : 
     151               7 :     sys_break = NaClUserToSys(nap, nap->break_addr);
     152                 : 
     153               7 :     usr_last_data_page = (nap->break_addr - 1) >> NACL_PAGESHIFT;
     154                 : 
     155               7 :     usr_new_last_data_page = (new_break - 1) >> NACL_PAGESHIFT;
     156                 : 
     157               7 :     last_internal_data_addr = NaClRoundAllocPage(new_break) - 1;
     158               7 :     last_internal_page = last_internal_data_addr >> NACL_PAGESHIFT;
     159                 : 
     160               7 :     NaClLog(4, ("current break sys addr 0x%08"NACL_PRIxPTR", "
     161                 :                 "usr last data page 0x%"NACL_PRIxPTR"\n"),
     162                 :             sys_break, usr_last_data_page);
     163               7 :     NaClLog(4, "new break usr last data page 0x%"NACL_PRIxPTR"\n",
     164                 :             usr_new_last_data_page);
     165               7 :     NaClLog(4, "last internal data addr 0x%08"NACL_PRIxPTR"\n",
     166                 :             last_internal_data_addr);
     167                 : 
     168               7 :     if (NULL == NaClVmmapFindPageIter(&nap->mem_map,
     169                 :                                       usr_last_data_page,
     170                 :                                       &iter)
     171                 :         || NaClVmmapIterAtEnd(&iter)) {
     172               0 :       NaClLog(LOG_FATAL, ("current break (0x%08"NACL_PRIxPTR", "
     173                 :                           "sys 0x%08"NACL_PRIxPTR") "
     174                 :                           "not in address map\n"),
     175                 :               nap->break_addr, sys_break);
     176                 :     }
     177               7 :     ent = NaClVmmapIterStar(&iter);
     178               7 :     NaClLog(4, ("segment containing current break"
     179                 :                 ": page_num 0x%08"NACL_PRIxPTR", npages 0x%"NACL_PRIxS"\n"),
     180                 :             ent->page_num, ent->npages);
     181               7 :     if (usr_new_last_data_page < ent->page_num + ent->npages) {
     182               6 :       NaClLog(4, "new break within break segment, just bumping addr\n");
     183               6 :       nap->break_addr = new_break;
     184               6 :       break_addr = new_break;
     185                 :     } else {
     186               1 :       NaClVmmapIterIncr(&iter);
     187               1 :       if (!NaClVmmapIterAtEnd(&iter)
     188                 :           && ((next_ent = NaClVmmapIterStar(&iter))->page_num
     189                 :               <= last_internal_page)) {
     190                 :         /* ran into next segment! */
     191               0 :         NaClLog(4,
     192                 :                 ("new break request of usr address "
     193                 :                  "0x%08"NACL_PRIxPTR" / usr page 0x%"NACL_PRIxPTR
     194                 :                  " runs into next region, page_num 0x%"NACL_PRIxPTR", "
     195                 :                  "npages 0x%"NACL_PRIxS"\n"),
     196                 :                 new_break, usr_new_last_data_page,
     197                 :                 next_ent->page_num, next_ent->npages);
     198               0 :         goto cleanup;
     199                 :       }
     200               1 :       NaClLog(4,
     201                 :               "extending segment: page_num 0x%08"NACL_PRIxPTR", "
     202                 :               "npages 0x%"NACL_PRIxS"\n",
     203                 :               ent->page_num, ent->npages);
     204                 :       /* go ahead and extend ent to cover, and make pages accessible */
     205               1 :       start_new_region = (ent->page_num + ent->npages) << NACL_PAGESHIFT;
     206               1 :       ent->npages = (last_internal_page - ent->page_num + 1);
     207               1 :       region_size = (((last_internal_page + 1) << NACL_PAGESHIFT)
     208                 :                      - start_new_region);
     209               1 :       if (0 != NaCl_mprotect((void *) NaClUserToSys(nap, start_new_region),
     210                 :                              region_size,
     211                 :                              PROT_READ | PROT_WRITE)) {
     212               0 :         NaClLog(LOG_FATAL,
     213                 :                 ("Could not mprotect(0x%08"NACL_PRIxPTR", "
     214                 :                  "0x%08"NACL_PRIxPTR", "
     215                 :                  "PROT_READ|PROT_WRITE)\n"),
     216                 :                 start_new_region,
     217                 :                 region_size);
     218                 :       }
     219               1 :       NaClLog(4, "segment now: page_num 0x%08"NACL_PRIxPTR", "
     220                 :               "npages 0x%"NACL_PRIxS"\n",
     221                 :               ent->page_num, ent->npages);
     222               1 :       nap->break_addr = new_break;
     223               1 :       break_addr = new_break;
     224                 :     }
     225                 :     /*
     226                 :      * Zero out memory between old break and new break.
     227                 :      */
     228               7 :     ASSERT(sys_new_break > sys_break);
     229               7 :     memset((void *) sys_break, 0, sys_new_break - sys_break);
     230                 :   }
     231                 : 
     232                 : 
     233                 : 
     234               7 : cleanup:
     235               7 :   NaClXMutexUnlock(&nap->mu);
     236              10 : cleanup_no_lock:
     237              10 :   NaClSysCommonThreadSyscallLeave(natp);
     238                 : 
     239                 :   /*
     240                 :    * This cast is safe because the incoming value (new_break) cannot
     241                 :    * exceed the user address space--even though its type (uintptr_t)
     242                 :    * theoretically allows larger values.
     243                 :    */
     244              10 :   rv = (int32_t) break_addr;
     245                 : 
     246              10 :   NaClLog(3, "NaClSetBreak: returning 0x%08"NACL_PRIx32"\n", rv);
     247              10 :   return rv;
     248                 : }
     249                 : 
     250                 : int NaClAclBypassChecks = 0;
     251                 : 
     252               3 : void NaClInsecurelyBypassAllAclChecks(void) {
     253               3 :   NaClLog(LOG_WARNING, "BYPASSING ALL ACL CHECKS\n");
     254               3 :   NaClAclBypassChecks = 1;
     255               3 : }
     256                 : 
     257               1 : int NaClHighResolutionTimerEnabled() {
     258               1 :   return NaClAclBypassChecks;
     259                 : }
     260                 : 
     261                 : /*
     262                 :  * NaClOpenAclCheck: Is the NaCl app authorized to open this file?  The
     263                 :  * return value is syscall return convention, so 0 is success and
     264                 :  * small negative numbers are negated errno values.
     265                 :  */
     266                 : int32_t NaClOpenAclCheck(struct NaClApp *nap,
     267                 :                          char const     *path,
     268                 :                          int            flags,
     269              16 :                          int            mode) {
     270                 :   /*
     271                 :    * TODO(bsy): provide some minimal authorization check, based on
     272                 :    * whether a debug flag is set; eventually provide a data-driven
     273                 :    * authorization configuration mechanism, perhaps persisted via
     274                 :    * gears.  need GUI for user configuration, as well as designing an
     275                 :    * appropriate language (with sufficient expressiveness), however.
     276                 :    */
     277              16 :   NaClLog(1, "NaClOpenAclCheck(0x%08"NACL_PRIxPTR", %s, 0%o, 0%o)\n",
     278                 :           (uintptr_t) nap, path, flags, mode);
     279              16 :   if (3 < NaClLogGetVerbosity()) {
     280               0 :     NaClLog(0, "O_ACCMODE: 0%o\n", flags & NACL_ABI_O_ACCMODE);
     281               0 :     NaClLog(0, "O_RDONLY = %d\n", NACL_ABI_O_RDONLY);
     282               0 :     NaClLog(0, "O_WRONLY = %d\n", NACL_ABI_O_WRONLY);
     283               0 :     NaClLog(0, "O_RDWR   = %d\n", NACL_ABI_O_RDWR);
     284                 : #define FLOG(VAR, BIT) do {\
     285                 :       NaClLog(1, "%s: %s\n", #BIT, (VAR & BIT) ? "yes" : "no");\
     286                 :     } while (0)
     287               0 :     FLOG(flags, NACL_ABI_O_CREAT);
     288               0 :     FLOG(flags, NACL_ABI_O_TRUNC);
     289               0 :     FLOG(flags, NACL_ABI_O_APPEND);
     290                 : #undef FLOG
     291                 :   }
     292              16 :   if (NaClAclBypassChecks) {
     293              16 :     return 0;
     294                 :   }
     295               0 :   return -NACL_ABI_EACCES;
     296                 : }
     297                 : 
     298                 : /*
     299                 :  * NaClStatAclCheck: Is the NaCl app authorized to stat this pathname?  The
     300                 :  * return value is syscall return convention, so 0 is success and
     301                 :  * small negative numbers are negated errno values.
     302                 :  *
     303                 :  * This is primarily for debug use.  File access should be through
     304                 :  * SRPC-based file servers.
     305                 :  */
     306                 : int32_t NaClStatAclCheck(struct NaClApp *nap,
     307               0 :                          char const     *path) {
     308               0 :   NaClLog(2,
     309                 :           "NaClStatAclCheck(0x%08"NACL_PRIxPTR", %s)\n", (uintptr_t) nap, path);
     310               0 :   if (NaClAclBypassChecks) {
     311               0 :     return 0;
     312                 :   }
     313               0 :   return -NACL_ABI_EACCES;
     314                 : }
     315                 : 
     316                 : int32_t NaClIoctlAclCheck(struct NaClApp  *nap,
     317                 :                           struct NaClDesc *ndp,
     318                 :                           int             request,
     319               0 :                           void            *arg) {
     320               0 :   NaClLog(2,
     321                 :           ("NaClIoctlAclCheck(0x%08"NACL_PRIxPTR", 0x%08"NACL_PRIxPTR","
     322                 :            " %d, 0x%08"NACL_PRIxPTR"\n"),
     323                 :           (uintptr_t) nap, (uintptr_t) ndp, request, (uintptr_t) arg);
     324               0 :   if (NaClAclBypassChecks) {
     325               0 :     return 0;
     326                 :   }
     327               0 :   return -NACL_ABI_EINVAL;
     328                 : }
     329                 : 
     330                 : int32_t NaClCommonSysExit(struct NaClAppThread  *natp,
     331               3 :                           int                   status) {
     332                 :   struct NaClApp            *nap;
     333                 : 
     334               3 :   NaClLog(1, "Exit syscall handler: %d\n", status);
     335               3 :   NaClSysCommonThreadSyscallEnter(natp);
     336                 : 
     337               3 :   nap = natp->nap;
     338                 : 
     339               3 :   (void) NaClReportExitStatus(nap, status);
     340                 : 
     341               3 :   NaClAppThreadTeardown(natp);
     342                 :   /* NOTREACHED */
     343               0 :   return -NACL_ABI_EINVAL;
     344                 : }
     345                 : 
     346                 : int32_t NaClCommonSysThreadExit(struct NaClAppThread  *natp,
     347               0 :                                 int32_t               *stack_flag) {
     348                 :   uintptr_t sys_stack_flag;
     349                 : 
     350               0 :   NaClLog(4, "NaclCommonSysThreadExit(0x%08"NACL_PRIxPTR", "
     351                 :           "0x%08"NACL_PRIxPTR"\n",
     352                 :           (uintptr_t) natp,
     353                 :           (uintptr_t) stack_flag);
     354               0 :   NaClSysCommonThreadSyscallEnter(natp);
     355                 :   /*
     356                 :    * NB: NaClThreads are never joinable, but the abstraction for NaClApps
     357                 :    * are.
     358                 :    */
     359                 : 
     360               0 :   if (NULL != stack_flag) {
     361               0 :     NaClLog(4,
     362                 :             "NaClCommonSysThreadExit: stack_flag is %"NACL_PRIxPTR"\n",
     363                 :             (uintptr_t) stack_flag);
     364               0 :     sys_stack_flag = NaClUserToSysAddrRange(natp->nap,
     365                 :                                             (uintptr_t) stack_flag,
     366                 :                                             sizeof(int32_t));
     367               0 :     NaClLog(4,
     368                 :             "NaClCommonSysThreadExit: sys_stack_flag is %"NACL_PRIxPTR"\n",
     369                 :             sys_stack_flag);
     370               0 :     if (kNaClBadAddress != sys_stack_flag) {
     371                 :       /*
     372                 :        * We don't return failure if the address is illegal because
     373                 :        * this function is not supposed to return.
     374                 :        */
     375               0 :       NaClLog(4,
     376                 :               "NaClCommonSysThreadExit: clearing stack flag\n");
     377               0 :       *(volatile int32_t *) sys_stack_flag = 0;
     378                 :     }
     379                 :   }
     380                 : 
     381               0 :   NaClAppThreadTeardown(natp);
     382                 :   /* NOTREACHED */
     383               0 :   return -NACL_ABI_EINVAL;
     384                 : }
     385                 : 
     386                 : int32_t NaClCommonSysNameService(struct NaClAppThread *natp,
     387               0 :                                  int32_t              *desc_addr) {
     388               0 :   int32_t   retval = -NACL_ABI_EINVAL;
     389                 :   uintptr_t sysaddr;
     390                 :   int32_t   desc;
     391                 : 
     392               0 :   NaClLog(3,
     393                 :           ("NaClCommonSysNameService(0x%08"NACL_PRIxPTR","
     394                 :            " 0x%08"NACL_PRIxPTR")\n"),
     395                 :           (uintptr_t) natp,
     396                 :           (uintptr_t) desc_addr);
     397               0 :   NaClSysCommonThreadSyscallEnter(natp);
     398                 : 
     399               0 :   sysaddr = NaClUserToSysAddrRange(natp->nap,
     400                 :                                    (uintptr_t) desc_addr,
     401                 :                                    sizeof(uint32_t));
     402               0 :   if (kNaClBadAddress == sysaddr) {
     403               0 :     NaClLog(LOG_ERROR,
     404                 :             "Invalid address argument to NaClCommonSysNameService\n");
     405               0 :     retval = -NACL_ABI_EFAULT;
     406               0 :     goto done;
     407                 :   }
     408                 : 
     409               0 :   desc = *(int32_t volatile *) sysaddr;
     410               0 :   if (-1 == desc) {
     411                 :     /* read */
     412               0 :     desc = NaClSetAvail(natp->nap,
     413                 :                         NaClDescRef(natp->nap->name_service_conn_cap));
     414               0 :     *(int32_t volatile *) sysaddr = desc;
     415               0 :     retval = 0;
     416                 :   } else {
     417               0 :     struct NaClDesc *desc_obj_ptr = NaClGetDesc(natp->nap, desc);
     418                 : 
     419               0 :     if (NULL == desc_obj_ptr) {
     420               0 :       retval = -NACL_ABI_EBADF;
     421               0 :       goto done;
     422                 :     }
     423               0 :     if (NACL_DESC_CONN_CAP != NACL_VTBL(NaClDesc, desc_obj_ptr)->typeTag &&
     424                 :         NACL_DESC_CONN_CAP_FD != NACL_VTBL(NaClDesc, desc_obj_ptr)->typeTag) {
     425               0 :       retval = -NACL_ABI_EINVAL;
     426               0 :       goto done;
     427                 :     }
     428                 :     /* write */
     429               0 :     NaClXMutexLock(&natp->nap->mu);
     430               0 :     NaClDescUnref(natp->nap->name_service_conn_cap);
     431               0 :     natp->nap->name_service_conn_cap = desc_obj_ptr;
     432               0 :     NaClXMutexUnlock(&natp->nap->mu);
     433               0 :     retval = 0;
     434                 :   }
     435                 : 
     436               0 :  done:
     437               0 :   NaClSysCommonThreadSyscallLeave(natp);
     438               0 :   return retval;
     439                 : }
     440                 : 
     441                 : int32_t NaClCommonSysDup(struct NaClAppThread *natp,
     442               0 :                          int                  oldfd) {
     443                 :   int             retval;
     444                 :   struct NaClDesc *old_nd;
     445                 : 
     446               0 :   NaClLog(3, "NaClCommonSysDup(0x%08"NACL_PRIxPTR", %d)\n",
     447                 :           (uintptr_t) natp, oldfd);
     448               0 :   NaClSysCommonThreadSyscallEnter(natp);
     449               0 :   old_nd = NaClGetDesc(natp->nap, oldfd);
     450               0 :   if (NULL == old_nd) {
     451               0 :     retval = -NACL_ABI_EBADF;
     452               0 :     goto done;
     453                 :   }
     454               0 :   retval = NaClSetAvail(natp->nap, old_nd);
     455               0 : done:
     456               0 :   NaClSysCommonThreadSyscallLeave(natp);
     457               0 :   return retval;
     458                 : }
     459                 : 
     460                 : int32_t NaClCommonSysDup2(struct NaClAppThread  *natp,
     461                 :                           int                   oldfd,
     462               0 :                           int                   newfd) {
     463                 :   int             retval;
     464                 :   struct NaClDesc *old_nd;
     465                 : 
     466               0 :   NaClLog(3, "NaClCommonSysDup(0x%08"NACL_PRIxPTR", %d, %d)\n",
     467                 :           (uintptr_t) natp, oldfd, newfd);
     468               0 :   NaClSysCommonThreadSyscallEnter(natp);
     469               0 :   if (newfd < 0) {
     470               0 :     retval = -NACL_ABI_EINVAL;
     471               0 :     goto done;
     472                 :   }
     473                 :   /*
     474                 :    * TODO(bsy): is this a reasonable largest sane value?  The
     475                 :    * descriptor array shouldn't get too large.
     476                 :    */
     477               0 :   if (newfd >= NACL_MAX_FD) {
     478               0 :     retval = -NACL_ABI_EINVAL;
     479               0 :     goto done;
     480                 :   }
     481               0 :   old_nd = NaClGetDesc(natp->nap, oldfd);
     482               0 :   if (NULL == old_nd) {
     483               0 :     retval = -NACL_ABI_EBADF;
     484               0 :     goto done;
     485                 :   }
     486               0 :   NaClSetDesc(natp->nap, newfd, old_nd);
     487               0 :   retval = newfd;
     488               0 : done:
     489               0 :   NaClSysCommonThreadSyscallLeave(natp);
     490               0 :   return retval;
     491                 : }
     492                 : 
     493                 : int32_t NaClCommonSysOpen(struct NaClAppThread  *natp,
     494                 :                           char                  *pathname,
     495                 :                           int                   flags,
     496              16 :                           int                   mode) {
     497              16 :   uint32_t             retval = -NACL_ABI_EINVAL;
     498                 :   uintptr_t            sysaddr;
     499                 :   char                 path[NACL_CONFIG_PATH_MAX];
     500                 :   size_t               len;
     501                 :   nacl_host_stat_t     stbuf;
     502                 :   int                  allowed_flags;
     503                 : 
     504              16 :   NaClLog(3, "NaClCommonSysOpen(0x%08"NACL_PRIxPTR", "
     505                 :           "0x%08"NACL_PRIxPTR", 0x%x, 0x%x)\n",
     506                 :           (uintptr_t) natp, (uintptr_t) pathname, flags, mode);
     507                 : 
     508              16 :   NaClSysCommonThreadSyscallEnter(natp);
     509                 : 
     510              16 :   sysaddr = NaClUserToSysAddr(natp->nap, (uintptr_t) pathname);
     511              16 :   if (kNaClBadAddress == sysaddr) {
     512               0 :     NaClLog(LOG_ERROR, "Invalid address for pathname\n");
     513               0 :     retval = -NACL_ABI_EFAULT;
     514               0 :     goto cleanup;
     515                 :   }
     516              16 :   allowed_flags = (NACL_ABI_O_ACCMODE | NACL_ABI_O_CREAT
     517                 :                    | NACL_ABI_O_TRUNC | NACL_ABI_O_APPEND);
     518              16 :   if (0 != (flags & ~allowed_flags)) {
     519               0 :     NaClLog(LOG_WARNING, "Invalid open flags 0%o, ignoring extraneous bits\n",
     520                 :             flags);
     521               0 :     flags &= allowed_flags;
     522                 :   }
     523              16 :   if (0 != (mode & ~0600)) {
     524               0 :     NaClLog(1, "IGNORING Invalid access mode bits 0%o\n", mode);
     525               0 :     mode &= 0600;
     526                 :   }
     527              16 :   NaClLog(4, " attempting to copy path via sysaddr 0x%08"NACL_PRIxPTR
     528                 :           "\n", sysaddr);
     529              16 :   NaClLog(4, " first 4 bytes: %.4s\n", (char *) sysaddr);
     530                 :   /*
     531                 :    * strncpy may (try to) get bytes that is outside the app's address
     532                 :    * space and generate a fault.
     533                 :    */
     534              16 :   strncpy(path, (char *) sysaddr, sizeof path);
     535                 :   /*
     536                 :    * survived the copy, but did there happen to be data beyond the end?
     537                 :    */
     538              16 :   path[sizeof path - 1] = '\0';  /* always null terminate */
     539              16 :   NaClLog(1, "NaClSysOpen: Path: %s\n", path);
     540              16 :   len = strlen(path);
     541                 :   /*
     542                 :    * make sure sysaddr is a string, and the whole string is in app
     543                 :    * address space...
     544                 :    *
     545                 :    * address space is convex, so it is impossible for beginning and
     546                 :    * end to be both in the address space and yet have an intermediate
     547                 :    * byte not be in the address space.
     548                 :    */
     549              16 :   if (kNaClBadAddress == NaClUserToSysAddr(natp->nap,
     550                 :                                            len + (uintptr_t) pathname)) {
     551               0 :     NaClLog(LOG_ERROR, "String ends outside addrspace\n");
     552               0 :     retval = -NACL_ABI_EFAULT;
     553               0 :     goto cleanup;
     554                 :   }
     555                 : 
     556              16 :   retval = NaClOpenAclCheck(natp->nap, path, flags, mode);
     557              16 :   if (0 != retval) {
     558               0 :     NaClLog(3, "Open ACL check rejected \"%s\".\n", path);
     559               0 :     goto cleanup;
     560                 :   }
     561                 : 
     562                 :   /*
     563                 :    * Perform a stat to determine whether the file is a directory.
     564                 :    *
     565                 :    * NB: it is okay for the stat to fail, since the request may be to
     566                 :    * create a new file.
     567                 :    *
     568                 :    * There is a race conditions here: between the stat and the
     569                 :    * open-as-a-file and open-as-a-dir, the type of the object that the
     570                 :    * path refers to can change.
     571                 :    */
     572              16 :   retval = NaClHostDescStat(path, &stbuf);
     573                 : 
     574                 :   /* Windows does not have S_ISDIR(m) macro */
     575              18 :   if (0 == retval && S_IFDIR == (S_IFDIR & stbuf.st_mode)) {
     576                 :     struct NaClHostDir  *hd;
     577                 : 
     578               2 :     hd = malloc(sizeof *hd);
     579               2 :     if (NULL == hd) {
     580               0 :       retval = -NACL_ABI_ENOMEM;
     581               0 :       goto cleanup;
     582                 :     }
     583               2 :     retval = NaClHostDirOpen(hd, path);
     584               2 :     NaClLog(1, "NaClHostDirOpen(0x%08"NACL_PRIxPTR", %s) returned %d\n",
     585                 :             (uintptr_t) hd, path, retval);
     586               2 :     if (0 == retval) {
     587               2 :       retval = NaClSetAvail(natp->nap,
     588                 :                             ((struct NaClDesc *) NaClDescDirDescMake(hd)));
     589               2 :       NaClLog(1, "Entered directory into open file table at %d\n",
     590                 :               retval);
     591                 :     }
     592                 :   } else {
     593                 :     struct NaClHostDesc  *hd;
     594                 : 
     595              14 :     hd = malloc(sizeof *hd);
     596              14 :     if (NULL == hd) {
     597               0 :       retval = -NACL_ABI_ENOMEM;
     598               0 :       goto cleanup;
     599                 :     }
     600              14 :     retval = NaClHostDescOpen(hd, path, flags, mode);
     601              14 :     NaClLog(1,
     602                 :             "NaClHostDescOpen(0x%08"NACL_PRIxPTR", %s, 0%o, 0%o) returned %d\n",
     603                 :             (uintptr_t) hd, path, flags, mode, retval);
     604              14 :     if (0 == retval) {
     605              10 :       retval = NaClSetAvail(natp->nap,
     606                 :                             ((struct NaClDesc *) NaClDescIoDescMake(hd)));
     607              10 :       NaClLog(1, "Entered into open file table at %d\n", retval);
     608                 :     }
     609                 :   }
     610              16 : cleanup:
     611              16 :   NaClSysCommonThreadSyscallLeave(natp);
     612                 : 
     613              16 :   return retval;
     614                 : }
     615                 : 
     616                 : int32_t NaClCommonSysClose(struct NaClAppThread *natp,
     617              26 :                            int                  d) {
     618              26 :   int             retval = -NACL_ABI_EBADF;
     619                 :   struct NaClDesc *ndp;
     620                 : 
     621              26 :   NaClLog(3, "Entered NaClCommonSysClose(0x%08"NACL_PRIxPTR", %d)\n",
     622                 :           (uintptr_t) natp, d);
     623                 : 
     624              26 :   NaClSysCommonThreadSyscallEnter(natp);
     625                 : 
     626              26 :   NaClXMutexLock(&natp->nap->desc_mu);
     627              26 :   ndp = NaClGetDescMu(natp->nap, d);
     628              26 :   if (NULL != ndp) {
     629              21 :     NaClSetDescMu(natp->nap, d, NULL);  /* Unref the desc_tbl */
     630                 :   }
     631              26 :   NaClXMutexUnlock(&natp->nap->desc_mu);
     632              26 :   NaClLog(5, "Invoking Close virtual function of object 0x%08"NACL_PRIxPTR"\n",
     633                 :           (uintptr_t) ndp);
     634              26 :   if (NULL != ndp) {
     635              21 :     NaClDescUnref(ndp);
     636              21 :     retval = 0;
     637                 :   }
     638                 : 
     639              26 :   NaClSysCommonThreadSyscallLeave(natp);
     640              26 :   return retval;
     641                 : }
     642                 : 
     643                 : int32_t NaClCommonSysGetdents(struct NaClAppThread *natp,
     644                 :                               int                  d,
     645                 :                               void                 *dirp,
     646               0 :                               size_t               count) {
     647               0 :   int32_t         retval = -NACL_ABI_EINVAL;
     648                 :   ssize_t         getdents_ret;
     649                 :   uintptr_t       sysaddr;
     650                 :   struct NaClDesc *ndp;
     651                 : 
     652               0 :   NaClLog(3,
     653                 :           ("Entered NaClCommonSysGetdents(0x%08"NACL_PRIxPTR", "
     654                 :            "%d, 0x%08"NACL_PRIxPTR", "
     655                 :            "%"NACL_PRIdS"[0x%"NACL_PRIxS"])\n"),
     656                 :           (uintptr_t) natp, d, (uintptr_t) dirp, count, count);
     657                 : 
     658               0 :   NaClSysCommonThreadSyscallEnter(natp);
     659                 : 
     660               0 :   ndp = NaClGetDesc(natp->nap, d);
     661               0 :   if (NULL == ndp) {
     662               0 :     retval = -NACL_ABI_EBADF;
     663               0 :     goto cleanup;
     664                 :   }
     665                 : 
     666               0 :   sysaddr = NaClUserToSysAddrRange(natp->nap, (uintptr_t) dirp, count);
     667               0 :   if (kNaClBadAddress == sysaddr) {
     668               0 :     NaClLog(4, " illegal address for directory data\n");
     669               0 :     retval = -NACL_ABI_EFAULT;
     670               0 :     goto cleanup_unref;
     671                 :   }
     672                 : 
     673                 :   /*
     674                 :    * Clamp count to INT32_MAX to avoid the possibility of Getdents returning
     675                 :    * a value that is outside the range of an int32.
     676                 :    */
     677               0 :   if (count > INT32_MAX) {
     678               0 :     count = INT32_MAX;
     679                 :   }
     680               0 :   getdents_ret = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
     681                 :                   Getdents)(ndp,
     682                 :                             (void *) sysaddr,
     683                 :                             count);
     684                 :   if ((getdents_ret < INT32_MIN && !NaClSSizeIsNegErrno(&getdents_ret))
     685                 :       || INT32_MAX < getdents_ret) {
     686                 :     /* This should never happen, because we already clamped the input count */
     687                 :     NaClLog(LOG_FATAL, "Overflow in Getdents: return value is %"NACL_PRIxS,
     688                 :             getdents_ret);
     689                 :   } else {
     690               0 :     retval = (int32_t) getdents_ret;
     691                 :   }
     692               0 :   if (retval > 0) {
     693               0 :     NaClLog(4, "getdents returned %d bytes\n", retval);
     694               0 :     NaClLog(8, "getdents result: %.*s\n", retval, (char *) sysaddr);
     695                 :   } else {
     696               0 :     NaClLog(4, "getdents returned %d\n", retval);
     697                 :   }
     698                 : 
     699               0 : cleanup_unref:
     700               0 :   NaClDescUnref(ndp);
     701                 : 
     702               0 : cleanup:
     703               0 :   NaClSysCommonThreadSyscallLeave(natp);
     704                 : 
     705               0 :   return retval;
     706                 : }
     707                 : 
     708                 : int32_t NaClCommonSysRead(struct NaClAppThread  *natp,
     709                 :                           int                   d,
     710                 :                           void                  *buf,
     711              16 :                           size_t                count) {
     712              16 :   int32_t         retval = -NACL_ABI_EINVAL;
     713              16 :   ssize_t         read_result = -NACL_ABI_EINVAL;
     714                 :   uintptr_t       sysaddr;
     715                 :   struct NaClDesc *ndp;
     716                 : 
     717                 : 
     718              16 :   NaClLog(3,
     719                 :           ("Entered NaClCommonSysRead(0x%08"NACL_PRIxPTR", "
     720                 :            "%d, 0x%08"NACL_PRIxPTR", "
     721                 :            "%"NACL_PRIdS"[0x%"NACL_PRIxS"])\n"),
     722                 :           (uintptr_t) natp, d, (uintptr_t) buf, count, count);
     723                 : 
     724              16 :   NaClSysCommonThreadSyscallEnter(natp);
     725                 : 
     726              16 :   ndp = NaClGetDesc(natp->nap, d);
     727              16 :   if (NULL == ndp) {
     728               2 :     retval = -NACL_ABI_EBADF;
     729               2 :     goto cleanup;
     730                 :   }
     731                 : 
     732              14 :   sysaddr = NaClUserToSysAddrRange(natp->nap, (uintptr_t) buf, count);
     733              14 :   if (kNaClBadAddress == sysaddr) {
     734               1 :     NaClDescUnref(ndp);
     735               1 :     retval = -NACL_ABI_EFAULT;
     736               1 :     goto cleanup;
     737                 :   }
     738                 : 
     739                 :   /*
     740                 :    * The maximum length for read and write is INT32_MAX--anything larger and
     741                 :    * the return value would overflow. Passing larger values isn't an error--
     742                 :    * we'll just clamp the request size if it's too large.
     743                 :    */
     744              13 :   if (count > INT32_MAX) {
     745               0 :     count = INT32_MAX;
     746                 :   }
     747                 : 
     748              13 :   read_result = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
     749                 :                  Read)(ndp, (void *) sysaddr, count);
     750              13 :   if (read_result > 0) {
     751               9 :     NaClLog(4, "read returned %"NACL_PRIdS" bytes\n", read_result);
     752               9 :     NaClLog(8, "read result: %.*s\n",
     753                 :            (int) read_result,
     754                 :            (char *) sysaddr);
     755                 :   } else {
     756               4 :     NaClLog(4, "read returned %"NACL_PRIdS"\n", read_result);
     757                 :   }
     758              13 :   NaClDescUnref(ndp);
     759                 : 
     760                 :   /* This cast is safe because we clamped count above.*/
     761              13 :   retval = (int32_t) read_result;
     762              16 : cleanup:
     763              16 :   NaClSysCommonThreadSyscallLeave(natp);
     764                 : 
     765              16 :   return retval;
     766                 : }
     767                 : 
     768                 : int32_t NaClCommonSysWrite(struct NaClAppThread *natp,
     769                 :                            int                  d,
     770                 :                            void                 *buf,
     771             151 :                            size_t               count) {
     772             151 :   int32_t         retval = -NACL_ABI_EINVAL;
     773             151 :   ssize_t         write_result = -NACL_ABI_EINVAL;
     774                 :   uintptr_t       sysaddr;
     775                 :   struct NaClDesc *ndp;
     776                 : 
     777             151 :   NaClLog(3,
     778                 :           "Entered NaClCommonSysWrite(0x%08"NACL_PRIxPTR", "
     779                 :           "%d, 0x%08"NACL_PRIxPTR", "
     780                 :           "%"NACL_PRIdS"[0x%"NACL_PRIxS"])\n",
     781                 :           (uintptr_t) natp, d, (uintptr_t) buf, count, count);
     782                 : 
     783             151 :   NaClSysCommonThreadSyscallEnter(natp);
     784                 : 
     785             151 :   ndp = NaClGetDesc(natp->nap, d);
     786             151 :   NaClLog(4, " ndp = %"NACL_PRIxPTR"\n", (uintptr_t) ndp);
     787             151 :   if (NULL == ndp) {
     788               1 :     retval = -NACL_ABI_EBADF;
     789               1 :     goto cleanup;
     790                 :   }
     791                 : 
     792             150 :   sysaddr = NaClUserToSysAddrRange(natp->nap, (uintptr_t) buf, count);
     793             150 :   if (kNaClBadAddress == sysaddr) {
     794               1 :     NaClDescUnref(ndp);
     795               1 :     retval = -NACL_ABI_EFAULT;
     796               1 :     goto cleanup;
     797                 :   }
     798                 : 
     799             149 :   NaClLog(4, "In NaClSysWrite(%d, %.*s, %"NACL_PRIdS")\n",
     800                 :           d, (int) count, (char *) sysaddr, count);
     801                 : 
     802                 :   /*
     803                 :    * The maximum length for read and write is INT32_MAX--anything larger and
     804                 :    * the return value would overflow. Passing larger values isn't an error--
     805                 :    * we'll just clamp the request size if it's too large.
     806                 :    */
     807             149 :   if (count > INT32_MAX) {
     808               0 :     count = INT32_MAX;
     809                 :   }
     810                 : 
     811             149 :   write_result = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
     812                 :                   Write)(ndp, (void *) sysaddr, count);
     813                 : 
     814             149 :   NaClDescUnref(ndp);
     815                 : 
     816                 :   /* This cast is safe because we clamped count above.*/
     817             149 :   retval = (int32_t) write_result;
     818                 : 
     819             151 : cleanup:
     820             151 :   NaClSysCommonThreadSyscallLeave(natp);
     821                 : 
     822             151 :   return retval;
     823                 : }
     824                 : 
     825                 : /*
     826                 :  * This is not lseek64, so the return value on success can be
     827                 :  * E_OVERFLOW if it does not fit in a 32-bit off_t.
     828                 :  */
     829                 : int32_t NaClCommonSysLseek(struct NaClAppThread *natp,
     830                 :                            int                  d,
     831                 :                            nacl_abi_off_t       *offp,
     832               9 :                            int                  whence) {
     833                 :   uintptr_t       sysaddr;
     834                 :   nacl_abi_off_t  offset;
     835                 :   nacl_off64_t    retval64;
     836               9 :   int32_t         retval = -NACL_ABI_EINVAL;
     837                 :   struct NaClDesc *ndp;
     838                 : 
     839               9 :   NaClLog(3,
     840                 :           ("Entered NaClCommonSysLseek(0x%08"NACL_PRIxPTR", %d,"
     841                 :            " 0x%08"NACL_PRIxPTR", %d)\n"),
     842                 :           (uintptr_t) natp, d, (uintptr_t) offp, whence);
     843                 : 
     844               9 :   NaClSysCommonThreadSyscallEnter(natp);
     845                 : 
     846               9 :   ndp = NaClGetDesc(natp->nap, d);
     847               9 :   if (NULL == ndp) {
     848               1 :     retval = -NACL_ABI_EBADF;
     849               1 :     goto cleanup;
     850                 :   }
     851                 : 
     852               8 :   sysaddr = NaClUserToSysAddrRange(natp->nap, (uintptr_t) offp, sizeof offset);
     853               8 :   if (kNaClBadAddress == sysaddr) {
     854               0 :     retval = -NACL_ABI_EFAULT;
     855               0 :     goto cleanup_unref;
     856                 :   }
     857               8 :   offset = *(nacl_abi_off_t volatile *) sysaddr;
     858               8 :   NaClLog(4, "offset 0x%08"NACL_PRIxNACL_OFF"\n", offset);
     859                 : 
     860               8 :   retval64 = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
     861                 :               Seek)(ndp, (nacl_off64_t) offset, whence);
     862               8 :   if (NaClOff64IsNegErrno(&retval64)) {
     863               2 :     retval = (int32_t) retval64;
     864                 :   } else {
     865               6 :     *(nacl_abi_off_t volatile *) sysaddr = retval64;
     866               6 :     retval = 0;
     867                 :   }
     868               8 : cleanup_unref:
     869               8 :   NaClDescUnref(ndp);
     870               9 : cleanup:
     871               9 :   NaClSysCommonThreadSyscallLeave(natp);
     872               9 :   return retval;
     873                 : }
     874                 : 
     875                 : int32_t NaClCommonSysIoctl(struct NaClAppThread *natp,
     876                 :                            int                  d,
     877                 :                            int                  request,
     878               0 :                            void                 *arg) {
     879               0 :   int             retval = -NACL_ABI_EINVAL;
     880                 :   uintptr_t       sysaddr;
     881                 :   struct NaClDesc *ndp;
     882                 : 
     883               0 :   NaClLog(3,
     884                 :           ("Entered NaClSysIoctl(0x%08"NACL_PRIxPTR
     885                 :            ", %d, %d, 0x%08"NACL_PRIxPTR")\n"),
     886                 :           (uintptr_t) natp, d, request,
     887                 :           (uintptr_t) arg);
     888                 : 
     889               0 :   NaClSysCommonThreadSyscallEnter(natp);
     890                 :   /*
     891                 :    * Note that NaClUserToSysAddrRange is not feasible right now, since
     892                 :    * the size of the arg argument depends on the request.  We do not
     893                 :    * have an enumeration of allowed ioctl requests yet.
     894                 :    *
     895                 :    * Furthermore, some requests take no arguments, so sysaddr might
     896                 :    * end up being kNaClBadAddress and that is perfectly okay.
     897                 :    */
     898               0 :   sysaddr = NaClUserToSysAddr(natp->nap, (uintptr_t) arg);
     899                 :   /*
     900                 :    ****************************************
     901                 :    * NOTE: sysaddr may be kNaClBadAddress *
     902                 :    ****************************************
     903                 :    */
     904                 : 
     905               0 :   ndp = NaClGetDesc(natp->nap, d);
     906               0 :   if (NULL == ndp) {
     907               0 :     NaClLog(4, "bad desc\n");
     908               0 :     retval = -NACL_ABI_EBADF;
     909               0 :     goto cleanup;
     910                 :   }
     911                 : 
     912               0 :   retval = NaClIoctlAclCheck(natp->nap, ndp, request, arg);
     913               0 :   if (0 != retval) {
     914               0 :     NaClLog(3, "Ioctl ACL check rejected descriptor %d\n", d);
     915               0 :     goto cleanup_unref;
     916                 :   }
     917                 : 
     918               0 :   retval = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
     919                 :             Ioctl)(ndp, request, (void *) sysaddr);
     920               0 : cleanup_unref:
     921               0 :   NaClDescUnref(ndp);
     922               0 : cleanup:
     923               0 :   NaClSysCommonThreadSyscallLeave(natp);
     924               0 :   return retval;
     925                 : }
     926                 : 
     927                 : 
     928                 : int32_t NaClCommonSysFstat(struct NaClAppThread *natp,
     929                 :                            int                  d,
     930               5 :                            struct nacl_abi_stat *nasp) {
     931               5 :   int32_t               retval = -NACL_ABI_EINVAL;
     932                 :   uintptr_t             sysaddr;
     933                 :   struct NaClDesc       *ndp;
     934                 : 
     935               5 :   NaClLog(3,
     936                 :           ("Entered NaClSysFstat(0x%08"NACL_PRIxPTR
     937                 :            ", %d, 0x%08"NACL_PRIxPTR")\n"),
     938                 :           (uintptr_t) natp,
     939                 :           d, (uintptr_t) nasp);
     940                 : 
     941               5 :   NaClSysCommonThreadSyscallEnter(natp);
     942                 : 
     943               5 :   NaClLog(4,
     944                 :           " sizeof(struct nacl_abi_stat) = %"NACL_PRIdS" (0x%"NACL_PRIxS")\n",
     945                 :           sizeof *nasp, sizeof *nasp);
     946                 : 
     947               5 :   ndp = NaClGetDesc(natp->nap, d);
     948               5 :   if (NULL == ndp) {
     949               0 :     NaClLog(4, "bad desc\n");
     950               0 :     retval = -NACL_ABI_EBADF;
     951               0 :     goto cleanup;
     952                 :   }
     953                 : 
     954               5 :   sysaddr = NaClUserToSysAddrRange(natp->nap, (uintptr_t) nasp, sizeof *nasp);
     955               5 :   if (kNaClBadAddress == sysaddr) {
     956               0 :     NaClLog(4, "bad addr\n");
     957               0 :     retval = -NACL_ABI_EFAULT;
     958                 :   } else {
     959               5 :     retval = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
     960                 :               Fstat)(ndp, (struct nacl_abi_stat *) sysaddr);
     961                 :   }
     962                 : 
     963               5 :   NaClDescUnref(ndp);
     964               5 : cleanup:
     965               5 :   NaClSysCommonThreadSyscallLeave(natp);
     966                 : 
     967               5 :   return retval;
     968                 : }
     969                 : 
     970                 : int32_t NaClCommonSysStat(struct NaClAppThread  *natp,
     971                 :                           const char            *pathname,
     972               0 :                           struct nacl_abi_stat  *buf) {
     973               0 :   int32_t             retval = -NACL_ABI_EINVAL;
     974                 :   uintptr_t           syspathaddr;
     975                 :   uintptr_t           sysbufaddr;
     976                 :   char                path[NACL_CONFIG_PATH_MAX];
     977                 :   size_t              len;
     978                 :   nacl_host_stat_t    stbuf;
     979                 : 
     980               0 :   NaClLog(3,
     981                 :           ("Entered NaClCommonSysStat(0x%08"NACL_PRIxPTR", 0x%08"NACL_PRIxPTR","
     982                 :            " 0x%08"NACL_PRIxPTR")\n"),
     983                 :           (uintptr_t) natp, (uintptr_t) pathname, (uintptr_t) buf);
     984                 : 
     985               0 :   NaClSysCommonThreadSyscallEnter(natp);
     986                 : 
     987               0 :   syspathaddr = NaClUserToSysAddr(natp->nap, (uintptr_t) pathname);
     988               0 :   if (kNaClBadAddress == syspathaddr) {
     989               0 :     NaClLog(LOG_ERROR, "Invalid address for pathname\n");
     990               0 :     retval = -NACL_ABI_EFAULT;
     991               0 :     goto cleanup;
     992                 :   }
     993                 :   /*
     994                 :    * strncpy may (try to) get bytes that is outside the app's address
     995                 :    * space and generate a fault.
     996                 :    */
     997               0 :   strncpy(path, (char *) syspathaddr, sizeof path);
     998                 :   /*
     999                 :    * survived the copy, but did there happen to be data beyond the end?
    1000                 :    */
    1001               0 :   path[sizeof path - 1] = '\0';  /* always null terminate */
    1002               0 :   NaClLog(2, "NaClCommonSysStat: Path: %s\n", path);
    1003               0 :   len = strlen(path);
    1004                 :   /*
    1005                 :    * make sure sysaddr is a string, and the whole string is in app
    1006                 :    * address space...
    1007                 :    *
    1008                 :    * address space is convex, so it is impossible for beginning and
    1009                 :    * end to be both in the address space and yet have an intermediate
    1010                 :    * byte not be in the address space.
    1011                 :    */
    1012               0 :   if (kNaClBadAddress == NaClUserToSysAddr(natp->nap,
    1013                 :                                            len + (uintptr_t) pathname)) {
    1014               0 :     NaClLog(LOG_ERROR, "String ends outside addrspace\n");
    1015               0 :     retval = -NACL_ABI_EFAULT;
    1016               0 :     goto cleanup;
    1017                 :   }
    1018                 : 
    1019                 :   /*
    1020                 :    * Make sure result buffer is in the app's address space.
    1021                 :    */
    1022               0 :   sysbufaddr = NaClUserToSysAddrRange(natp->nap, (uintptr_t) buf, sizeof *buf);
    1023               0 :   if (kNaClBadAddress == sysbufaddr) {
    1024               0 :     retval = -NACL_ABI_EFAULT;
    1025               0 :     goto cleanup;
    1026                 :   }
    1027                 : 
    1028               0 :   retval = NaClStatAclCheck(natp->nap, path);
    1029               0 :   if (0 != retval) {
    1030               0 :     goto cleanup;
    1031                 :   }
    1032                 : 
    1033                 :   /*
    1034                 :    * Perform a host stat.
    1035                 :    */
    1036               0 :   retval = NaClHostDescStat(path, &stbuf);
    1037               0 :   if (0 == retval) {
    1038               0 :     retval = NaClAbiStatHostDescStatXlateCtor((struct nacl_abi_stat *)
    1039                 :                                               sysbufaddr,
    1040                 :                                               &stbuf);
    1041                 :   }
    1042               0 : cleanup:
    1043               0 :   NaClSysCommonThreadSyscallLeave(natp);
    1044               0 :   return retval;
    1045                 : }
    1046                 : 
    1047                 : void NaClCommonUtilUpdateAddrMap(struct NaClApp       *nap,
    1048                 :                                  uintptr_t            sysaddr,
    1049                 :                                  size_t               nbytes,
    1050                 :                                  int                  sysprot,
    1051                 :                                  struct NaClDesc      *backing_desc,
    1052                 :                                  nacl_off64_t         backing_bytes,
    1053                 :                                  nacl_off64_t         offset_bytes,
    1054               4 :                                  int                  delete_mem) {
    1055                 :   uintptr_t                   usraddr;
    1056                 :   struct NaClMemObj           *nmop;
    1057                 : 
    1058               4 :   NaClLog(3,
    1059                 :           ("NaClCommonUtilUpdateAddrMap(0x%08"NACL_PRIxPTR", "
    1060                 :            "0x%08"NACL_PRIxPTR", "
    1061                 :            "0x%"NACL_PRIxS", 0x%x, 0x%08"NACL_PRIxPTR", 0x%"NACL_PRIx64", "
    1062                 :            "0x%"NACL_PRIx64", %d)\n"),
    1063                 :           (uintptr_t) nap, sysaddr, nbytes,
    1064                 :           sysprot, (uintptr_t) backing_desc, backing_bytes,
    1065                 :           offset_bytes,
    1066                 :           delete_mem);
    1067               4 :   usraddr = NaClSysToUser(nap, sysaddr);
    1068               4 :   nmop = NULL;
    1069                 :   /* delete_mem -> NULL == backing_desc */
    1070               4 :   if (NULL != backing_desc) {
    1071               1 :     if (delete_mem) {
    1072               0 :       NaClLog(LOG_FATAL,
    1073                 :               ("invariant of delete_mem implies backing_desc NULL"
    1074                 :                " violated.\n"));
    1075                 :     }
    1076               1 :     nmop = NaClMemObjMake(backing_desc, backing_bytes, offset_bytes);
    1077                 :   }
    1078                 : 
    1079               4 :   NaClVmmapUpdate(&nap->mem_map,
    1080                 :                   usraddr >> NACL_PAGESHIFT,
    1081                 :                   nbytes >> NACL_PAGESHIFT,
    1082                 :                   sysprot,
    1083                 :                   nmop,
    1084                 :                   delete_mem);
    1085               4 : }
    1086                 : 
    1087                 : 
    1088                 : int NaClSysCommonAddrRangeContainsExecutablePages_mu(struct NaClApp *nap,
    1089                 :                                                      uintptr_t      usraddr,
    1090               7 :                                                      size_t         length) {
    1091                 :   /*
    1092                 :    * NOTE: currently only trampoline and text region are executable,
    1093                 :    * and they are at the beginning of the address space, so this code
    1094                 :    * is fine.  We will probably never allow users to mark other pages
    1095                 :    * as executable; but if so, we will have to revisit how this check
    1096                 :    * is implemented.
    1097                 :    *
    1098                 :    * nap->static_text_end is a multiple of 4K, the memory protection
    1099                 :    * granularity.  Since this routine is used for checking whether
    1100                 :    * memory map adjustments / allocations -- which has 64K granularity
    1101                 :    * -- is okay, usraddr must be an allocation granularity value.  Our
    1102                 :    * callers (as of this writing) does this, but we truncate it down
    1103                 :    * to an allocation boundary to be sure.
    1104                 :    */
    1105                 :   UNREFERENCED_PARAMETER(length);
    1106               7 :   usraddr = NaClTruncAllocPage(usraddr);
    1107               7 :   return usraddr < nap->dynamic_text_end;
    1108                 : }
    1109                 : 
    1110                 : 
    1111                 : /* Warning: sizeof(nacl_abi_off_t)!=sizeof(off_t) on OSX */
    1112                 : int32_t NaClCommonSysMmapIntern(struct NaClApp        *nap,
    1113                 :                                 void                  *start,
    1114                 :                                 size_t                length,
    1115                 :                                 int                   prot,
    1116                 :                                 int                   flags,
    1117                 :                                 int                   d,
    1118               5 :                                 nacl_abi_off_t        offset) {
    1119                 :   int                         allowed_flags;
    1120                 :   struct NaClDesc             *ndp;
    1121                 :   uintptr_t                   usraddr;
    1122                 :   uintptr_t                   usrpage;
    1123                 :   uintptr_t                   sysaddr;
    1124                 :   uintptr_t                   endaddr;
    1125                 :   uintptr_t                   map_result;
    1126                 :   int                         holding_app_lock;
    1127                 :   struct NaClMemObj           *nmop;
    1128                 :   struct nacl_abi_stat        stbuf;
    1129                 :   size_t                      alloc_rounded_length;
    1130                 :   nacl_off64_t                file_size;
    1131                 :   nacl_off64_t                file_bytes;
    1132                 :   nacl_off64_t                host_rounded_file_bytes;
    1133                 :   size_t                      alloc_rounded_file_bytes;
    1134                 :   size_t                      start_of_inaccessible;
    1135                 : 
    1136               5 :   holding_app_lock = 0;
    1137               5 :   nmop = NULL;
    1138               5 :   ndp = NULL;
    1139                 : 
    1140               5 :   allowed_flags = (NACL_ABI_MAP_FIXED | NACL_ABI_MAP_SHARED
    1141                 :                    | NACL_ABI_MAP_PRIVATE | NACL_ABI_MAP_ANONYMOUS);
    1142                 : 
    1143               5 :   usraddr = (uintptr_t) start;
    1144                 : 
    1145               5 :   if (0 != (flags & ~allowed_flags)) {
    1146               0 :     NaClLog(LOG_WARNING, "invalid mmap flags 0%o, ignoring extraneous bits\n",
    1147                 :             flags);
    1148               0 :     flags &= allowed_flags;
    1149                 :   }
    1150                 : 
    1151               5 :   if (0 != (flags & NACL_ABI_MAP_ANONYMOUS)) {
    1152                 :     /*
    1153                 :      * anonymous mmap, so backing store is just swap: no descriptor is
    1154                 :      * involved, and no memory object will be created to represent the
    1155                 :      * descriptor.
    1156                 :      */
    1157               4 :     ndp = NULL;
    1158                 :   } else {
    1159               1 :     ndp = NaClGetDesc(nap, d);
    1160               1 :     if (NULL == ndp) {
    1161               0 :       map_result = -NACL_ABI_EBADF;
    1162               0 :       goto cleanup;
    1163                 :     }
    1164                 :   }
    1165                 : 
    1166                 :   /*
    1167                 :    * Starting address must be aligned to worst-case allocation
    1168                 :    * granularity.  (Windows.)
    1169                 :    */
    1170               5 :   if (!NaClIsAllocPageMultiple(usraddr)) {
    1171               1 :     NaClLog(2, "NaClSysMmap: address not allocation granularity aligned\n");
    1172               1 :     map_result = -NACL_ABI_EINVAL;
    1173               1 :     goto cleanup;
    1174                 :   }
    1175                 :   /*
    1176                 :    * Offset should be non-negative (nacl_abi_off_t is signed).  This
    1177                 :    * condition is caught when the file is stat'd and checked, and
    1178                 :    * offset is ignored for anonymous mappings.
    1179                 :    */
    1180               4 :   if (offset < 0) {
    1181               0 :     NaClLog(1,  /* application bug */
    1182                 :             "NaClSysMmap: negative file offset: %"NACL_PRIdNACL_OFF"\n",
    1183                 :             offset);
    1184               0 :     map_result = -NACL_ABI_EINVAL;
    1185               0 :     goto cleanup;
    1186                 :   }
    1187                 :   /*
    1188                 :    * And offset must be a multiple of the allocation unit.
    1189                 :    */
    1190               4 :   if (!NaClIsAllocPageMultiple((uintptr_t) offset)) {
    1191               0 :     NaClLog(1,
    1192                 :             ("NaClSysMmap: file offset 0x%08"NACL_PRIxPTR" not multiple"
    1193                 :              " of allocation size\n"),
    1194                 :             (uintptr_t) offset);
    1195               0 :     map_result = -NACL_ABI_EINVAL;
    1196               0 :     goto cleanup;
    1197                 :   }
    1198                 : 
    1199               4 :   if (0 == length) {
    1200               0 :     map_result = -NACL_ABI_EINVAL;
    1201               0 :     goto cleanup;
    1202                 :   }
    1203               4 :   alloc_rounded_length = NaClRoundAllocPage(length);
    1204               4 :   if (alloc_rounded_length != length) {
    1205               1 :     NaClLog(1,
    1206                 :             "mmap: rounded length to 0x%"NACL_PRIxS"\n",
    1207                 :             alloc_rounded_length);
    1208                 :   }
    1209                 : 
    1210               4 :   if (NULL == ndp) {
    1211                 :     /*
    1212                 :      * Note: sentinel values are bigger than the NaCl module addr space.
    1213                 :      */
    1214               3 :     file_size                = kMaxUsableFileSize;
    1215               3 :     file_bytes               = kMaxUsableFileSize;
    1216               3 :     host_rounded_file_bytes  = kMaxUsableFileSize;
    1217               3 :     alloc_rounded_file_bytes = kMaxUsableFileSize;
    1218                 :   } else {
    1219                 :     /*
    1220                 :      * We stat the file to figure out its actual size.
    1221                 :      *
    1222                 :      * This is needed since we allow an app to mmap in a odd-sized
    1223                 :      * file and will zero fill the allocation page containing the last
    1224                 :      * byte(s) of the file, but if the app asked for a length that
    1225                 :      * goes beyond the last allocation page, that memory is actually
    1226                 :      * inaccessible.  Of course, the underlying OS deals with real
    1227                 :      * pages, and we may need to simulate this behavior (i.e., OSX and
    1228                 :      * Linux, we will need to put zero-filled pages between the last
    1229                 :      * 4K system page containing file data and the rest of the
    1230                 :      * simulated windows allocation 64K page.
    1231                 :      */
    1232               1 :     map_result = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
    1233                 :                   Fstat)(ndp, &stbuf);
    1234               1 :     if (0 != map_result) {
    1235               0 :       goto cleanup;
    1236                 :     }
    1237                 :     /*
    1238                 :      * BUG(bsy): there's a race between this fstat and the actual mmap
    1239                 :      * below.  It's probably insoluble.  Even if we fstat again after
    1240                 :      * mmap and compared, the mmap could have "seen" the file with a
    1241                 :      * different size, after which the racing thread restored back to
    1242                 :      * the same value before the 2nd fstat takes place.
    1243                 :      */
    1244               1 :     file_size = stbuf.nacl_abi_st_size;
    1245                 : 
    1246               1 :     if (file_size < offset) {
    1247               0 :       map_result = -NACL_ABI_EINVAL;
    1248               0 :       goto cleanup;
    1249                 :     }
    1250                 : 
    1251               1 :     file_bytes = file_size - offset;
    1252               1 :     NaClLog(4,
    1253                 :             "NaClCommonSysMmapIntern: file_bytes 0x%016"NACL_PRIxNACL_OFF"\n",
    1254                 :             file_bytes);
    1255               1 :     if ((nacl_off64_t) kMaxUsableFileSize < file_bytes) {
    1256               0 :       host_rounded_file_bytes = kMaxUsableFileSize;
    1257                 :     } else {
    1258               1 :       host_rounded_file_bytes = NaClRoundHostAllocPage((size_t) file_bytes);
    1259                 :     }
    1260                 : 
    1261               1 :     ASSERT(host_rounded_file_bytes <= (nacl_off64_t) kMaxUsableFileSize);
    1262                 :     /*
    1263                 :      * We need to deal with NaClRoundHostAllocPage rounding up to zero
    1264                 :      * from ~0u - n, where n < 4096 or 65536 (== 1 alloc page).
    1265                 :      *
    1266                 :      * Luckily, file_bytes is at most kMaxUsableFileSize which is
    1267                 :      * smaller than SIZE_T_MAX, so it should never happen, but we
    1268                 :      * leave the explicit check below as defensive programming.
    1269                 :      */
    1270               1 :     alloc_rounded_file_bytes =
    1271                 :       NaClRoundAllocPage((size_t) host_rounded_file_bytes);
    1272                 : 
    1273               1 :     if (0 == alloc_rounded_file_bytes && 0 != host_rounded_file_bytes) {
    1274               0 :       map_result = -NACL_ABI_ENOMEM;
    1275               0 :       goto cleanup;
    1276                 :     }
    1277                 : 
    1278                 :     /*
    1279                 :      * NB: host_rounded_file_bytes and alloc_rounded_file_bytes can be
    1280                 :      * zero.  Such an mmap just makes memory (offset relative to
    1281                 :      * usraddr) in the range [0, alloc_rounded_length) inaccessible.
    1282                 :      */
    1283                 :   }
    1284                 : 
    1285                 :   /*
    1286                 :    * host_rounded_file_bytes is how many bytes we can map from the
    1287                 :    * file, given the user-supplied starting offset.  It is at least
    1288                 :    * one page.  If it came from a real file, it is a multiple of
    1289                 :    * host-OS allocation size.  it cannot be larger than
    1290                 :    * kMaxUsableFileSize.
    1291                 :    */
    1292               4 :   length = size_min(alloc_rounded_length, (size_t) host_rounded_file_bytes);
    1293               4 :   start_of_inaccessible = size_min(alloc_rounded_length,
    1294                 :                                    alloc_rounded_file_bytes);
    1295                 : 
    1296                 :   /*
    1297                 :    * Now, we map, relative to usraddr, bytes [0, length) from the file
    1298                 :    * starting at offset, zero-filled pages for the memory region
    1299                 :    * [length, start_of_inaccessible), and inaccessible pages for the
    1300                 :    * memory region [start_of_inaccessible, alloc_rounded_length).
    1301                 :    */
    1302                 : 
    1303                 :   /*
    1304                 :    * Lock the addr space.
    1305                 :    */
    1306               4 :   NaClXMutexLock(&nap->mu);
    1307                 : 
    1308               8 :   while (0 != nap->threads_launching) {
    1309               0 :     NaClXCondVarWait(&nap->cv, &nap->mu);
    1310                 :   }
    1311               4 :   nap->vm_hole_may_exist = 1;
    1312               4 :   NaClUntrustedThreadsSuspend(nap);
    1313                 : 
    1314               4 :   holding_app_lock = 1;
    1315                 : 
    1316               4 :   if (0 == (flags & NACL_ABI_MAP_FIXED)) {
    1317                 :     /*
    1318                 :      * The user wants us to pick an address range.
    1319                 :      */
    1320               3 :     if (0 == usraddr) {
    1321                 :       /*
    1322                 :        * Pick a hole in addr space of appropriate size, anywhere.
    1323                 :        * We pick one that's best for the system.
    1324                 :        */
    1325               3 :       usrpage = NaClVmmapFindMapSpace(&nap->mem_map,
    1326                 :                                       alloc_rounded_length >> NACL_PAGESHIFT);
    1327               3 :       NaClLog(4, "NaClSysMmap: FindMapSpace: page 0x%05"NACL_PRIxPTR"\n",
    1328                 :               usrpage);
    1329               3 :       if (0 == usrpage) {
    1330               0 :         map_result = -NACL_ABI_ENOMEM;
    1331               0 :         goto cleanup;
    1332                 :       }
    1333               3 :       usraddr = usrpage << NACL_PAGESHIFT;
    1334               3 :       NaClLog(4, "NaClSysMmap: new starting addr: 0x%08"NACL_PRIxPTR
    1335                 :               "\n", usraddr);
    1336                 :     } else {
    1337                 :       /*
    1338                 :        * user supplied an addr, but it's to be treated as a hint; we
    1339                 :        * find a hole of the right size in the app's address space,
    1340                 :        * according to the usual mmap semantics.
    1341                 :        */
    1342               0 :       usrpage = NaClVmmapFindMapSpaceAboveHint(&nap->mem_map,
    1343                 :                                                usraddr,
    1344                 :                                                (alloc_rounded_length
    1345                 :                                                 >> NACL_PAGESHIFT));
    1346               0 :       NaClLog(4, "NaClSysMmap: FindSpaceAboveHint: page 0x%05"NACL_PRIxPTR"\n",
    1347                 :               usrpage);
    1348               0 :       if (0 == usrpage) {
    1349               0 :         NaClLog(4, "NaClSysMmap: hint failed, doing generic allocation\n");
    1350               0 :         usrpage = NaClVmmapFindMapSpace(&nap->mem_map,
    1351                 :                                         alloc_rounded_length >> NACL_PAGESHIFT);
    1352                 :       }
    1353               0 :       if (0 == usrpage) {
    1354               0 :         map_result = -NACL_ABI_ENOMEM;
    1355               0 :         goto cleanup;
    1356                 :       }
    1357               0 :       usraddr = usrpage << NACL_PAGESHIFT;
    1358               0 :       NaClLog(4, "NaClSysMmap: new starting addr: 0x%08"NACL_PRIxPTR"\n",
    1359                 :               usraddr);
    1360                 :     }
    1361                 :   }
    1362                 : 
    1363                 :   /*
    1364                 :    * Validate [usraddr, endaddr) is okay.
    1365                 :    */
    1366               4 :   if (usraddr >= ((uintptr_t) 1 << nap->addr_bits)) {
    1367               0 :     NaClLog(2,
    1368                 :             ("NaClSysMmap: start address (0x%08"NACL_PRIxPTR") outside address"
    1369                 :              " space\n"),
    1370                 :             usraddr);
    1371               0 :     map_result = -NACL_ABI_EINVAL;
    1372               0 :     goto cleanup;
    1373                 :   }
    1374               4 :   endaddr = usraddr + alloc_rounded_length;
    1375               4 :   if (endaddr < usraddr) {
    1376               0 :     NaClLog(0,
    1377                 :             ("NaClSysMmap: integer overflow -- "
    1378                 :              "NaClSysMmap(0x%08"NACL_PRIxPTR",0x%"NACL_PRIxS",0x%x,0x%x,%d,"
    1379                 :              "0x%08"NACL_PRIxPTR"\n"),
    1380                 :             usraddr, length, prot, flags, d, (uintptr_t) offset);
    1381               0 :     map_result = -NACL_ABI_EINVAL;
    1382               0 :     goto cleanup;
    1383                 :   }
    1384                 :   /*
    1385                 :    * NB: we use > instead of >= here.
    1386                 :    *
    1387                 :    * endaddr is the address of the first byte beyond the target region
    1388                 :    * and it can equal the address space limit.  (of course, normally
    1389                 :    * the main thread's stack is there.)
    1390                 :    */
    1391               4 :   if (endaddr > ((uintptr_t) 1 << nap->addr_bits)) {
    1392               0 :     NaClLog(2,
    1393                 :             ("NaClSysMmap: end address (0x%08"NACL_PRIxPTR") is beyond"
    1394                 :              " the end of the address space\n"),
    1395                 :             endaddr);
    1396               0 :     map_result = -NACL_ABI_EINVAL;
    1397               0 :     goto cleanup;
    1398                 :   }
    1399                 : 
    1400               4 :   if (NaClSysCommonAddrRangeContainsExecutablePages_mu(nap,
    1401                 :                                                        usraddr,
    1402                 :                                                        length)) {
    1403               1 :     NaClLog(2, "NaClSysMmap: region contains executable pages\n");
    1404               1 :     map_result = -NACL_ABI_EINVAL;
    1405               1 :     goto cleanup;
    1406                 :   }
    1407                 : 
    1408                 :   /*
    1409                 :    * Force NACL_ABI_MAP_FIXED, since we are specifying address in NaCl
    1410                 :    * app address space.
    1411                 :    */
    1412               3 :   flags |= NACL_ABI_MAP_FIXED;
    1413                 : 
    1414                 :   /*
    1415                 :    * Never allow users to say that mmapped pages are executable.  This
    1416                 :    * is primarily for the service runtime's own bookkeeping -- prot is
    1417                 :    * used in NaClCommonUtilUpdateAddrMap -- since %cs restriction
    1418                 :    * makes page protection irrelevant, it doesn't matter that on many
    1419                 :    * systems (w/o NX) PROT_READ implies PROT_EXEC.
    1420                 :    */
    1421               3 :   prot &= ~NACL_ABI_PROT_EXEC;
    1422                 : 
    1423                 :   /*
    1424                 :    * Exactly one of NACL_ABI_MAP_SHARED and NACL_ABI_MAP_PRIVATE is set.
    1425                 :    */
    1426               3 :   if ((0 == (flags & NACL_ABI_MAP_SHARED))
    1427                 :       == (0 == (flags & NACL_ABI_MAP_PRIVATE))) {
    1428               0 :     map_result = -NACL_ABI_EINVAL;
    1429               0 :     goto cleanup;
    1430                 :   }
    1431                 : 
    1432               3 :   sysaddr = NaClUserToSys(nap, usraddr);
    1433                 : 
    1434                 :   /* [0, length) */
    1435               3 :   if (length > 0) {
    1436               3 :     if (NULL == ndp) {
    1437               2 :       NaClLog(4,
    1438                 :               ("NaClSysMmap: NaClDescIoDescMap(,,0x%08"NACL_PRIxPTR","
    1439                 :                "0x%08"NACL_PRIxS",0x%x,0x%x,0x%08"NACL_PRIxPTR")\n"),
    1440                 :               sysaddr, length, prot, flags, (uintptr_t) offset);
    1441               2 :       map_result = NaClDescIoDescMapAnon(nap->effp,
    1442                 :                                          (void *) sysaddr,
    1443                 :                                          length,
    1444                 :                                          prot,
    1445                 :                                          flags,
    1446                 :                                          (off_t) offset);
    1447                 :     } else {
    1448                 :       /*
    1449                 :        * This is a fix for Windows, where we cannot pass a size that
    1450                 :        * goes beyond the non-page-rounded end of the file.
    1451                 :        */
    1452               1 :       size_t length_to_map = size_min(length, (size_t) file_bytes);
    1453                 : 
    1454               1 :       NaClLog(4,
    1455                 :               ("NaClSysMmap: (*ndp->Map)(,,0x%08"NACL_PRIxPTR","
    1456                 :                "0x%08"NACL_PRIxS",0x%x,0x%x,0x%08"NACL_PRIxPTR")\n"),
    1457                 :               sysaddr, length, prot, flags, (uintptr_t) offset);
    1458                 : 
    1459               1 :       map_result = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
    1460                 :                     Map)(ndp,
    1461                 :                          nap->effp,
    1462                 :                          (void *) sysaddr,
    1463                 :                          length_to_map,
    1464                 :                          prot,
    1465                 :                          flags,
    1466                 :                          (off_t) offset);
    1467                 :     }
    1468                 :     /*
    1469                 :      * "Small" negative integers are errno values.  Larger ones are
    1470                 :      * virtual addresses.
    1471                 :      */
    1472               3 :     if (NaClPtrIsNegErrno(&map_result)) {
    1473               0 :       NaClLog(LOG_FATAL,
    1474                 :               ("NaClSysMmap: Map failed, but we"
    1475                 :                " cannot handle address space move, error %"NACL_PRIuS"\n"),
    1476                 :               (size_t) map_result);
    1477                 :     }
    1478               3 :     if (map_result != sysaddr) {
    1479               0 :       NaClLog(LOG_FATAL, "system mmap did not honor NACL_ABI_MAP_FIXED\n");
    1480                 :     }
    1481               3 :     if (prot == NACL_ABI_PROT_NONE) {
    1482                 :       /*
    1483                 :        * windows nacl_host_desc implementation requires that PROT_NONE
    1484                 :        * memory be freed using VirtualFree rather than
    1485                 :        * UnmapViewOfFile.  TODO(bsy): remove this ugliness.
    1486                 :        */
    1487               1 :       NaClCommonUtilUpdateAddrMap(nap, sysaddr, length, PROT_NONE,
    1488                 :                                   NULL, file_size, offset, 0);
    1489                 :     } else {
    1490                 :       /* record change for file-backed memory */
    1491               2 :       NaClCommonUtilUpdateAddrMap(nap, sysaddr, length, NaClProtMap(prot),
    1492                 :                                   ndp, file_size, offset, 0);
    1493                 :     }
    1494                 :   } else {
    1495               0 :     map_result = sysaddr;
    1496                 :   }
    1497                 :   /* zero fill [length, start_of_inaccessible) */
    1498               3 :   if (length < start_of_inaccessible) {
    1499               1 :     size_t  map_len = start_of_inaccessible - length;
    1500                 : 
    1501               1 :     NaClLog(2,
    1502                 :             ("zero-filling pages for memory range"
    1503                 :              " [0x%08"NACL_PRIxPTR", 0x%08"NACL_PRIxPTR
    1504                 :              "), length 0x%"NACL_PRIxS"\n"),
    1505                 :             sysaddr + length, sysaddr + start_of_inaccessible, map_len);
    1506               1 :     map_result = NaClHostDescMap((struct NaClHostDesc *) NULL,
    1507                 :                                  (void *) (sysaddr + length),
    1508                 :                                  map_len,
    1509                 :                                  prot,
    1510                 :                                  NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE,
    1511                 :                                  (off_t) 0);
    1512               1 :     if (NaClPtrIsNegErrno(&map_result)) {
    1513               0 :       NaClLog(LOG_ERROR,
    1514                 :               ("Could not create zero-filled pages for memory range"
    1515                 :                " [0x%08"NACL_PRIxPTR", 0x%08"NACL_PRIxPTR")\n"),
    1516                 :               sysaddr + length, sysaddr + start_of_inaccessible);
    1517               0 :       goto cleanup;
    1518                 :     }
    1519               1 :     NaClCommonUtilUpdateAddrMap(nap, sysaddr + length, map_len,
    1520                 :                                 NaClProtMap(prot),
    1521                 :                                 (struct NaClDesc *) NULL, 0, (off_t) 0, 0);
    1522                 :   }
    1523                 :   /* inaccessible: [start_of_inaccessible, alloc_rounded_length) */
    1524               3 :   if (start_of_inaccessible < alloc_rounded_length) {
    1525               0 :     size_t  map_len = alloc_rounded_length - start_of_inaccessible;
    1526                 : 
    1527               0 :     NaClLog(2,
    1528                 :             ("inaccessible pages for memory range"
    1529                 :              " [0x%08"NACL_PRIxPTR", 0x%08"NACL_PRIxPTR"),"
    1530                 :              " length 0x%"NACL_PRIxS"\n"),
    1531                 :             sysaddr + start_of_inaccessible,
    1532                 :             sysaddr + alloc_rounded_length,
    1533                 :             map_len);
    1534               0 :     map_result = NaClHostDescMap((struct NaClHostDesc *) NULL,
    1535                 :                              (void *) (sysaddr + start_of_inaccessible),
    1536                 :                              map_len,
    1537                 :                              NACL_ABI_PROT_NONE,
    1538                 :                              NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE,
    1539                 :                              (off_t) 0);
    1540               0 :     if (NaClPtrIsNegErrno(&map_result)) {
    1541               0 :       NaClLog(LOG_ERROR,
    1542                 :             ("Could not create inaccessible pages for memory range"
    1543                 :              " [0x%08"NACL_PRIxPTR", 0x%08"NACL_PRIxPTR
    1544                 :              "), length 0x%"NACL_PRIxS"\n"),
    1545                 :             sysaddr + start_of_inaccessible,
    1546                 :             sysaddr + alloc_rounded_length,
    1547                 :             map_len);
    1548                 :     }
    1549               0 :     NaClCommonUtilUpdateAddrMap(nap, sysaddr + start_of_inaccessible,
    1550                 :                                 map_len, PROT_NONE,
    1551                 :                                 (struct NaClDesc *) NULL, 0,
    1552                 :                                 (off_t) 0, 0);
    1553                 :   }
    1554               3 :   NaClLog(3, "NaClSysMmap: got address 0x%08"NACL_PRIxPTR"\n",
    1555                 :           (uintptr_t) map_result);
    1556                 : 
    1557               3 :   map_result = usraddr;
    1558                 : 
    1559               5 : cleanup:
    1560               5 :   if (holding_app_lock) {
    1561               4 :     nap->vm_hole_may_exist = 0;
    1562               4 :     NaClXCondVarBroadcast(&nap->cv);
    1563               4 :     NaClXMutexUnlock(&nap->mu);
    1564                 : 
    1565               4 :     NaClUntrustedThreadsResume(nap);
    1566                 :   }
    1567               5 :   if (NULL != ndp) {
    1568               1 :     NaClDescUnref(ndp);
    1569                 :   }
    1570               5 :   if (NaClPtrIsNegErrno(&map_result)) {
    1571               2 :     free(nmop);
    1572                 :   }
    1573                 : 
    1574                 :   /*
    1575                 :    * Check to ensure that map_result will fit into a 32-bit value. This is
    1576                 :    * a bit tricky because there are two valid ranges: one is the range from
    1577                 :    * 0 to (almost) 2^32, the other is from -1 to -4096 (our error range).
    1578                 :    * For a 32-bit value these ranges would overlap, but if the value is 64-bit
    1579                 :    * they will be disjoint.
    1580                 :    */
    1581                 :   if (map_result > UINT32_MAX
    1582                 :       && !NaClPtrIsNegErrno(&map_result)) {
    1583                 :     NaClLog(LOG_FATAL, "Overflow in NaClSysMmap: return address is "
    1584                 :                        "0x%"NACL_PRIxPTR"\n", map_result);
    1585                 :   }
    1586               5 :   NaClLog(3, "NaClSysMmap: returning 0x%08"NACL_PRIxPTR"\n", map_result);
    1587                 : 
    1588               5 :   return (int32_t) map_result;
    1589                 : }
    1590                 : 
    1591                 : int32_t NaClCommonSysMmap(struct NaClAppThread  *natp,
    1592                 :                           void                  *start,
    1593                 :                           size_t                length,
    1594                 :                           int                   prot,
    1595                 :                           int                   flags,
    1596                 :                           int                   d,
    1597               5 :                           nacl_abi_off_t        *offp) {
    1598                 :   int32_t         retval;
    1599                 :   uintptr_t       sysaddr;
    1600                 :   nacl_abi_off_t  offset;
    1601                 : 
    1602               5 :   NaClLog(3,
    1603                 :           "Entered NaClSysMmap(0x%08"NACL_PRIxPTR",0x%"NACL_PRIxS","
    1604                 :           "0x%x,0x%x,%d,0x%08"NACL_PRIxPTR")\n",
    1605                 :           (uintptr_t) start, length, prot, flags, d, (uintptr_t) offp);
    1606                 : 
    1607               5 :   if ((nacl_abi_off_t *) 0 == offp) {
    1608                 :     /*
    1609                 :      * This warning is really targetted towards trusted code,
    1610                 :      * especially tests that didn't notice the argument type change.
    1611                 :      * Unfortunatey, zero is a common and legitimate offset value, and
    1612                 :      * the compiler will not complain since an automatic type
    1613                 :      * conversion works.
    1614                 :      */
    1615               0 :     NaClLog(LOG_WARNING,
    1616                 :             "NaClCommonSysMmap: NULL pointer used"
    1617                 :             " for offset in/out argument\n");
    1618               0 :     return -NACL_ABI_EINVAL;
    1619                 :   }
    1620                 : 
    1621               5 :   NaClSysCommonThreadSyscallEnter(natp);
    1622                 : 
    1623               5 :   sysaddr = NaClUserToSysAddrRange(natp->nap, (uintptr_t) offp, sizeof offset);
    1624               5 :   if (kNaClBadAddress == sysaddr) {
    1625               0 :     NaClLog(3,
    1626                 :             "NaClCommonSysMmap: offset in a bad untrusted memory location\n");
    1627               0 :     retval = -NACL_ABI_EFAULT;
    1628               0 :     goto cleanup;
    1629                 :   }
    1630               5 :   offset = *(nacl_abi_off_t volatile *) sysaddr;
    1631                 : 
    1632               5 :   NaClLog(4, " offset = 0x%08"NACL_PRIxNACL_OFF"\n", offset);
    1633                 : 
    1634               5 :   retval = NaClCommonSysMmapIntern(natp->nap,
    1635                 :                                    start, length,
    1636                 :                                    prot,
    1637                 :                                    flags,
    1638                 :                                    d, offset);
    1639               5 : cleanup:
    1640               5 :   NaClSysCommonThreadSyscallLeave(natp);
    1641                 : 
    1642               5 :   return retval;
    1643                 : }
    1644                 : 
    1645                 : int32_t NaClCommonSysImc_MakeBoundSock(struct NaClAppThread *natp,
    1646               0 :                                        int32_t              *sap) {
    1647                 :   /*
    1648                 :    * Create a bound socket descriptor and a socket address descriptor.
    1649                 :    */
    1650                 : 
    1651               0 :   int32_t                     retval = -NACL_ABI_EINVAL;
    1652                 :   uintptr_t                   sys_sap;
    1653                 :   struct NaClDesc             *pair[2];
    1654                 : 
    1655               0 :   NaClLog(3,
    1656                 :           ("Entered NaClCommonSysImc_MakeBoundSock(0x%08"NACL_PRIxPTR","
    1657                 :            " 0x%08"NACL_PRIxPTR")\n"),
    1658                 :           (uintptr_t) natp, (uintptr_t) sap);
    1659                 : 
    1660               0 :   NaClSysCommonThreadSyscallEnter(natp);
    1661                 : 
    1662               0 :   sys_sap = NaClUserToSysAddrRange(natp->nap,
    1663                 :                                    (uintptr_t) sap,
    1664                 :                                    2 * sizeof *sap);
    1665               0 :   if (kNaClBadAddress == sys_sap) {
    1666               0 :     NaClLog(3, " illegal address\n");
    1667               0 :     retval = -NACL_ABI_EFAULT;
    1668               0 :     goto cleanup;
    1669                 :   }
    1670                 : 
    1671               0 :   retval = NaClCommonDescMakeBoundSock(pair);
    1672               0 :   if (0 != retval) {
    1673               0 :     goto cleanup;
    1674                 :   }
    1675                 : 
    1676               0 :   ((int32_t *) sys_sap)[0] = NaClSetAvail(natp->nap, pair[0]);
    1677               0 :   ((int32_t *) sys_sap)[1] = NaClSetAvail(natp->nap, pair[1]);
    1678               0 :   retval = 0;
    1679               0 : cleanup:
    1680               0 :   NaClSysCommonThreadSyscallLeave(natp);
    1681                 : 
    1682               0 :   return retval;
    1683                 : }
    1684                 : 
    1685                 : int32_t NaClCommonSysImc_Accept(struct NaClAppThread  *natp,
    1686               0 :                                 int                   d) {
    1687               0 :   int32_t         retval = -NACL_ABI_EINVAL;
    1688                 :   struct NaClDesc *ndp;
    1689                 : 
    1690               0 :   NaClLog(3, "Entered NaClSysImc_Accept(0x%08"NACL_PRIxPTR", %d)\n",
    1691                 :           (uintptr_t) natp, d);
    1692                 : 
    1693               0 :   NaClSysCommonThreadSyscallEnter(natp);
    1694                 : 
    1695               0 :   ndp = NaClGetDesc(natp->nap, d);
    1696               0 :   if (NULL == ndp) {
    1697               0 :     retval = -NACL_ABI_EBADF;
    1698                 :   } else {
    1699                 :     struct NaClDesc *result_desc;
    1700               0 :     retval = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
    1701                 :               AcceptConn)(ndp, &result_desc);
    1702               0 :     if (retval == 0) {
    1703               0 :       retval = NaClSetAvail(natp->nap, result_desc);
    1704                 :     }
    1705               0 :     NaClDescUnref(ndp);
    1706                 :   }
    1707                 : 
    1708               0 :   NaClSysCommonThreadSyscallLeave(natp);
    1709               0 :   return retval;
    1710                 : }
    1711                 : 
    1712                 : int32_t NaClCommonSysImc_Connect(struct NaClAppThread *natp,
    1713               0 :                                  int                  d) {
    1714               0 :   int32_t         retval = -NACL_ABI_EINVAL;
    1715                 :   struct NaClDesc *ndp;
    1716                 : 
    1717               0 :   NaClLog(3, "Entered NaClSysImc_ConnectAddr(0x%08"NACL_PRIxPTR", %d)\n",
    1718                 :           (uintptr_t) natp, d);
    1719                 : 
    1720               0 :   NaClSysCommonThreadSyscallEnter(natp);
    1721                 : 
    1722               0 :   ndp = NaClGetDesc(natp->nap, d);
    1723               0 :   if (NULL == ndp) {
    1724               0 :     retval = -NACL_ABI_EBADF;
    1725                 :   } else {
    1726                 :     struct NaClDesc *result;
    1727               0 :     retval = (*((struct NaClDescVtbl const *) ndp->base.vtbl)->
    1728                 :               ConnectAddr)(ndp, &result);
    1729               0 :     if (retval == 0) {
    1730               0 :       retval = NaClSetAvail(natp->nap, result);
    1731                 :     }
    1732               0 :     NaClDescUnref(ndp);
    1733                 :   }
    1734                 : 
    1735               0 :   NaClSysCommonThreadSyscallLeave(natp);
    1736               0 :   return retval;
    1737                 : }
    1738                 : 
    1739                 : /*
    1740                 :  * This function converts addresses from user addresses to system
    1741                 :  * addresses, copying into kernel space as needed to avoid TOCvTOU
    1742                 :  * races, then invoke NaClImcSendTypedMessage from the nrd_xfer
    1743                 :  * library.
    1744                 :  */
    1745                 : int32_t NaClCommonSysImc_Sendmsg(struct NaClAppThread         *natp,
    1746                 :                                  int                          d,
    1747                 :                                  struct NaClAbiNaClImcMsgHdr *nanimhp,
    1748               0 :                                  int                          flags) {
    1749               0 :   int32_t                       retval = -NACL_ABI_EINVAL;
    1750                 :   ssize_t                       ssize_retval;
    1751                 :   uintptr_t                     sysaddr;
    1752                 :   /* copy of user-space data for validation */
    1753                 :   struct NaClAbiNaClImcMsgHdr   kern_nanimh;
    1754                 :   struct NaClAbiNaClImcMsgIoVec kern_naiov[NACL_ABI_IMC_IOVEC_MAX];
    1755                 :   struct NaClImcMsgIoVec        kern_iov[NACL_ABI_IMC_IOVEC_MAX];
    1756                 :   /* kernel-side representatin of descriptors */
    1757                 :   struct NaClDesc               *kern_desc[NACL_ABI_IMC_USER_DESC_MAX];
    1758                 :   struct NaClImcTypedMsgHdr     kern_msg_hdr;
    1759                 :   struct NaClDesc               *ndp;
    1760                 :   size_t                        i;
    1761                 : 
    1762               0 :   NaClLog(3,
    1763                 :           ("Entered NaClCommonSysImc_Sendmsg(0x%08"NACL_PRIxPTR", %d,"
    1764                 :            " 0x%08"NACL_PRIxPTR", 0x%x)\n"),
    1765                 :           (uintptr_t) natp, d, (uintptr_t) nanimhp, flags);
    1766                 : 
    1767               0 :   NaClSysCommonThreadSyscallEnter(natp);
    1768                 : 
    1769               0 :   sysaddr = NaClUserToSysAddrRange(natp->nap,
    1770                 :                                    (uintptr_t) nanimhp,
    1771                 :                                    sizeof *nanimhp);
    1772               0 :   if (kNaClBadAddress == sysaddr) {
    1773               0 :     NaClLog(4, "NaClImcMsgHdr not in user address space\n");
    1774               0 :     retval = -NACL_ABI_EFAULT;
    1775               0 :     goto cleanup_leave;
    1776                 :   }
    1777                 : 
    1778               0 :   kern_nanimh = *(struct NaClAbiNaClImcMsgHdr volatile *) sysaddr;
    1779                 :   /* copy before validating */
    1780                 : 
    1781                 :   /*
    1782                 :    * Some of these checks duplicate checks that will be done in the
    1783                 :    * nrd xfer library, but it is better to check before doing the
    1784                 :    * address translation of memory/descriptor vectors if those vectors
    1785                 :    * might be too long.  Plus, we need to copy and validate vectors
    1786                 :    * for TOCvTOU race protection, and we must prevent overflows.  The
    1787                 :    * nrd xfer library's checks should never fire when called from the
    1788                 :    * service runtime, but the nrd xfer library might be called from
    1789                 :    * other code.
    1790                 :    */
    1791               0 :   if (kern_nanimh.iov_length > NACL_ABI_IMC_IOVEC_MAX) {
    1792               0 :     NaClLog(4, "gather/scatter array too large\n");
    1793               0 :     retval = -NACL_ABI_EINVAL;
    1794               0 :     goto cleanup_leave;
    1795                 :   }
    1796               0 :   if (kern_nanimh.desc_length > NACL_ABI_IMC_USER_DESC_MAX) {
    1797               0 :     NaClLog(4, "handle vector too long\n");
    1798               0 :     retval = -NACL_ABI_EINVAL;
    1799               0 :     goto cleanup_leave;
    1800                 :   }
    1801                 : 
    1802               0 :   if (kern_nanimh.iov_length > 0) {
    1803               0 :     sysaddr = NaClUserToSysAddrRange(natp->nap,
    1804                 :                                      (uintptr_t) kern_nanimh.iov,
    1805                 :                                      (kern_nanimh.iov_length
    1806                 :                                       * sizeof kern_naiov[0]));
    1807               0 :     if (kNaClBadAddress == sysaddr) {
    1808               0 :       NaClLog(4, "gather/scatter array not in user address space\n");
    1809               0 :       retval = -NACL_ABI_EFAULT;
    1810               0 :       goto cleanup_leave;
    1811                 :     }
    1812                 : 
    1813               0 :     memcpy(kern_naiov, (void *) sysaddr,
    1814                 :            kern_nanimh.iov_length * sizeof kern_naiov[0]);
    1815                 : 
    1816               0 :     for (i = 0; i < kern_nanimh.iov_length; ++i) {
    1817               0 :       sysaddr = NaClUserToSysAddrRange(natp->nap,
    1818                 :                                        (uintptr_t) kern_naiov[i].base,
    1819                 :                                        kern_naiov[i].length);
    1820               0 :       if (kNaClBadAddress == sysaddr) {
    1821               0 :         retval = -NACL_ABI_EFAULT;
    1822               0 :         goto cleanup_leave;
    1823                 :       }
    1824               0 :       kern_iov[i].base = (void *) sysaddr;
    1825               0 :       kern_iov[i].length = kern_naiov[i].length;
    1826                 :     }
    1827                 :   }
    1828                 : 
    1829               0 :   ndp = NaClGetDesc(natp->nap, d);
    1830               0 :   if (NULL == ndp) {
    1831               0 :     retval = -NACL_ABI_EBADF;
    1832               0 :     goto cleanup_leave;
    1833                 :   }
    1834                 : 
    1835                 :   /*
    1836                 :    * make things easier for cleaup exit processing
    1837                 :    */
    1838               0 :   memset(kern_desc, 0, sizeof kern_desc);
    1839               0 :   retval = -NACL_ABI_EINVAL;
    1840                 : 
    1841               0 :   kern_msg_hdr.iov = kern_iov;
    1842               0 :   kern_msg_hdr.iov_length = kern_nanimh.iov_length;
    1843                 : 
    1844               0 :   if (0 == kern_nanimh.desc_length) {
    1845               0 :     kern_msg_hdr.ndescv = 0;
    1846               0 :     kern_msg_hdr.ndesc_length = 0;
    1847                 :   } else {
    1848               0 :     sysaddr = NaClUserToSysAddrRange(natp->nap,
    1849                 :                                      (uintptr_t) kern_nanimh.descv,
    1850                 :                                      kern_nanimh.desc_length * sizeof(int32_t));
    1851               0 :     if (kNaClBadAddress == sysaddr) {
    1852               0 :       retval = -NACL_ABI_EFAULT;
    1853               0 :       goto cleanup;
    1854                 :     }
    1855                 : 
    1856                 :     /*
    1857                 :      * NB: for each descv entry, we read from NaCl app address space
    1858                 :      * exactly once.
    1859                 :      */
    1860               0 :     for (i = 0; i < kern_nanimh.desc_length; ++i) {
    1861               0 :       int32_t user_desc = ((volatile int32_t *) sysaddr)[i];
    1862                 :       /* fetch it once */
    1863                 : 
    1864               0 :       if (kKnownInvalidDescNumber == user_desc) {
    1865               0 :         kern_desc[i] = (struct NaClDesc *) NaClDescInvalidMake();
    1866                 :       } else {
    1867                 :         /* NaCl modules are ILP32, so this works on ILP32 and LP64 systems */
    1868               0 :         kern_desc[i] = NaClGetDesc(natp->nap, user_desc);
    1869                 :       }
    1870               0 :       if (NULL == kern_desc[i]) {
    1871               0 :         retval = -NACL_ABI_EBADF;
    1872               0 :         goto cleanup;
    1873                 :       }
    1874                 :     }
    1875               0 :     kern_msg_hdr.ndescv = kern_desc;
    1876               0 :     kern_msg_hdr.ndesc_length = kern_nanimh.desc_length;
    1877                 :   }
    1878               0 :   kern_msg_hdr.flags = kern_nanimh.flags;
    1879                 : 
    1880               0 :   ssize_retval = NaClImcSendTypedMessage(ndp, &kern_msg_hdr, flags);
    1881                 : 
    1882               0 :   if (NaClSSizeIsNegErrno(&ssize_retval)) {
    1883                 :     /*
    1884                 :      * NaClWouldBlock uses TSD (for both the errno-based and
    1885                 :      * GetLastError()-based implementations), so this is threadsafe.
    1886                 :      */
    1887               0 :     if (0 != (flags & NACL_DONT_WAIT) && NaClWouldBlock()) {
    1888               0 :       retval = -NACL_ABI_EAGAIN;
    1889               0 :     } else if (-NACL_ABI_EMSGSIZE == ssize_retval) {
    1890                 :       /*
    1891                 :        * Allow the caller to handle the case when imc_sendmsg fails because
    1892                 :        * the message is too large for the system to send in one piece.
    1893                 :        */
    1894               0 :       retval = -NACL_ABI_EMSGSIZE;
    1895                 :     } else {
    1896                 :       /*
    1897                 :        * TODO(bsy): the else case is some mysterious internal error.
    1898                 :        * Should we destroy the ndp or otherwise mark it as bad?  Was
    1899                 :        * the failure atomic?  Did it send some partial data?  Linux
    1900                 :        * implementation appears okay.
    1901                 :        */
    1902               0 :       retval = -NACL_ABI_EIO;
    1903                 :     }
    1904                 :   } else if (ssize_retval > INT32_MAX || ssize_retval < INT32_MIN) {
    1905                 :     retval = -NACL_ABI_EOVERFLOW;
    1906                 :   } else {
    1907                 :     /* cast is safe due to range checks above */
    1908               0 :     retval = (int32_t)ssize_retval;
    1909                 :   }
    1910                 : 
    1911               0 : cleanup:
    1912               0 :   for (i = 0; i < kern_nanimh.desc_length; ++i) {
    1913               0 :     if (NULL != kern_desc[i]) {
    1914               0 :       NaClDescUnref(kern_desc[i]);
    1915               0 :       kern_desc[i] = NULL;
    1916                 :     }
    1917                 :   }
    1918               0 :   NaClDescUnref(ndp);
    1919               0 : cleanup_leave:
    1920               0 :   NaClSysCommonThreadSyscallLeave(natp);
    1921               0 :   NaClLog(3, "NaClCommonSysImc_Sendmsg: returning %d\n", retval);
    1922               0 :   return retval;
    1923                 : }
    1924                 : 
    1925                 : int32_t NaClCommonSysImc_Recvmsg(struct NaClAppThread         *natp,
    1926                 :                                  int                          d,
    1927                 :                                  struct NaClAbiNaClImcMsgHdr  *nanimhp,
    1928               0 :                                  int                          flags) {
    1929               0 :   int32_t                               retval = -NACL_ABI_EINVAL;
    1930                 :   ssize_t                               ssize_retval;
    1931                 :   uintptr_t                             sysaddr;
    1932                 :   struct NaClAbiNaClImcMsgHdr volatile  *kern_nanimhp;
    1933                 :   size_t                                i;
    1934                 :   struct NaClDesc                       *ndp;
    1935                 :   struct NaClAbiNaClImcMsgHdr           kern_nanimh;
    1936                 :   struct NaClAbiNaClImcMsgIoVec         kern_naiov[NACL_ABI_IMC_IOVEC_MAX];
    1937                 :   struct NaClImcMsgIoVec                kern_iov[NACL_ABI_IMC_IOVEC_MAX];
    1938                 :   int32_t volatile                      *kern_descv;
    1939                 :   struct NaClImcTypedMsgHdr             recv_hdr;
    1940                 :   struct NaClDesc                       *new_desc[NACL_ABI_IMC_DESC_MAX];
    1941                 :   nacl_abi_size_t                       num_user_desc;
    1942               0 :   struct NaClDesc                       *invalid_desc = NULL;
    1943                 : 
    1944               0 :   NaClLog(3,
    1945                 :           ("Entered NaClCommonSysImc_RecvMsg(0x%08"NACL_PRIxPTR", %d,"
    1946                 :            " 0x%08"NACL_PRIxPTR")\n"),
    1947                 :           (uintptr_t) natp, d, (uintptr_t) nanimhp);
    1948                 : 
    1949               0 :   NaClSysCommonThreadSyscallEnter(natp);
    1950                 : 
    1951                 :   /*
    1952                 :    * First, we validate user-supplied message headers before
    1953                 :    * allocating a receive buffer.
    1954                 :    */
    1955               0 :   sysaddr = NaClUserToSysAddrRange(natp->nap,
    1956                 :                                    (uintptr_t) nanimhp,
    1957                 :                                    sizeof *nanimhp);
    1958               0 :   if (kNaClBadAddress == sysaddr) {
    1959               0 :     NaClLog(4, "NaClImcMsgHdr not in user address space\n");
    1960               0 :     retval = -NACL_ABI_EFAULT;
    1961               0 :     goto cleanup_leave;
    1962                 :   }
    1963               0 :   kern_nanimhp = (struct NaClAbiNaClImcMsgHdr volatile *) sysaddr;
    1964               0 :   kern_nanimh = *kern_nanimhp;
    1965                 :   /* copy before validating */
    1966                 : 
    1967               0 :   if (kern_nanimh.iov_length > NACL_ABI_IMC_IOVEC_MAX) {
    1968               0 :     NaClLog(4, "gather/scatter array too large: %"NACL_PRIdNACL_SIZE"\n",
    1969                 :             kern_nanimh.iov_length);
    1970               0 :     retval = -NACL_ABI_EINVAL;
    1971               0 :     goto cleanup_leave;
    1972                 :   }
    1973               0 :   if (kern_nanimh.desc_length > NACL_ABI_IMC_USER_DESC_MAX) {
    1974               0 :     NaClLog(4, "handle vector too long: %"NACL_PRIdNACL_SIZE"\n",
    1975                 :             kern_nanimh.desc_length);
    1976               0 :     retval = -NACL_ABI_EINVAL;
    1977               0 :     goto cleanup_leave;
    1978                 :   }
    1979                 : 
    1980               0 :   if (kern_nanimh.iov_length > 0) {
    1981               0 :     sysaddr = NaClUserToSysAddrRange(natp->nap,
    1982                 :                                      (uintptr_t) kern_nanimh.iov,
    1983                 :                                      (kern_nanimh.iov_length
    1984                 :                                       * sizeof kern_naiov[0]));
    1985               0 :     if (kNaClBadAddress == sysaddr) {
    1986               0 :       NaClLog(4, "gather/scatter array not in user address space\n");
    1987               0 :       retval = -NACL_ABI_EFAULT;
    1988               0 :       goto cleanup_leave;
    1989                 :     }
    1990                 :     /*
    1991                 :      * Copy IOV array into kernel space.  Validate this snapshot and do
    1992                 :      * user->kernel address conversions on this snapshot.
    1993                 :      */
    1994               0 :     memcpy(kern_naiov, (void *) sysaddr,
    1995                 :            kern_nanimh.iov_length * sizeof kern_naiov[0]);
    1996                 :     /*
    1997                 :      * Convert every IOV base from user to system address, validate
    1998                 :      * range of bytes are really in user address space.
    1999                 :      */
    2000                 : 
    2001               0 :     for (i = 0; i < kern_nanimh.iov_length; ++i) {
    2002               0 :       sysaddr = NaClUserToSysAddrRange(natp->nap,
    2003                 :                                        (uintptr_t) kern_naiov[i].base,
    2004                 :                                        kern_naiov[i].length);
    2005               0 :       if (kNaClBadAddress == sysaddr) {
    2006               0 :         NaClLog(4, "iov number %"NACL_PRIdS" not entirely in user space\n", i);
    2007               0 :         retval = -NACL_ABI_EFAULT;
    2008               0 :         goto cleanup_leave;
    2009                 :       }
    2010               0 :       kern_iov[i].base = (void *) sysaddr;
    2011               0 :       kern_iov[i].length = kern_naiov[i].length;
    2012                 :     }
    2013                 :   }
    2014                 : 
    2015               0 :   if (kern_nanimh.desc_length > 0) {
    2016               0 :     sysaddr = NaClUserToSysAddrRange(natp->nap,
    2017                 :                                      (uintptr_t) kern_nanimh.descv,
    2018                 :                                      kern_nanimh.desc_length * sizeof(int32_t));
    2019               0 :     if (kNaClBadAddress == sysaddr) {
    2020               0 :       retval = -NACL_ABI_EFAULT;
    2021               0 :       goto cleanup_leave;
    2022                 :     }
    2023               0 :     kern_descv = (int32_t volatile *) sysaddr;
    2024                 :   } else {
    2025                 :     /* ensure we will SEGV if there's a bug below */
    2026               0 :     kern_descv = (int32_t volatile *) NULL;
    2027                 :   }
    2028                 : 
    2029               0 :   ndp = NaClGetDesc(natp->nap, d);
    2030               0 :   if (NULL == ndp) {
    2031               0 :     NaClLog(4, "receiving descriptor invalid\n");
    2032               0 :     retval = -NACL_ABI_EBADF;
    2033               0 :     goto cleanup_leave;
    2034                 :   }
    2035                 : 
    2036               0 :   recv_hdr.iov = kern_iov;
    2037               0 :   recv_hdr.iov_length = kern_nanimh.iov_length;
    2038                 : 
    2039               0 :   recv_hdr.ndescv = new_desc;
    2040               0 :   recv_hdr.ndesc_length = NACL_ARRAY_SIZE(new_desc);
    2041               0 :   memset(new_desc, 0, sizeof new_desc);
    2042                 : 
    2043               0 :   recv_hdr.flags = 0;  /* just to make it obvious; IMC will clear it for us */
    2044                 : 
    2045               0 :   ssize_retval = NaClImcRecvTypedMessage(ndp, &recv_hdr, flags,
    2046                 :       (struct NaClDescQuotaInterface *) natp->nap->reverse_quota_interface);
    2047                 :   /*
    2048                 :    * retval is number of user payload bytes received and excludes the
    2049                 :    * header bytes.
    2050                 :    */
    2051               0 :   NaClLog(3, "NaClCommonSysImc_RecvMsg: "
    2052                 :           "NaClImcRecvTypedMessage returned %"NACL_PRIdS"\n",
    2053                 :           ssize_retval);
    2054               0 :   if (NaClSSizeIsNegErrno(&ssize_retval)) {
    2055                 :     /* negative error numbers all have valid 32-bit representations,
    2056                 :      * so this cast is safe. */
    2057               0 :     retval = (int32_t) ssize_retval;
    2058               0 :     goto cleanup;
    2059                 :   } else if (ssize_retval > INT32_MAX || ssize_retval < INT32_MIN) {
    2060                 :     retval = -NACL_ABI_EOVERFLOW;
    2061                 :     goto cleanup;
    2062                 :   } else {
    2063                 :     /* cast is safe due to range check above */
    2064               0 :     retval = (int32_t) ssize_retval;
    2065                 :   }
    2066                 : 
    2067                 :   /*
    2068                 :    * NB: recv_hdr.flags may contain NACL_ABI_MESSAGE_TRUNCATED and/or
    2069                 :    * NACL_ABI_HANDLES_TRUNCATED.
    2070                 :    */
    2071                 : 
    2072               0 :   kern_nanimh.flags = recv_hdr.flags;
    2073                 : 
    2074                 :   /*
    2075                 :    * Now internalize the NaClHandles as NaClDesc objects.
    2076                 :    */
    2077               0 :   num_user_desc = recv_hdr.ndesc_length;
    2078                 : 
    2079               0 :   if (kern_nanimh.desc_length < num_user_desc) {
    2080               0 :     kern_nanimh.flags |= NACL_ABI_RECVMSG_DESC_TRUNCATED;
    2081               0 :     for (i = kern_nanimh.desc_length; i < num_user_desc; ++i) {
    2082               0 :       NaClDescUnref(new_desc[i]);
    2083               0 :       new_desc[i] = NULL;
    2084                 :     }
    2085               0 :     num_user_desc = kern_nanimh.desc_length;
    2086                 :   }
    2087                 : 
    2088               0 :   invalid_desc = (struct NaClDesc *) NaClDescInvalidMake();
    2089               0 :   for (i = 0; i < num_user_desc; ++i) {
    2090                 :     /* write out to user space the descriptor numbers */
    2091               0 :     if (invalid_desc == new_desc[i]) {
    2092               0 :       kern_descv[i] = kKnownInvalidDescNumber;
    2093                 :     } else {
    2094               0 :       kern_descv[i] = NaClSetAvail(natp->nap, new_desc[i]);
    2095                 :     }
    2096               0 :     new_desc[i] = NULL;
    2097                 :   }
    2098                 : 
    2099               0 :   kern_nanimh.desc_length = num_user_desc;
    2100               0 :   *kern_nanimhp = kern_nanimh;
    2101                 :   /* copy out updated desc count, flags */
    2102               0 :  cleanup:
    2103               0 :   if (retval < 0) {
    2104               0 :     for (i = 0; i < NACL_ARRAY_SIZE(new_desc); ++i) {
    2105               0 :       if (NULL != new_desc[i]) {
    2106               0 :         NaClDescUnref(new_desc[i]);
    2107               0 :         new_desc[i] = NULL;
    2108                 :       }
    2109                 :     }
    2110                 :   }
    2111               0 :   NaClDescUnref(ndp);
    2112               0 :   NaClDescSafeUnref(invalid_desc);
    2113               0 :   NaClLog(3, "NaClCommonSysImc_RecvMsg: returning %d\n", retval);
    2114               0 : cleanup_leave:
    2115               0 :   NaClSysCommonThreadSyscallLeave(natp);
    2116               0 :   return retval;
    2117                 : }
    2118                 : 
    2119                 : int32_t NaClCommonSysImc_Mem_Obj_Create(struct NaClAppThread  *natp,
    2120               0 :                                         size_t                size) {
    2121               0 :   int32_t               retval = -NACL_ABI_EINVAL;
    2122                 :   struct NaClDescImcShm *shmp;
    2123                 :   off_t                 size_as_off;
    2124                 : 
    2125               0 :   NaClLog(3,
    2126                 :           ("Entered NaClCommonSysImc_Mem_Obj_Create(0x%08"NACL_PRIxPTR
    2127                 :            " 0x%08"NACL_PRIxS")\n"),
    2128                 :           (uintptr_t) natp, size);
    2129                 : 
    2130               0 :   if (0 != (size & (NACL_MAP_PAGESIZE - 1))) {
    2131               0 :     return -NACL_ABI_EINVAL;
    2132                 :   }
    2133                 :   /*
    2134                 :    * TODO(bsy): policy about maximum shm object size should be
    2135                 :    * enforced here.
    2136                 :    */
    2137               0 :   size_as_off = (off_t) size;
    2138               0 :   if (size_as_off < 0) {
    2139               0 :     return -NACL_ABI_EINVAL;
    2140                 :   }
    2141                 : 
    2142               0 :   shmp = NULL;
    2143                 : 
    2144               0 :   NaClSysCommonThreadSyscallEnter(natp);
    2145                 : 
    2146               0 :   shmp = malloc(sizeof *shmp);
    2147               0 :   if (NULL == shmp) {
    2148               0 :     retval = -NACL_ABI_ENOMEM;
    2149               0 :     goto cleanup;
    2150                 :   }
    2151                 : 
    2152               0 :   if (!NaClDescImcShmAllocCtor(shmp, size_as_off, /* executable= */ 0)) {
    2153               0 :     retval = -NACL_ABI_ENOMEM;  /* is this reasonable? */
    2154               0 :     goto cleanup;
    2155                 :   }
    2156                 : 
    2157               0 :   retval = NaClSetAvail(natp->nap, (struct NaClDesc *) shmp);
    2158               0 :   shmp = NULL;
    2159                 : 
    2160               0 : cleanup:
    2161               0 :   free(shmp);
    2162                 : 
    2163               0 :   NaClSysCommonThreadSyscallLeave(natp);
    2164                 : 
    2165               0 :   return retval;
    2166                 : }
    2167                 : 
    2168                 : int32_t NaClCommonSysImc_SocketPair(struct NaClAppThread *natp,
    2169               0 :                                     uint32_t             descs_out) {
    2170                 :   uintptr_t               sysaddr;
    2171                 :   volatile int32_t        *descs_out_trusted;
    2172                 :   struct NaClDesc         *pair[2];
    2173                 :   int32_t                 retval;
    2174                 : 
    2175               0 :   NaClLog(3,
    2176                 :           ("Entered NaClCommonSysImc_SocketPair(0x%08"NACL_PRIxPTR
    2177                 :            " 0x%08"NACL_PRIx32")\n"),
    2178                 :           (uintptr_t) natp, descs_out);
    2179                 : 
    2180               0 :   NaClSysCommonThreadSyscallEnter(natp);
    2181                 : 
    2182               0 :   sysaddr = NaClUserToSysAddrRange(natp->nap, descs_out,
    2183                 :                                    2 * sizeof(*descs_out_trusted));
    2184               0 :   if (kNaClBadAddress == sysaddr) {
    2185               0 :     NaClLog(1,
    2186                 :             ("NaClCommonSysImc_Socket_Pair: bad output descriptor array "
    2187                 :              " (0x%08"NACL_PRIx32")\n"),
    2188                 :             descs_out);
    2189               0 :     retval = -NACL_ABI_EFAULT;
    2190               0 :     goto cleanup;
    2191                 :   }
    2192               0 :   descs_out_trusted = (volatile int32_t *) sysaddr;
    2193                 : 
    2194               0 :   retval = NaClCommonDescSocketPair(pair);
    2195               0 :   if (0 != retval) {
    2196               0 :     goto cleanup;
    2197                 :   }
    2198                 : 
    2199               0 :   descs_out_trusted[0] = NaClSetAvail(natp->nap, pair[0]);
    2200               0 :   descs_out_trusted[1] = NaClSetAvail(natp->nap, pair[1]);
    2201                 : 
    2202               0 :   retval = 0;
    2203               0 : cleanup:
    2204               0 :   NaClSysCommonThreadSyscallLeave(natp);
    2205               0 :   return retval;
    2206                 : }
    2207                 : 
    2208                 : int32_t NaClCommonSysTls_Init(struct NaClAppThread  *natp,
    2209               3 :                               void                  *thread_ptr) {
    2210               3 :   int32_t   retval = -NACL_ABI_EINVAL;
    2211                 :   uintptr_t sys_tls;
    2212                 : 
    2213               3 :   NaClLog(3,
    2214                 :           ("Entered NaClCommonSysTls_Init(0x%08"NACL_PRIxPTR
    2215                 :            ", 0x%08"NACL_PRIxPTR")\n"),
    2216                 :           (uintptr_t) natp, (uintptr_t) thread_ptr);
    2217                 : 
    2218               3 :   NaClSysCommonThreadSyscallEnter(natp);
    2219                 : 
    2220                 :   /* Verify that the address in the app's range and translated from
    2221                 :    * nacl module address to service runtime address - a nop on ARM
    2222                 :    */
    2223               3 :   sys_tls = NaClUserToSysAddrRange(natp->nap, (uintptr_t) thread_ptr, 4);
    2224               3 :   NaClLog(4,
    2225                 :           "NaClCommonSysTls_Init: thread_ptr 0x%p, sys_tls 0x%"NACL_PRIxPTR"\n",
    2226                 :           thread_ptr, sys_tls);
    2227               3 :   if (kNaClBadAddress == sys_tls) {
    2228               0 :     retval = -NACL_ABI_EFAULT;
    2229               0 :     goto cleanup;
    2230                 :   }
    2231                 : 
    2232               3 :   if (0 == NaClTlsChange(natp, (void *) sys_tls)) {
    2233               0 :     retval = -NACL_ABI_EINVAL;
    2234               0 :     goto cleanup;
    2235                 :   }
    2236               3 :   natp->sys_tls = sys_tls;
    2237               3 :   *natp->usr_tlsp = (uint32_t) (uintptr_t) thread_ptr;
    2238               3 :   retval = 0;
    2239               3 : cleanup:
    2240               3 :   NaClSysCommonThreadSyscallLeave(natp);
    2241               3 :   return retval;
    2242                 : }
    2243                 : 
    2244                 : int32_t NaClCommonSysThread_Create(struct NaClAppThread *natp,
    2245                 :                                    void                 *prog_ctr,
    2246                 :                                    void                 *stack_ptr,
    2247                 :                                    void                 *thread_ptr,
    2248               0 :                                    void                 *second_thread_ptr) {
    2249               0 :   int32_t     retval = -NACL_ABI_EINVAL;
    2250                 :   uintptr_t   sys_tls;
    2251                 :   uintptr_t   sys_stack;
    2252                 : 
    2253               0 :   NaClLog(3,
    2254                 :           ("Entered NaClCommonSysThread_Create(0x%08"NACL_PRIxPTR
    2255                 :            " pc=0x%08"NACL_PRIxPTR", sp=0x%08"NACL_PRIxPTR", thread_ptr=0x%08"
    2256                 :            NACL_PRIxPTR")\n"),
    2257                 :           (uintptr_t) natp, (uintptr_t) prog_ctr, (uintptr_t) stack_ptr,
    2258                 :           (uintptr_t) thread_ptr);
    2259                 : 
    2260               0 :   NaClSysCommonThreadSyscallEnter(natp);
    2261                 : 
    2262                 :   /* make sure that the thread start function is in the text region */
    2263               0 :   if ((uintptr_t) prog_ctr >= natp->nap->dynamic_text_end) {
    2264               0 :     NaClLog(LOG_ERROR, "bad pc start\n");
    2265               0 :     retval = -NACL_ABI_EFAULT;
    2266               0 :     goto cleanup;
    2267                 :   }
    2268                 :   /* make sure that the thread start function is aligned */
    2269                 :   /* TODO(robertm): there should be a function for this test */
    2270                 : 
    2271                 : #if 0 == NACL_DANGEROUS_DEBUG_MODE_DISABLE_INNER_SANDBOX
    2272               0 :   if (0 != ((natp->nap->bundle_size - 1) & (uintptr_t) prog_ctr)) {
    2273               0 :     NaClLog(LOG_ERROR, "bad pc alignment\n");
    2274               0 :     retval = -NACL_ABI_EINVAL;
    2275               0 :     goto cleanup;
    2276                 :   }
    2277                 : #endif
    2278                 :   /* we do not enforce stack alignment, just check for validity */
    2279               0 :   sys_stack = NaClUserToSysAddr(natp->nap, (uintptr_t) stack_ptr);
    2280               0 :   if (kNaClBadAddress == sys_stack) {
    2281               0 :     NaClLog(LOG_ERROR, "bad stack\n");
    2282               0 :     retval = -NACL_ABI_EFAULT;
    2283               0 :     goto cleanup;
    2284                 :   }
    2285               0 :   sys_tls = NaClUserToSysAddrRange(natp->nap, (uintptr_t) thread_ptr, 4);
    2286               0 :   if (kNaClBadAddress == sys_tls) {
    2287               0 :     NaClLog(LOG_ERROR, "bad TLS pointer\n");
    2288               0 :     retval = -NACL_ABI_EFAULT;
    2289               0 :     goto cleanup;
    2290                 :   }
    2291                 : 
    2292               0 :   NaClVmHoleWaitToStartThread(natp->nap);
    2293                 : 
    2294               0 :   retval = NaClCreateAdditionalThread(natp->nap,
    2295                 :                                       (uintptr_t) prog_ctr,
    2296                 :                                       sys_stack,
    2297                 :                                       sys_tls,
    2298                 :                                       (uint32_t) (uintptr_t) second_thread_ptr);
    2299                 : 
    2300               0 : cleanup:
    2301               0 :   NaClSysCommonThreadSyscallLeave(natp);
    2302               0 :   return retval;
    2303                 : }
    2304                 : 
    2305                 : /*
    2306                 :  * This is not used on x86-64 and its functionality is replaced by
    2307                 :  * NaClGetTlsFastPath (see nacl_syscall_64.S).
    2308                 :  */
    2309             310 : int32_t NaClCommonSysTlsGet(struct NaClAppThread *natp) {
    2310                 :   uint32_t user_tls;
    2311                 : 
    2312                 :   /* too frequently used, and syscall-number level logging suffices */
    2313             310 :   user_tls = (int32_t) NaClSysToUser(natp->nap, natp->sys_tls);
    2314             310 :   return user_tls;
    2315                 : }
    2316                 : 
    2317                 : int32_t NaClSysSecond_Tls_Set(struct NaClAppThread *natp,
    2318               0 :                               uint32_t             new_value) {
    2319               0 :   natp->tls2 = new_value;
    2320               0 :   return 0;
    2321                 : }
    2322                 : 
    2323               0 : int32_t NaClSysSecond_Tls_Get(struct NaClAppThread *natp) {
    2324               0 :   return natp->tls2;
    2325                 : }
    2326                 : 
    2327                 : int NaClCommonSysThread_Nice(struct NaClAppThread *natp,
    2328               0 :                              const int            nice) {
    2329                 :   /* Note: implementation of nacl_thread_nice is OS dependent. */
    2330                 :   UNREFERENCED_PARAMETER(natp);
    2331               0 :   return nacl_thread_nice(nice);
    2332                 : }
    2333                 : 
    2334               0 : int32_t NaClCommonSysMutex_Create(struct NaClAppThread *natp) {
    2335               0 :   int32_t              retval = -NACL_ABI_EINVAL;
    2336                 :   struct NaClDescMutex *desc;
    2337                 : 
    2338               0 :   NaClLog(3,
    2339                 :           ("Entered NaClCommonSysMutex_Create(0x%08"NACL_PRIxPTR")\n"),
    2340                 :           (uintptr_t) natp);
    2341                 : 
    2342               0 :   NaClSysCommonThreadSyscallEnter(natp);
    2343                 : 
    2344               0 :   desc = malloc(sizeof(*desc));
    2345                 : 
    2346               0 :   if (!desc || !NaClDescMutexCtor(desc)) {
    2347               0 :     retval = -NACL_ABI_ENOMEM;
    2348               0 :     goto cleanup;
    2349                 :   }
    2350                 : 
    2351               0 :   retval = NaClSetAvail(natp->nap, (struct NaClDesc *) desc);
    2352               0 :   desc = NULL;
    2353               0 : cleanup:
    2354               0 :   free(desc);
    2355               0 :   NaClSysCommonThreadSyscallLeave(natp);
    2356               0 :   NaClLog(3,
    2357                 :           ("NaClCommonSysMutex_Create(0x%08"NACL_PRIxPTR") = %d\n"),
    2358                 :           (uintptr_t) natp, retval);
    2359               0 :   return retval;
    2360                 : }
    2361                 : 
    2362                 : int32_t NaClCommonSysMutex_Lock(struct NaClAppThread  *natp,
    2363               0 :                                 int32_t               mutex_handle) {
    2364               0 :   int32_t               retval = -NACL_ABI_EINVAL;
    2365                 :   struct NaClDesc       *desc;
    2366                 : 
    2367               0 :   NaClLog(3,
    2368                 :           ("Entered NaClCommonSysMutex_Lock(0x%08"NACL_PRIxPTR", %d)\n"),
    2369                 :           (uintptr_t) natp, mutex_handle);
    2370                 : 
    2371               0 :   NaClSysCommonThreadSyscallEnter(natp);
    2372                 : 
    2373               0 :   desc = NaClGetDesc(natp->nap, mutex_handle);
    2374                 : 
    2375               0 :   if (NULL == desc) {
    2376               0 :     retval = -NACL_ABI_EBADF;
    2377               0 :     goto cleanup;
    2378                 :   }
    2379                 : 
    2380               0 :   retval = (*((struct NaClDescVtbl const *) desc->base.vtbl)->Lock)(desc);
    2381               0 :   NaClDescUnref(desc);
    2382                 : 
    2383               0 : cleanup:
    2384               0 :   NaClSysCommonThreadSyscallLeave(natp);
    2385               0 :   return retval;
    2386                 : }
    2387                 : 
    2388                 : int32_t NaClCommonSysMutex_Unlock(struct NaClAppThread  *natp,
    2389               0 :                                   int32_t               mutex_handle) {
    2390               0 :   int32_t         retval = -NACL_ABI_EINVAL;
    2391                 :   struct NaClDesc *desc;
    2392                 : 
    2393               0 :   NaClLog(3,
    2394                 :           ("Entered NaClCommonSysMutex_Unlock(0x%08"NACL_PRIxPTR", %d)\n"),
    2395                 :           (uintptr_t) natp, mutex_handle);
    2396                 : 
    2397               0 :   NaClSysCommonThreadSyscallEnter(natp);
    2398                 : 
    2399               0 :   desc = NaClGetDesc(natp->nap, mutex_handle);
    2400                 : 
    2401               0 :   if (NULL == desc) {
    2402               0 :     retval = -NACL_ABI_EBADF;
    2403               0 :     goto cleanup;
    2404                 :   }
    2405                 : 
    2406               0 :   retval = (*((struct NaClDescVtbl const *) desc->base.vtbl)->Unlock)(desc);
    2407               0 :   NaClDescUnref(desc);
    2408                 : 
    2409               0 : cleanup:
    2410               0 :   NaClSysCommonThreadSyscallLeave(natp);
    2411               0 :   return retval;
    2412                 : }
    2413                 : 
    2414                 : int32_t NaClCommonSysMutex_Trylock(struct NaClAppThread   *natp,
    2415               0 :                                   int32_t                 mutex_handle) {
    2416               0 :   int32_t         retval = -NACL_ABI_EINVAL;
    2417                 :   struct NaClDesc *desc;
    2418                 : 
    2419               0 :   NaClLog(3,
    2420                 :           ("Entered NaClCommonSysMutex_Trylock(0x%08"NACL_PRIxPTR", %d)\n"),
    2421                 :           (uintptr_t) natp, mutex_handle);
    2422                 : 
    2423               0 :   NaClSysCommonThreadSyscallEnter(natp);
    2424                 : 
    2425               0 :   desc = NaClGetDesc(natp->nap, mutex_handle);
    2426                 : 
    2427               0 :   if (NULL == desc) {
    2428               0 :     retval = -NACL_ABI_EBADF;
    2429               0 :     goto cleanup;
    2430                 :   }
    2431                 : 
    2432               0 :   retval = (*((struct NaClDescVtbl const *) desc->base.vtbl)->TryLock)(desc);
    2433               0 :   NaClDescUnref(desc);
    2434                 : 
    2435               0 : cleanup:
    2436               0 :   NaClSysCommonThreadSyscallLeave(natp);
    2437               0 :   return retval;
    2438                 : }
    2439                 : 
    2440               0 : int32_t NaClCommonSysCond_Create(struct NaClAppThread *natp) {
    2441               0 :   int32_t                retval = -NACL_ABI_EINVAL;
    2442                 :   struct NaClDescCondVar *desc;
    2443                 : 
    2444               0 :   NaClLog(3,
    2445                 :           ("Entered NaClCommonSysCond_Create(0x%08"NACL_PRIxPTR")\n"),
    2446                 :           (uintptr_t) natp);
    2447                 : 
    2448               0 :   NaClSysCommonThreadSyscallEnter(natp);
    2449                 : 
    2450               0 :   desc = malloc(sizeof(*desc));
    2451                 : 
    2452               0 :   if (!desc || !NaClDescCondVarCtor(desc)) {
    2453               0 :     retval = -NACL_ABI_ENOMEM;
    2454               0 :     goto cleanup;
    2455                 :   }
    2456                 : 
    2457               0 :   retval = NaClSetAvail(natp->nap, (struct NaClDesc *)desc);
    2458               0 :   desc = NULL;
    2459               0 : cleanup:
    2460               0 :   free(desc);
    2461               0 :   NaClSysCommonThreadSyscallLeave(natp);
    2462               0 :   NaClLog(3,
    2463                 :           ("NaClCommonSysCond_Create(0x%08"NACL_PRIxPTR") = %d\n"),
    2464                 :           (uintptr_t) natp, retval);
    2465               0 :   return retval;
    2466                 : }
    2467                 : 
    2468                 : int32_t NaClCommonSysCond_Wait(struct NaClAppThread *natp,
    2469                 :                                int32_t              cond_handle,
    2470               0 :                                int32_t              mutex_handle) {
    2471               0 :   int32_t         retval = -NACL_ABI_EINVAL;
    2472                 :   struct NaClDesc *cv_desc;
    2473                 :   struct NaClDesc *mutex_desc;
    2474                 : 
    2475               0 :   NaClLog(3,
    2476                 :           ("Entered NaClCommonSysCond_Wait(0x%08"NACL_PRIxPTR", %d, %d)\n"),
    2477                 :           (uintptr_t) natp, cond_handle, mutex_handle);
    2478                 : 
    2479               0 :   NaClSysCommonThreadSyscallEnter(natp);
    2480                 : 
    2481               0 :   cv_desc = NaClGetDesc(natp->nap, cond_handle);
    2482                 : 
    2483               0 :   if (NULL == cv_desc) {
    2484               0 :     retval = -NACL_ABI_EBADF;
    2485               0 :     goto cleanup;
    2486                 :   }
    2487                 : 
    2488               0 :   mutex_desc = NaClGetDesc(natp->nap, mutex_handle);
    2489               0 :   if (NULL == mutex_desc) {
    2490               0 :     NaClDescUnref(cv_desc);
    2491               0 :     retval = -NACL_ABI_EBADF;
    2492               0 :     goto cleanup;
    2493                 :   }
    2494                 : 
    2495               0 :   retval = (*((struct NaClDescVtbl const *) cv_desc->base.vtbl)->
    2496                 :             Wait)(cv_desc, mutex_desc);
    2497               0 :   NaClDescUnref(cv_desc);
    2498               0 :   NaClDescUnref(mutex_desc);
    2499                 : 
    2500               0 : cleanup:
    2501               0 :   NaClSysCommonThreadSyscallLeave(natp);
    2502               0 :   return retval;
    2503                 : }
    2504                 : 
    2505                 : int32_t NaClCommonSysCond_Signal(struct NaClAppThread *natp,
    2506               0 :                                  int32_t              cond_handle) {
    2507               0 :   int32_t         retval = -NACL_ABI_EINVAL;
    2508                 :   struct NaClDesc *desc;
    2509                 : 
    2510               0 :   NaClLog(3,
    2511                 :           ("Entered NaClCommonSysCond_Signal(0x%08"NACL_PRIxPTR", %d)\n"),
    2512                 :           (uintptr_t) natp, cond_handle);
    2513                 : 
    2514               0 :   NaClSysCommonThreadSyscallEnter(natp);
    2515                 : 
    2516               0 :   desc = NaClGetDesc(natp->nap, cond_handle);
    2517                 : 
    2518               0 :   if (NULL == desc) {
    2519               0 :     retval = -NACL_ABI_EBADF;
    2520               0 :     goto cleanup;
    2521                 :   }
    2522                 : 
    2523               0 :   retval = (*((struct NaClDescVtbl const *) desc->base.vtbl)->Signal)(desc);
    2524               0 :   NaClDescUnref(desc);
    2525               0 : cleanup:
    2526               0 :   NaClSysCommonThreadSyscallLeave(natp);
    2527               0 :   return retval;
    2528                 : }
    2529                 : 
    2530                 : int32_t NaClCommonSysCond_Broadcast(struct NaClAppThread  *natp,
    2531               0 :                                     int32_t               cond_handle) {
    2532                 :   struct NaClDesc *desc;
    2533               0 :   int32_t         retval = -NACL_ABI_EINVAL;
    2534                 : 
    2535               0 :   NaClLog(3,
    2536                 :           ("Entered NaClCommonSysCond_Broadcast(0x%08"NACL_PRIxPTR", %d)\n"),
    2537                 :           (uintptr_t) natp, cond_handle);
    2538                 : 
    2539               0 :   NaClSysCommonThreadSyscallEnter(natp);
    2540                 : 
    2541               0 :   desc = NaClGetDesc(natp->nap, cond_handle);
    2542                 : 
    2543               0 :   if (NULL == desc) {
    2544               0 :     retval = -NACL_ABI_EBADF;
    2545               0 :     goto cleanup;
    2546                 :   }
    2547                 : 
    2548               0 :   retval = (*((struct NaClDescVtbl const *) desc->base.vtbl)->Broadcast)(desc);
    2549               0 :   NaClDescUnref(desc);
    2550                 : 
    2551               0 : cleanup:
    2552               0 :   NaClSysCommonThreadSyscallLeave(natp);
    2553               0 :   return retval;
    2554                 : }
    2555                 : 
    2556                 : int32_t NaClCommonSysCond_Timed_Wait_Abs(struct NaClAppThread     *natp,
    2557                 :                                          int32_t                  cond_handle,
    2558                 :                                          int32_t                  mutex_handle,
    2559               0 :                                          struct nacl_abi_timespec *ts) {
    2560               0 :   int32_t                  retval = -NACL_ABI_EINVAL;
    2561                 :   struct NaClDesc          *cv_desc;
    2562                 :   struct NaClDesc          *mutex_desc;
    2563                 :   uintptr_t                sys_ts;
    2564                 :   struct nacl_abi_timespec trusted_ts;
    2565                 : 
    2566               0 :   NaClLog(3,
    2567                 :           ("Entered NaClCommonSysCond_Timed_Wait_Abs(0x%08"NACL_PRIxPTR
    2568                 :            ", %d, %d, 0x%08"NACL_PRIxPTR")\n"),
    2569                 :           (uintptr_t) natp, cond_handle, mutex_handle, (uintptr_t) ts);
    2570                 : 
    2571               0 :   NaClSysCommonThreadSyscallEnter(natp);
    2572                 : 
    2573               0 :   sys_ts = NaClUserToSysAddrRange(natp->nap,
    2574                 :                                   (uintptr_t) ts,
    2575                 :                                   sizeof(*ts));
    2576               0 :   if (kNaClBadAddress == sys_ts) {
    2577               0 :     retval = -NACL_ABI_EFAULT;
    2578               0 :     goto cleanup;
    2579                 :   }
    2580                 :   /* TODO(gregoryd): validate ts - do we have a limit for time to wait? */
    2581               0 :   memcpy(&trusted_ts, (void *) sys_ts, sizeof(trusted_ts));
    2582                 : 
    2583               0 :   cv_desc = NaClGetDesc(natp->nap, cond_handle);
    2584               0 :   if (NULL == cv_desc) {
    2585               0 :     retval = -NACL_ABI_EBADF;
    2586               0 :     goto cleanup;
    2587                 :   }
    2588                 : 
    2589               0 :   mutex_desc = NaClGetDesc(natp->nap, mutex_handle);
    2590               0 :   if (NULL == mutex_desc) {
    2591               0 :     NaClDescUnref(cv_desc);
    2592               0 :     retval = -NACL_ABI_EBADF;
    2593               0 :     goto cleanup;
    2594                 :   }
    2595                 : 
    2596               0 :   retval = (*((struct NaClDescVtbl const *) cv_desc->base.vtbl)->
    2597                 :             TimedWaitAbs)(cv_desc,
    2598                 :                           mutex_desc,
    2599                 :                           &trusted_ts);
    2600               0 :   NaClDescUnref(cv_desc);
    2601               0 :   NaClDescUnref(mutex_desc);
    2602               0 : cleanup:
    2603               0 :   NaClSysCommonThreadSyscallLeave(natp);
    2604               0 :   return retval;
    2605                 : }
    2606                 : 
    2607                 : int32_t NaClCommonSysSem_Create(struct NaClAppThread *natp,
    2608               0 :                                 int32_t              init_value) {
    2609               0 :   int32_t                  retval = -NACL_ABI_EINVAL;
    2610                 :   struct NaClDescSemaphore *desc;
    2611                 : 
    2612               0 :   NaClLog(3,
    2613                 :           ("Entered NaClCommonSysSem_Create(0x%08"NACL_PRIxPTR
    2614                 :            ", %d)\n"),
    2615                 :           (uintptr_t) natp, init_value);
    2616                 : 
    2617               0 :   NaClSysCommonThreadSyscallEnter(natp);
    2618                 : 
    2619               0 :   desc = malloc(sizeof(*desc));
    2620                 : 
    2621               0 :   if (!desc || !NaClDescSemaphoreCtor(desc, init_value)) {
    2622               0 :     retval = -NACL_ABI_ENOMEM;
    2623               0 :     goto cleanup;
    2624                 :   }
    2625                 : 
    2626               0 :   retval = NaClSetAvail(natp->nap, (struct NaClDesc *) desc);
    2627               0 :   desc = NULL;
    2628               0 : cleanup:
    2629               0 :   free(desc);
    2630               0 :   NaClSysCommonThreadSyscallLeave(natp);
    2631               0 :   return retval;
    2632                 : }
    2633                 : 
    2634                 : 
    2635                 : int32_t NaClCommonSysSem_Wait(struct NaClAppThread *natp,
    2636               0 :                               int32_t              sem_handle) {
    2637               0 :   int32_t         retval = -NACL_ABI_EINVAL;
    2638                 :   struct NaClDesc *desc;
    2639                 : 
    2640               0 :   NaClLog(3,
    2641                 :           ("Entered NaClCommonSysSem_Wait(0x%08"NACL_PRIxPTR
    2642                 :            ", %d)\n"),
    2643                 :           (uintptr_t) natp, sem_handle);
    2644                 : 
    2645               0 :   NaClSysCommonThreadSyscallEnter(natp);
    2646                 : 
    2647               0 :   desc = NaClGetDesc(natp->nap, sem_handle);
    2648                 : 
    2649               0 :   if (NULL == desc) {
    2650               0 :     retval = -NACL_ABI_EBADF;
    2651               0 :     goto cleanup;
    2652                 :   }
    2653                 : 
    2654                 :   /*
    2655                 :    * TODO(gregoryd): we have to decide on the syscall API: do we
    2656                 :    * switch to read/write/ioctl API or do we stay with the more
    2657                 :    * detailed API. Anyway, using a single syscall for waiting on all
    2658                 :    * synchronization objects makes sense.
    2659                 :    */
    2660               0 :   retval = (*((struct NaClDescVtbl const *) desc->base.vtbl)->SemWait)(desc);
    2661               0 :   NaClDescUnref(desc);
    2662               0 : cleanup:
    2663               0 :   NaClSysCommonThreadSyscallLeave(natp);
    2664               0 :   return retval;
    2665                 : }
    2666                 : 
    2667                 : int32_t NaClCommonSysSem_Post(struct NaClAppThread *natp,
    2668               0 :                               int32_t              sem_handle) {
    2669               0 :   int32_t         retval = -NACL_ABI_EINVAL;
    2670                 :   struct NaClDesc *desc;
    2671                 : 
    2672               0 :   NaClLog(3,
    2673                 :           ("Entered NaClCommonSysSem_Post(0x%08"NACL_PRIxPTR
    2674                 :            ", %d)\n"),
    2675                 :           (uintptr_t) natp, sem_handle);
    2676                 : 
    2677               0 :   NaClSysCommonThreadSyscallEnter(natp);
    2678                 : 
    2679               0 :   desc = NaClGetDesc(natp->nap, sem_handle);
    2680                 : 
    2681               0 :   if (NULL == desc) {
    2682               0 :     retval = -NACL_ABI_EBADF;
    2683               0 :     goto cleanup;
    2684                 :   }
    2685                 : 
    2686               0 :   retval = (*((struct NaClDescVtbl const *) desc->base.vtbl)->Post)(desc);
    2687               0 :   NaClDescUnref(desc);
    2688               0 : cleanup:
    2689               0 :   NaClSysCommonThreadSyscallLeave(natp);
    2690               0 :   return retval;
    2691                 : }
    2692                 : 
    2693                 : int32_t NaClCommonSysSem_Get_Value(struct NaClAppThread *natp,
    2694               0 :                                    int32_t              sem_handle) {
    2695               0 :   int32_t         retval = -NACL_ABI_EINVAL;
    2696                 :   struct NaClDesc *desc;
    2697                 : 
    2698               0 :   NaClLog(3,
    2699                 :           ("Entered NaClCommonSysSem_Get_Value(0x%08"NACL_PRIxPTR
    2700                 :            ", %d)\n"),
    2701                 :           (uintptr_t) natp, sem_handle);
    2702                 : 
    2703               0 :   NaClSysCommonThreadSyscallEnter(natp);
    2704                 : 
    2705               0 :   desc = NaClGetDesc(natp->nap, sem_handle);
    2706                 : 
    2707               0 :   if (NULL == desc) {
    2708               0 :     retval = -NACL_ABI_EBADF;
    2709               0 :     goto cleanup;
    2710                 :   }
    2711                 : 
    2712               0 :   retval = (*((struct NaClDescVtbl const *) desc->base.vtbl)->GetValue)(desc);
    2713               0 :   NaClDescUnref(desc);
    2714               0 : cleanup:
    2715               0 :   NaClSysCommonThreadSyscallLeave(natp);
    2716               0 :   return retval;
    2717                 : }
    2718                 : 
    2719                 : 
    2720                 : int32_t NaClCommonSysException_Handler(struct NaClAppThread *natp,
    2721                 :                                        uint32_t             handler_addr,
    2722               0 :                                        uint32_t             old_handler) {
    2723                 :   uintptr_t safe_old_handler;
    2724               0 :   if (!natp->nap->enable_exception_handling) {
    2725               0 :     return -NACL_ABI_ENOSYS;
    2726                 :   }
    2727               0 :   if (!NaClIsValidJumpTarget(natp->nap, handler_addr)) {
    2728               0 :     return -NACL_ABI_EFAULT;
    2729                 :   }
    2730               0 :   safe_old_handler = NaClUserToSysAddrNullOkay(natp->nap, old_handler);
    2731               0 :   if (kNaClBadAddress == safe_old_handler) {
    2732               0 :     return -NACL_ABI_EINVAL;
    2733                 :   }
    2734               0 :   NaClXMutexLock(&natp->nap->exception_mu);
    2735               0 :   if (old_handler) {
    2736               0 :     *(volatile uint32_t *) safe_old_handler = natp->nap->exception_handler;
    2737                 :   }
    2738               0 :   natp->nap->exception_handler = handler_addr;
    2739               0 :   NaClXMutexUnlock(&natp->nap->exception_mu);
    2740               0 :   return 0;
    2741                 : }
    2742                 : 
    2743                 : int32_t NaClCommonSysException_Stack(struct NaClAppThread *natp,
    2744                 :                                      uint32_t             stack_addr,
    2745               0 :                                      uint32_t             stack_size) {
    2746               0 :   if (!natp->nap->enable_exception_handling) {
    2747               0 :     return -NACL_ABI_ENOSYS;
    2748                 :   }
    2749               0 :   if (kNaClBadAddress == NaClUserToSysAddrNullOkay(natp->nap,
    2750                 :                                                    stack_addr + stack_size)) {
    2751               0 :     return -NACL_ABI_EINVAL;
    2752                 :   }
    2753               0 :   natp->user.exception_stack = stack_addr + stack_size;
    2754               0 :   return 0;
    2755                 : }
    2756                 : 
    2757               0 : int32_t NaClCommonSysException_Clear_Flag(struct NaClAppThread *natp) {
    2758               0 :   if (!natp->nap->enable_exception_handling) {
    2759               0 :     return -NACL_ABI_ENOSYS;
    2760                 :   }
    2761               0 :   natp->user.exception_flag = 0;
    2762               0 :   return 0;
    2763                 : }
    2764                 : 
    2765                 : 
    2766               0 : int32_t NaClCommonSysTest_InfoLeak(struct NaClAppThread *natp) {
    2767                 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86
    2768                 :   /*
    2769                 :    * Put some interesting bits into the x87 and SSE registers.
    2770                 :    */
    2771                 :   union fxsave {
    2772                 :     char buf[512];
    2773                 :     struct {
    2774                 :       uint16_t fcw;
    2775                 :       uint16_t fsw;
    2776                 :       uint16_t ftw;
    2777                 :       uint16_t fop;
    2778                 :       union {
    2779                 :         struct {
    2780                 :           uint64_t rip;
    2781                 :           uint64_t rdp;
    2782                 :         } x64;
    2783                 :         struct {
    2784                 :           uint32_t fpu_ip;
    2785                 :           uint32_t cs;
    2786                 :           uint32_t fpu_dp;
    2787                 :           uint32_t ds;
    2788                 :         } ia32;
    2789                 :       } bitness;
    2790                 :       uint32_t mxcsr;
    2791                 :       uint32_t mxcsr_mask;
    2792                 :       struct {
    2793                 :         uint8_t st[10];
    2794                 :         uint8_t reserved[6];
    2795                 :       } st_space[8];
    2796                 :       uint32_t xmm_space[64];
    2797                 :     } fxsave;
    2798                 :   };
    2799                 : 
    2800                 :   static const char tenbytes[10] = "SecretBits";
    2801                 :   static const char manybytes[256] =
    2802                 :       "Highly sensitive information must not be leaked to untrusted code!\n"
    2803                 :       "xyzzy\nplugh\nYou are likely to be eaten by a grue.\n"
    2804                 :       "When in the Course of human events it becomes necessary for one people"
    2805                 :       " to dissolve the political bands which have connected them with ...\n";
    2806                 : 
    2807                 : # ifdef __GNUC__
    2808                 :   union fxsave u __attribute__((aligned(16)));
    2809                 : # elif NACL_WINDOWS
    2810                 :   __declspec(align(16)) union fxsave u;
    2811                 : # else
    2812                 : #  error Unsupported platform
    2813                 : # endif
    2814                 : 
    2815                 :   int i;
    2816                 : 
    2817                 : # ifdef __GNUC__
    2818               0 :   __asm__("fxsave %0" : "=m" (u));
    2819                 : # elif NACL_WINDOWS
    2820                 : #  if NACL_BUILD_SUBARCH == 64
    2821                 :   {
    2822                 :     void DoFxsave(union fxsave *);
    2823                 :     DoFxsave(&u);
    2824                 :   }
    2825                 : #  else
    2826                 :   __asm {
    2827                 :     fxsave u
    2828                 :   };
    2829                 : #  endif
    2830                 : # else
    2831                 : # error Unsupported platform
    2832                 : # endif
    2833                 : 
    2834               0 :   for (i = 0; i < 8; ++i)
    2835               0 :     memcpy(&u.fxsave.st_space[i], tenbytes, sizeof(tenbytes));
    2836                 : 
    2837               0 :   memcpy(u.fxsave.xmm_space, manybytes, sizeof(u.fxsave.xmm_space));
    2838                 : 
    2839                 : # ifdef __GNUC__
    2840               0 :   __asm__ volatile("fxrstor %0" :: "m" (u));
    2841                 : # elif NACL_WINDOWS
    2842                 : #  if NACL_BUILD_SUBARCH == 64
    2843                 :   {
    2844                 :     void DoFxrstor(union fxsave *);
    2845                 :     DoFxrstor(&u);
    2846                 :   }
    2847                 : #  else
    2848                 :   __asm {
    2849                 :     fxrstor u
    2850                 :   };
    2851                 : #  endif
    2852                 : # else
    2853                 : # error Unsupported platform
    2854                 : # endif
    2855                 : 
    2856                 : #endif
    2857                 : 
    2858                 :   UNREFERENCED_PARAMETER(natp);
    2859                 : 
    2860               0 :   return -NACL_ABI_ENOSYS;
    2861                 : }
    2862                 : 
    2863               0 : static int NaClIsValidClockId(int clk_id) {
    2864               0 :   switch (clk_id) {
    2865                 :     case NACL_ABI_CLOCK_REALTIME:
    2866                 :     case NACL_ABI_CLOCK_MONOTONIC:
    2867                 :     case NACL_ABI_CLOCK_PROCESS_CPUTIME_ID:
    2868                 :     case NACL_ABI_CLOCK_THREAD_CPUTIME_ID:
    2869               0 :       return 1;
    2870                 :   }
    2871               0 :   return 0;
    2872                 : }
    2873                 : 
    2874                 : int32_t NaClCommonSysClockGetCommon(struct NaClAppThread  *natp,
    2875                 :                                     int                   clk_id,
    2876                 :                                     uint32_t              ts_addr,
    2877                 :                                     int                   (*timefunc)(
    2878                 :                                         nacl_clockid_t            clk_id,
    2879               0 :                                         struct nacl_abi_timespec  *tp)) {
    2880               0 :   int                       retval = -NACL_ABI_EINVAL;
    2881                 :   uintptr_t                 sysaddr;
    2882                 :   struct nacl_abi_timespec  out_buf;
    2883                 : 
    2884               0 :   NaClSysCommonThreadSyscallEnter(natp);
    2885               0 :   if (!NaClIsValidClockId(clk_id)) {
    2886               0 :     goto done;
    2887                 :   }
    2888               0 :   sysaddr = NaClUserToSysAddrRange(natp->nap,
    2889                 :                                    (uintptr_t) ts_addr, sizeof(out_buf));
    2890               0 :   if (kNaClBadAddress == sysaddr) {
    2891               0 :     NaClLog(1,
    2892                 :             ("NaClSysCommonSysClockGetCommon: bad timespec address "
    2893                 :              " (0x%08"NACL_PRIx32")\n"),
    2894                 :             ts_addr);
    2895               0 :     retval = -NACL_ABI_EFAULT;
    2896               0 :     goto done;
    2897                 :   }
    2898               0 :   retval = (*timefunc)((nacl_clockid_t) clk_id, &out_buf);
    2899               0 :   if (0 == retval) {
    2900               0 :     *(struct nacl_abi_timespec volatile *) sysaddr = out_buf;
    2901                 :   }
    2902               0 :  done:
    2903               0 :   return retval;
    2904                 : }
    2905                 : 
    2906                 : int32_t NaClCommonSysClockGetRes(struct NaClAppThread *natp,
    2907                 :                                  int                  clk_id,
    2908               0 :                                  uint32_t             tsp) {
    2909               0 :   return NaClCommonSysClockGetCommon(natp, clk_id, (uintptr_t) tsp,
    2910                 :                                      NaClClockGetRes);
    2911                 : }
    2912                 : 
    2913                 : int32_t NaClCommonSysClockGetTime(struct NaClAppThread  *natp,
    2914                 :                                   int                   clk_id,
    2915               0 :                                   uint32_t              tsp) {
    2916               0 :   return NaClCommonSysClockGetCommon(natp, clk_id, (uintptr_t) tsp,
    2917                 :                                      NaClClockGetTime);
    2918                 : }

Generated by: LCOV version 1.7