LCOV - code coverage report
Current view: directory - src/shared/platform/win - nacl_host_desc.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 539 298 55.3 %
Date: 2014-09-25 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 Runtime.  I/O Descriptor / Handle abstraction.  Memory
       9                 :  * mapping using descriptors.
      10                 :  */
      11                 : #include "native_client/src/include/portability.h"
      12                 : #include "native_client/src/include/portability_io.h"
      13                 : 
      14                 : #include <windows.h>
      15                 : #include <direct.h>
      16                 : #include <io.h>
      17                 : #include <sys/types.h>
      18                 : #include <sys/stat.h>
      19                 : #include <share.h>
      20                 : 
      21                 : #include "native_client/src/include/nacl_macros.h"
      22                 : #include "native_client/src/include/nacl_platform.h"
      23                 : #include "native_client/src/shared/platform/nacl_check.h"
      24                 : #include "native_client/src/shared/platform/nacl_find_addrsp.h"
      25                 : #include "native_client/src/shared/platform/nacl_host_desc.h"
      26                 : #include "native_client/src/shared/platform/nacl_log.h"
      27                 : #include "native_client/src/shared/platform/nacl_sync.h"
      28                 : #include "native_client/src/shared/platform/nacl_sync_checked.h"
      29                 : #include "native_client/src/shared/platform/win/xlate_system_error.h"
      30                 : #include "native_client/src/trusted/desc/nacl_desc_effector.h"
      31                 : #include "native_client/src/trusted/desc/nacl_desc_effector_trusted_mem.h"
      32                 : 
      33                 : #include "native_client/src/trusted/service_runtime/nacl_config.h"
      34                 : #include "native_client/src/trusted/service_runtime/internal_errno.h"
      35                 : #include "native_client/src/trusted/service_runtime/sel_util-inl.h"
      36                 : 
      37                 : #include "native_client/src/trusted/service_runtime/include/bits/mman.h"
      38                 : #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
      39                 : #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
      40                 : #include "native_client/src/trusted/service_runtime/include/sys/stat.h"
      41                 : #include "native_client/src/trusted/service_runtime/include/sys/unistd.h"
      42                 : 
      43                 : #define OFFSET_FOR_FILEPOS_LOCK (GG_LONGLONG(0x7000000000000000))
      44                 : 
      45                 : /*
      46                 :  * By convention, we use locking the byte at OFFSET_FOR_FILEPOS_LOCK
      47                 :  * as locking for the implicit file position associated with a file
      48                 :  * handle.  According to MSDN, LockFileEx of a byte range that does
      49                 :  * not (yet) exist in a file is not an error, which makes sense in
      50                 :  * that one might want to have exclusive access to a file region that
      51                 :  * is beyond the end of the file before populating it.  We assume that
      52                 :  * OFFSET_FOR_FILEPOS_LOCK is large enough that no real file will
      53                 :  * actually be that big (even if sparse) and cause problems.
      54                 :  *
      55                 :  * One drawback of this is that two independent file handles on the
      56                 :  * same file will share the same lock.  If this leads to actual
      57                 :  * contention issues, we can use the following randomized approach,
      58                 :  * ASSUMING that each file handle / posix-level host descriptor is
      59                 :  * introduced to NaCl at most once (e.g., no dup'ing and invoking
      60                 :  * NaClHostDescPosixTake multiple times): we pick a random offset from
      61                 :  * OFFSET_FOR_FILEPOS_LOCK, and make sure we transfer that with the
      62                 :  * file handle in the nrd_xfer protocol.  This way, we use a range of
      63                 :  * byte offsets for locking files and avoid false contention.  We
      64                 :  * would be subject to the birthday paradox, of course, so if we
      65                 :  * picked a 16-bit random offset to use, then if a file is opened ~256
      66                 :  * times we would start seeing performance issues caused by
      67                 :  * contention, which is probably acceptable; a 32-bit nonce would be
      68                 :  * plenty.
      69                 :  *
      70                 :  * On Windows, fcntl is not available.  A very similar function to
      71                 :  * lockf, _locking, exists in the Windows CRT.  It does not permit
      72                 :  * specification of the start of a region, only size (just like lockf)
      73                 :  * -- implicitly from the current position -- which is less than
      74                 :  * useful for our purposes.
      75                 :  */
      76               4 : static void NaClTakeFilePosLock(HANDLE hFile) {
      77                 :   OVERLAPPED overlap;
      78                 :   DWORD err;
      79                 : 
      80               4 :   memset(&overlap, 0, sizeof overlap);
      81               4 :   overlap.Offset = (DWORD) OFFSET_FOR_FILEPOS_LOCK;
      82               4 :   overlap.OffsetHigh = (DWORD) (OFFSET_FOR_FILEPOS_LOCK >> 32);
      83                 :   /*
      84                 :    * LockFileEx should never fail -- untrusted code cannot cause hFile
      85                 :    * to become invalid, since all NaClHostDesc objects are wrapped in
      86                 :    * NaClDesc objects and all uses of NaClDesc objects take a
      87                 :    * reference before use, so a threading race that closes a
      88                 :    * descriptor at the untrusted code level will only dereference the
      89                 :    * NaClDesc (and make it unavailable to the untrusted code), but the
      90                 :    * object will not be destroyed until after the NaClDesc-level
      91                 :    * operation (which in turn invokes the NaClHostDesc level
      92                 :    * operation) completes.  Only after the operation completes will
      93                 :    * the reference to the NaClDesc be drop by the syscall handler.
      94                 :    */
      95                 :   if (!LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK,
      96                 :                   /* dwReserved= */ 0,
      97                 :                   /* nNumberOfBytesToLockLow= */ 1,
      98                 :                   /* nNumberOfBytesToLockHigh= */ 0,
      99               4 :                   &overlap)) {
     100               0 :     err = GetLastError();
     101                 :     NaClLog(LOG_FATAL, "NaClTakeFilePosLock: LockFileEx failed, error %u\n",
     102               0 :             err);
     103                 :   }
     104               4 : }
     105                 : 
     106                 : /*
     107                 :  * Map our ABI to the host OS's ABI.
     108                 :  * Note: there is no X bit equivalent on windows so NACL_ABI_S_IXUSR
     109                 :  * is ignored.
     110                 :  */
     111               0 : static INLINE mode_t NaClMapMode(nacl_abi_mode_t abi_mode) {
     112               0 :   mode_t m = 0;
     113               0 :   if (0 != (abi_mode & NACL_ABI_S_IRUSR))
     114               0 :     m |= _S_IREAD;
     115               0 :   if (0 != (abi_mode & NACL_ABI_S_IWUSR))
     116               0 :     m |= _S_IWRITE;
     117               0 :   return m;
     118               0 : }
     119                 : 
     120                 : /* Windows doesn't define R_OK or W_OK macros but expects these constants */
     121                 : #define WIN_F_OK 0
     122                 : #define WIN_R_OK 4
     123                 : #define WIN_W_OK 2
     124                 : 
     125                 : /*
     126                 :  * Map our ABI to the host OS's ABI.
     127                 :  * There is no X_OK (0x1) on win32 so we ignore
     128                 :  * NACL_ABI_X_OK and report everything that exists
     129                 :  * as being executable.
     130                 :  */
     131               0 : static INLINE int NaClMapAccessMode(int nacl_mode) {
     132               0 :   int mode = 0;
     133               0 :   if (nacl_mode == NACL_ABI_F_OK) {
     134               0 :     mode = WIN_F_OK;
     135               0 :   } else {
     136               0 :     if (nacl_mode & NACL_ABI_R_OK)
     137               0 :       mode |= WIN_R_OK;
     138               0 :     if (nacl_mode & NACL_ABI_W_OK)
     139               0 :       mode |= WIN_W_OK;
     140                 :   }
     141               0 :   return mode;
     142               0 : }
     143                 : 
     144               4 : static void NaClDropFilePosLock(HANDLE hFile) {
     145                 :   OVERLAPPED overlap;
     146                 :   DWORD err;
     147                 : 
     148               4 :   memset(&overlap, 0, sizeof overlap);
     149               4 :   overlap.Offset = (DWORD) OFFSET_FOR_FILEPOS_LOCK;
     150               4 :   overlap.OffsetHigh = (DWORD) (OFFSET_FOR_FILEPOS_LOCK >> 32);
     151                 :   if (!UnlockFileEx(hFile,
     152                 :                     /* dwReserved= */ 0,
     153                 :                     /* nNumberOfBytesToLockLow= */ 1,
     154                 :                     /* nNumberOfBytesToLockHigh= */ 0,
     155               4 :                     &overlap)) {
     156               0 :     err = GetLastError();
     157                 :     NaClLog(LOG_FATAL, "NaClDropFilePosLock: UnlockFileEx failed, error %u\n",
     158               0 :             err);
     159                 :   }
     160               4 : }
     161                 : 
     162               1 : static nacl_off64_t NaClLockAndGetCurrentFilePos(HANDLE hFile) {
     163                 :   LARGE_INTEGER to_move;
     164                 :   LARGE_INTEGER cur_pos;
     165                 :   DWORD err;
     166                 : 
     167               1 :   NaClTakeFilePosLock(hFile);
     168               1 :   to_move.QuadPart = 0;
     169               1 :   if (!SetFilePointerEx(hFile, to_move, &cur_pos, FILE_CURRENT)) {
     170               0 :     err = GetLastError();
     171                 :     NaClLog(LOG_FATAL,
     172                 :             "NaClLockAndGetCurrentFilePos: SetFilePointerEx failed, error %u\n",
     173               0 :             err);
     174                 :   }
     175               1 :   return cur_pos.QuadPart;
     176               1 : }
     177                 : 
     178                 : static void NaClSetCurrentFilePosAndUnlock(HANDLE hFile,
     179               1 :                                            nacl_off64_t pos) {
     180                 :   LARGE_INTEGER to_move;
     181                 :   DWORD err;
     182                 : 
     183               1 :   to_move.QuadPart = pos;
     184               1 :   if (!SetFilePointerEx(hFile, to_move, (LARGE_INTEGER *) NULL, FILE_BEGIN)) {
     185               0 :     err = GetLastError();
     186                 :     NaClLog(LOG_FATAL,
     187                 :             "NaClSetCurrentFilePosAndUnlock: SetFilePointerEx failed:"
     188                 :             " error %d\n",
     189               0 :             err);
     190                 :   }
     191               1 :   NaClDropFilePosLock(hFile);
     192               1 : }
     193                 : 
     194                 : /*
     195                 :  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
     196                 :  *
     197                 :  * The implementation of the host descriptor abstractions will
     198                 :  * probably change.  In particularly, blocking I/O calls must be
     199                 :  * interruptible in order to implement the address-space move
     200                 :  * mechanism for mmap error recovery, and the it seems that the only
     201                 :  * way that this would be feasible is to do the following: instead of
     202                 :  * using the POSIX abstraction layer, do the I/O using Windows file
     203                 :  * handles opened for asynchronous operations.  When a potentially
     204                 :  * blocking system call (e.g., read or write) is performed, use
     205                 :  * overlapped I/O via ReadFile/WriteFile to initiate the I/O operation
     206                 :  * in a non-blocking manner, and use a separate event object, so that
     207                 :  * the thread can, after initiating the I/O, perform
     208                 :  * WaitForMultipleObjects on both I/O completion (event in the
     209                 :  * OVERLAPPED structure) and on mmap-generated interrupts.  The event
     210                 :  * can be signalled via SetEvent by any other thread that wish to
     211                 :  * perform a safe mmap operation.
     212                 :  *
     213                 :  * When the safe mmap is to occur, all other application threads are
     214                 :  * stopped (beware, of course, of the race condition where two threads
     215                 :  * try to do mmap), and the remaining running thread performs
     216                 :  * VirtualFree and MapViewOfFileEx.  If a thread (from some injected
     217                 :  * DLL) puts some memory in the hole created by VirtualFree before the
     218                 :  * MapViewOfFileEx runs, then we have to move the entire address space
     219                 :  * to avoid allowing the untrusted NaCl app from touching this
     220                 :  * innocent thread's memory.
     221                 :  *
     222                 :  * What this implies is that a mechanism must exist in order for the
     223                 :  * mmapping thread to stop all other application threads, and this is
     224                 :  * why the blocking syscalls must be interruptible.  When interrupted,
     225                 :  * the thread that initiated the I/O must perform CancelIo and check,
     226                 :  * via GetOverlappedResult, to see how much have completed, etc, then
     227                 :  * put itself into a restartable state -- we might simply return EINTR
     228                 :  * if no work has been dnoe and require libc to restart the syscall in
     229                 :  * the SysV style, though it should be possible to just restart the
     230                 :  * syscall in the BSD style -- and to signal the mmapping thread that
     231                 :  * it is ready.
     232                 :  *
     233                 :  * Alternatively, these interrupted operations can return a private
     234                 :  * version of EAGAIN, so that the code calling the host descriptor
     235                 :  * (syscall handler) can quiesce the thread and restart the I/O
     236                 :  * operation once the address space move is complete.
     237                 :  *
     238                 :  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
     239                 :  */
     240                 : 
     241                 : /*
     242                 :  * TODO(bsy, gregoryd): check that _get_errno is indeed a thread-safe way
     243                 :  * to get the error from the last 'syscall' into the posix layer.
     244                 :  */
     245               0 : int GetErrno(void) {
     246                 :   int thread_errno;
     247                 : 
     248               0 :   (void) _get_errno(&thread_errno);
     249               0 :   return NaClXlateErrno(thread_errno);
     250               0 : }
     251                 : 
     252               3 : static INLINE size_t size_min(size_t a, size_t b) {
     253               3 :   return (a < b) ? a : b;
     254               3 : }
     255                 : 
     256                 : /*
     257                 :  * The mapping and unmapping code work in 64K chunks rather than a
     258                 :  * single large allocation because all of our uses will use 64K
     259                 :  * chunks.  Higher level code keeps track of whether memory came from
     260                 :  * VirtualAlloc or NaClHostDescMap, and will call the appropriate
     261                 :  * deallocation functions.
     262                 :  *
     263                 :  * NB: if prot is NACL_ABI_PROT_NONE, then the memory should be
     264                 :  * deallocated via VirtualFree as if it came from paging file rather
     265                 :  * than via a file mapping object representing the paging file (and
     266                 :  * thus UnmapViewOfFile).
     267                 :  */
     268                 : 
     269                 : /*
     270                 :  * out_flProtect == 0 means error, and the error string can be used
     271                 :  * for a logging message (except for the cases that the caller should
     272                 :  * be checking for).
     273                 :  *
     274                 :  * in parameters are all NACL_ABI_ values or bool (0/1).
     275                 :  *
     276                 :  * accmode may be NACL_ABI_O_RDONLY or NACL_ABI_O_RDWR, but not
     277                 :  * NACL_ABI_O_WRONLY (see below).
     278                 :  *
     279                 :  * Caller should check for:
     280                 :  *
     281                 :  * - PROT_NONE -> special case handling,
     282                 :  * - NACL_ABI_O_APPEND and PROT_WRITE -> EACCES,
     283                 :  * - accmode is O_WRONLY -> EACCES,
     284                 :  *
     285                 :  * The interpretation here is that PROT_EXEC or PROT_WRITE implies
     286                 :  * asking for PROT_READ, since most hardware behaves this way.  So if
     287                 :  * the descriptor is O_WRONLY, we generally refuse.
     288                 :  *
     289                 :  * The file mapping object created by CreateFileMapping's flProtect
     290                 :  * argument specifies the MAXIMUM protection, and MapViewOfFileEx will
     291                 :  * request a lesser level of access.  We should always
     292                 :  * CreateFileMapping with a high level of access so that
     293                 :  * VirtualProtect (used by mprotect) can be used to turn on write when
     294                 :  * the initial mmap had read-only mappings.
     295                 :  *
     296                 :  * BUG(phosek): Due to Windows XP limitation, in particular the missing
     297                 :  * PAGE_EXECUTE_WRITECOPY protection support for file mapping objects,
     298                 :  * we cannot mmap r/o file as private, read/write and later make it
     299                 :  * executable or vice versa mmap r/o file as private, read/execute and
     300                 :  * later make it writable. This is a platform difference, but since
     301                 :  * untrusted code is not allowed to mmap files as write/execute, this
     302                 :  * difference is invisible to application developers and will therefore
     303                 :  * likely remain unresolved as the solution would likely be very
     304                 :  * expensive. Furthemore, after dropping the support for Windows XP, this
     305                 :  * difference can be easily resolved by updating the flag mapping.
     306                 :  */
     307                 : void NaClflProtectAndDesiredAccessMap(int prot,
     308                 :                                       int is_private,
     309                 :                                       int accmode,
     310                 :                                       DWORD *out_flMappingProtect,
     311                 :                                       DWORD *out_flProtect,
     312                 :                                       DWORD *out_dwDesiredAccess,
     313               3 :                                       char const **out_msg) {
     314                 : #define M(mp,p,da,err) { mp, p, da, err, #mp, #p, #da }
     315                 :   static struct {
     316                 :     DWORD flMappingProtect;
     317                 :     DWORD flProtect;
     318                 :     DWORD dwDesiredAccess;
     319                 :     char const *err;
     320                 :     char const *flMappingProtect_str;
     321                 :     char const *flProtect_str;
     322                 :     char const *dwDesiredAccess_str;
     323                 :   } table[] = {
     324                 :     /* RDONLY */
     325                 :     /* shared */
     326                 :     /* PROT_NONE */
     327                 :     M(PAGE_EXECUTE_READ, PAGE_NOACCESS, FILE_MAP_READ, NULL),
     328                 :     /* PROT_READ */
     329                 :     M(PAGE_EXECUTE_READ, PAGE_READONLY, FILE_MAP_READ, NULL),
     330                 :     /* PROT_WRITE */
     331                 :     M(0, 0, 0, "file open for read only; no shared write allowed"),
     332                 :     /* PROT_READ | PROT_WRITE */
     333                 :     M(0, 0, 0, "file open for read only; no shared read/write allowed"),
     334                 :     /* PROT_EXEC */
     335                 :     M(PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE,
     336                 :       FILE_MAP_READ | FILE_MAP_EXECUTE, NULL),
     337                 :     /* PROT_READ | PROT_EXEC */
     338                 :     M(PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READ,
     339                 :       FILE_MAP_READ | FILE_MAP_EXECUTE, NULL),
     340                 :     /* PROT_WRITE | PROT_EXEC */
     341                 :     M(0, 0, 0, "file open for read only; no shared write/exec allowed"),
     342                 :     /* PROT_READ | PROT_WRITE | PROT_EXEC */
     343                 :     M(0, 0, 0, "file open for read only; no shared read/write/exec allowed"),
     344                 : 
     345                 :     /* is_private */
     346                 :     /* PROT_NONE */
     347                 :     M(PAGE_EXECUTE_READ, PAGE_NOACCESS, FILE_MAP_READ, NULL),
     348                 :     /* PROT_READ */
     349                 :     M(PAGE_EXECUTE_READ, PAGE_READONLY, FILE_MAP_READ, NULL),
     350                 :     /* PROT_WRITE */
     351                 :     M(PAGE_EXECUTE_READ, PAGE_WRITECOPY, FILE_MAP_COPY, NULL),
     352                 :     /* PROT_READ | PROT_WRITE */
     353                 :     M(PAGE_EXECUTE_READ, PAGE_WRITECOPY, FILE_MAP_COPY, NULL),
     354                 : 
     355                 :     /*
     356                 :      * NB: PAGE_EXECUTE_WRITECOPY is not supported on Server 2003 or
     357                 :      * XP, which means that the mmap will fail.  In this case we fallback
     358                 :      * to PAGE_EXECUTE_READ.
     359                 :      *
     360                 :      * Even with PAGE_EXECUTE_WRITECOPY, the PROT_WRITE | PROT_EXEC
     361                 :      * case where we are asking for FILE_MAP_COPY | FILE_MAP_EXECUTE
     362                 :      * seems to always fail, with GetLastError() yielding 87
     363                 :      * (ERROR_INVALID_PARAMETER).  This may be due to antivirus.
     364                 :      */
     365                 : 
     366                 :     /* PROT_EXEC */
     367                 :     M(PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE,
     368                 :       FILE_MAP_READ | FILE_MAP_EXECUTE, NULL),
     369                 :     /* PROT_READ | PROT_EXEC */
     370                 :     M(PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_READ,
     371                 :       FILE_MAP_READ | FILE_MAP_EXECUTE, NULL),
     372                 :     /* PROT_WRITE | PROT_EXEC */
     373                 :     M(PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_WRITECOPY,
     374                 :       FILE_MAP_COPY | FILE_MAP_EXECUTE, NULL),
     375                 :     /* PROT_READ | PROT_WRITE | PROT_EXEC */
     376                 :     M(PAGE_EXECUTE_WRITECOPY, PAGE_EXECUTE_WRITECOPY,
     377                 :       FILE_MAP_COPY | FILE_MAP_EXECUTE, NULL),
     378                 : 
     379                 :     /* RDWR */
     380                 :     /* shared */
     381                 :     /* PROT_NONE */
     382                 :     M(PAGE_EXECUTE_READWRITE, PAGE_NOACCESS, FILE_MAP_READ, NULL),
     383                 :     /* PROT_READ */
     384                 :     M(PAGE_EXECUTE_READWRITE, PAGE_READONLY, FILE_MAP_READ, NULL),
     385                 :     /* PROT_WRITE */
     386                 :     M(PAGE_EXECUTE_READWRITE, PAGE_READWRITE, FILE_MAP_WRITE, NULL),
     387                 :     /* PROT_READ | PROT_WRITE */
     388                 :     M(PAGE_EXECUTE_READWRITE, PAGE_READWRITE, FILE_MAP_WRITE, NULL),
     389                 : 
     390                 :     /* PROT_EXEC */
     391                 :     M(PAGE_EXECUTE_READWRITE, PAGE_EXECUTE,
     392                 :       FILE_MAP_READ | FILE_MAP_EXECUTE, NULL),
     393                 :     /* PROT_READ | PROT_EXEC */
     394                 :     M(PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_READ,
     395                 :       FILE_MAP_READ | FILE_MAP_EXECUTE, NULL),
     396                 :     /* PROT_WRITE | PROT_EXEC */
     397                 :     M(PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_READWRITE,
     398                 :       FILE_MAP_WRITE | FILE_MAP_EXECUTE, NULL),
     399                 :     /* PROT_READ | PROT_WRITE | PROT_EXEC */
     400                 :     M(PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_READWRITE,
     401                 :       FILE_MAP_WRITE | FILE_MAP_EXECUTE, NULL),
     402                 : 
     403                 :     /* is_private */
     404                 :     /* PROT_NONE */
     405                 :     M(PAGE_EXECUTE_READWRITE, PAGE_NOACCESS, FILE_MAP_READ, NULL),
     406                 :     /* PROT_READ */
     407                 :     M(PAGE_EXECUTE_READWRITE, PAGE_READONLY, FILE_MAP_READ, NULL),
     408                 :     /* PROT_WRITE */
     409                 :     M(PAGE_EXECUTE_READWRITE, PAGE_WRITECOPY, FILE_MAP_COPY, NULL),
     410                 :     /* PROT_READ | PROT_WRITE */
     411                 :     M(PAGE_EXECUTE_READWRITE, PAGE_WRITECOPY, FILE_MAP_COPY, NULL),
     412                 : 
     413                 :     /* PROT_EXEC */
     414                 :     M(PAGE_EXECUTE_READWRITE, PAGE_EXECUTE,
     415                 :       FILE_MAP_WRITE | FILE_MAP_EXECUTE, NULL),
     416                 :     /* PROT_READ | PROT_EXEC */
     417                 :     M(PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_READ,
     418                 :       FILE_MAP_WRITE | FILE_MAP_EXECUTE, NULL),
     419                 :     /* PROT_WRITE | PROT_EXEC */
     420                 :     M(PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_WRITECOPY,
     421                 :       FILE_MAP_WRITE | FILE_MAP_EXECUTE, NULL),
     422                 :     /* PROT_READ | PROT_WRITE | PROT_EXEC */
     423                 :     M(PAGE_EXECUTE_READWRITE, PAGE_EXECUTE_WRITECOPY,
     424                 :       FILE_MAP_WRITE | FILE_MAP_EXECUTE, NULL),
     425                 :   };
     426                 : #undef M
     427                 : 
     428                 :   size_t ix;
     429                 : 
     430                 :   NaClLog(3,
     431                 :           "NaClflProtectAndDesiredAccessMap(prot 0x%x,"
     432                 :           " priv 0x%x, accmode 0x%x, ...)\n",
     433               3 :           prot, is_private, accmode);
     434                 : 
     435               3 :   NACL_COMPILE_TIME_ASSERT(NACL_ABI_O_RDONLY == 0);
     436               3 :   NACL_COMPILE_TIME_ASSERT(NACL_ABI_O_RDWR == 2);
     437               3 :   NACL_COMPILE_TIME_ASSERT(NACL_ABI_PROT_NONE == 0);
     438               3 :   NACL_COMPILE_TIME_ASSERT(NACL_ABI_PROT_READ == 1);
     439               3 :   NACL_COMPILE_TIME_ASSERT(NACL_ABI_PROT_WRITE == 2);
     440               3 :   NACL_COMPILE_TIME_ASSERT(NACL_ABI_PROT_EXEC == 4);
     441                 : 
     442               3 :   CHECK(accmode != NACL_ABI_O_WRONLY);
     443                 : 
     444                 :   /*
     445                 :    * NACL_ABI_O_RDONLY == 0, NACL_ABI_O_RDWR == 2, so multiplying by 8
     446                 :    * yields a base separation of 8 for the 16 element subtable indexed
     447                 :    * by the NACL_ABI_PROT_{READ|WRITE|EXEC} and is_private values.
     448                 :    */
     449                 :   ix = ((prot & NACL_ABI_PROT_MASK) +
     450                 :         (is_private << 3) +
     451               3 :         ((accmode & NACL_ABI_O_ACCMODE) << 3));
     452                 : 
     453               3 :   CHECK(ix < NACL_ARRAY_SIZE(table));  /* compiler should elide this */
     454                 : 
     455               3 :   if (NULL != out_flMappingProtect) {
     456               3 :     *out_flMappingProtect = table[ix].flMappingProtect;
     457                 :   }
     458               3 :   if (NULL != out_flProtect) {
     459               3 :     *out_flProtect = table[ix].flProtect;
     460                 :   }
     461               3 :   if (NULL != out_dwDesiredAccess) {
     462               3 :     *out_dwDesiredAccess = table[ix].dwDesiredAccess;
     463                 :   }
     464               3 :   if (NULL != out_msg) {
     465               3 :     *out_msg = table[ix].err;
     466                 :   }
     467                 : 
     468                 :   NaClLog(3, "NaClflProtectAndDesiredAccessMap: %s %s %s\n",
     469                 :           table[ix].flMappingProtect_str,
     470                 :           table[ix].flProtect_str,
     471               3 :           table[ix].dwDesiredAccess_str);
     472               3 : }
     473                 : 
     474                 : /*
     475                 :  * Returns flProtect flags for VirtualAlloc'd memory, file based
     476                 :  * mappings should always use NaClflProtectAndDesiredAccessMap.
     477                 :  */
     478               0 : DWORD NaClflProtectMap(int prot) {
     479                 : #define M(p) { p, #p }
     480                 :   static struct {
     481                 :     DWORD flProtect;
     482                 :     char const *flProtect_str;
     483                 :   } table[] = {
     484                 :     /* PROT_NONE */
     485                 :     M(PAGE_NOACCESS),
     486                 :     /* PROT_READ */
     487                 :     M(PAGE_READONLY),
     488                 :     /* PROT_WRITE */
     489                 :     M(PAGE_READWRITE),
     490                 :     /* PROT_READ | PROT_WRITE */
     491                 :     M(PAGE_READWRITE),
     492                 : 
     493                 :     /* PROT_EXEC */
     494                 :     M(PAGE_EXECUTE),
     495                 :     /* PROT_READ | PROT_EXEC */
     496                 :     M(PAGE_EXECUTE_READ),
     497                 :     /* PROT_WRITE | PROT_EXEC */
     498                 :     M(PAGE_EXECUTE_READWRITE),
     499                 :     /* PROT_READ | PROT_WRITE | PROT_EXEC */
     500                 :     M(PAGE_EXECUTE_READWRITE),
     501                 :   };
     502                 : #undef M
     503                 : 
     504                 :   size_t ix;
     505                 : 
     506               0 :   NaClLog(3, "NaClflProtectMap(prot 0x%x)\n", prot);
     507                 : 
     508               0 :   NACL_COMPILE_TIME_ASSERT(NACL_ABI_PROT_NONE == 0);
     509               0 :   NACL_COMPILE_TIME_ASSERT(NACL_ABI_PROT_READ == 1);
     510               0 :   NACL_COMPILE_TIME_ASSERT(NACL_ABI_PROT_WRITE == 2);
     511               0 :   NACL_COMPILE_TIME_ASSERT(NACL_ABI_PROT_EXEC == 4);
     512                 : 
     513               0 :   ix = (prot & NACL_ABI_PROT_MASK);
     514               0 :   CHECK(ix < NACL_ARRAY_SIZE(table));  /* compiler should elide this */
     515                 : 
     516               0 :   NaClLog(3, "NaClflProtectMap: %s\n", table[ix].flProtect_str);
     517                 : 
     518               0 :   return table[ix].flProtect;
     519               0 : }
     520                 : 
     521                 : /*
     522                 :  * Unfortunately, when the descriptor is imported via
     523                 :  * NaClHostDescPosixTake or NaClHostDescPosixDup, the underlying file
     524                 :  * handle may not have GENERIC_EXECUTE permission associated with it,
     525                 :  * unlike the files open using NaClHostDescOpen.  This means that the
     526                 :  * CreateFileMapping with flMappingProtect that specifies PAGE_EXECUTE_*
     527                 :  * will fail. Since we don't know whether GENERIC_EXECUTE without doing
     528                 :  * a query, we instead lazily determine the need by detecting the
     529                 :  * CreateFileMapping error and retrying using a fallback
     530                 :  * flMappingProtect that does not have EXECUTE rights.  We record this
     531                 :  * in the descriptor so that the next time we do not have to try with
     532                 :  * the PAGE_EXECUTE_* and have it deterministically fail.
     533                 :  *
     534                 :  * This function is also used when mapping in anonymous memory.  We
     535                 :  * assume that we never map anonymous executable memory -- mmap of
     536                 :  * executable data is always from a file, and the page will be
     537                 :  * non-writable -- and we ensure that anonymous memory is never
     538                 :  * executable.
     539                 :  */
     540               2 : static DWORD NaClflProtectRemoveExecute(DWORD flProtect) {
     541               2 :   switch (flProtect) {
     542                 :     case PAGE_EXECUTE:
     543               0 :       return PAGE_NOACCESS;
     544                 :     case PAGE_EXECUTE_READ:
     545               2 :       return PAGE_READONLY;
     546                 :     case PAGE_EXECUTE_READWRITE:
     547               2 :       return PAGE_READWRITE;
     548                 :     case PAGE_EXECUTE_WRITECOPY:
     549               0 :       return PAGE_WRITECOPY;
     550                 :   }
     551               0 :   return flProtect;
     552               2 : }
     553                 : 
     554                 : /* Check if flProtect has executable permission. */
     555               2 : static int NaClflProtectHasExecute(DWORD flProtect) {
     556                 :   return flProtect == PAGE_EXECUTE ||
     557                 :          flProtect == PAGE_EXECUTE_READ ||
     558                 :          flProtect == PAGE_EXECUTE_READWRITE ||
     559               2 :          flProtect == PAGE_EXECUTE_WRITECOPY;
     560               2 : }
     561                 : 
     562                 : /*
     563                 :  * TODO(mseaborn): Reduce duplication between this function and
     564                 :  * nacl::Map()/NaClMap().
     565                 :  */
     566                 : uintptr_t NaClHostDescMap(struct NaClHostDesc *d,
     567                 :                           struct NaClDescEffector *effp,
     568                 :                           void                *start_addr,
     569                 :                           size_t              len,
     570                 :                           int                 prot,
     571                 :                           int                 flags,
     572               3 :                           nacl_off64_t        offset) {
     573                 :   uintptr_t retval;
     574                 :   uintptr_t addr;
     575                 :   int       desc_flags;
     576                 :   HANDLE    hFile;
     577                 :   HANDLE    hMap;
     578                 :   int       retry_fallback;
     579                 :   DWORD     flMappingProtect;
     580                 :   DWORD     dwDesiredAccess;
     581                 :   DWORD     flProtect;
     582                 :   DWORD     flOldProtect;
     583                 :   char const *err_msg;
     584                 :   DWORD     dwMaximumSizeHigh;
     585                 :   DWORD     dwMaximumSizeLow;
     586                 :   uintptr_t map_result;
     587                 :   size_t    chunk_offset;
     588                 :   size_t    chunk_size;
     589                 : 
     590               3 :   if (NULL == d && 0 == (flags & NACL_ABI_MAP_ANONYMOUS)) {
     591               0 :     NaClLog(LOG_FATAL, "NaClHostDescMap: 'this' is NULL and not anon map\n");
     592                 :   }
     593               3 :   if (NULL != d && -1 == d->d) {
     594               0 :     NaClLog(LOG_FATAL, "NaClHostDescMap: already closed\n");
     595                 :   }
     596                 :   if ((0 == (flags & NACL_ABI_MAP_SHARED)) ==
     597               3 :       (0 == (flags & NACL_ABI_MAP_PRIVATE))) {
     598                 :     NaClLog(LOG_FATAL,
     599                 :             "NaClHostDescMap: exactly one of NACL_ABI_MAP_SHARED"
     600               0 :             " and NACL_ABI_MAP_PRIVATE must be set.\n");
     601                 :   }
     602               3 :   addr = (uintptr_t) start_addr;
     603               3 :   prot &= NACL_ABI_PROT_MASK;
     604                 : 
     605                 :   /*
     606                 :    * Check that if FIXED, start_addr is not NULL.
     607                 :    * Use platform free address space locator to set start_addr if NULL and
     608                 :    * not FIXED.
     609                 :    */
     610               3 :   if (0 == (flags & NACL_ABI_MAP_FIXED)) {
     611                 :     /*
     612                 :      * Not fixed, addr is a hint... which we ignore.  We cannot just
     613                 :      * let windows pick, since we are mapping memory in chunks of
     614                 :      * 64-kB to permit piecewise unmapping.
     615                 :      */
     616               2 :     if (!NaClFindAddressSpace(&addr, len)) {
     617                 :       NaClLog(LOG_ERROR,
     618               0 :               "NaClHostDescMap: not fixed, and could not find space\n");
     619               0 :       return (uintptr_t) -NACL_ABI_ENOMEM;
     620                 :     }
     621                 : 
     622                 :     NaClLog(4,
     623                 :             "NaClHostDescMap: NOT FIXED, found space at %"NACL_PRIxPTR"\n",
     624               2 :             addr);
     625                 : 
     626               2 :     start_addr = (void *) addr;
     627                 :   }
     628                 : 
     629               3 :   flProtect = 0;
     630               3 :   dwDesiredAccess = 0;
     631                 : 
     632               3 :   if (0 != (flags & NACL_ABI_MAP_ANONYMOUS)) {
     633                 :     /*
     634                 :      * anonymous memory must be free'able later via VirtualFree
     635                 :      */
     636               0 :     NaClLog(3, "NaClHostDescMap: anonymous mapping\n");
     637                 : 
     638               0 :     flProtect = NaClflProtectMap(prot & (~PROT_EXEC));
     639               0 :     NaClLog(3, "NaClHostDescMap: flProtect 0x%x\n", flProtect);
     640                 : 
     641                 :     for (chunk_offset = 0;
     642                 :          chunk_offset < len;
     643               0 :          chunk_offset += NACL_MAP_PAGESIZE) {
     644               0 :       uintptr_t chunk_addr = addr + chunk_offset;
     645                 : 
     646               0 :       (*effp->vtbl->UnmapMemory)(effp, chunk_addr, NACL_MAP_PAGESIZE);
     647                 : 
     648                 :       NaClLog(3,
     649                 :               "NaClHostDescMap: VirtualAlloc(0x%08x,,%x,%x)\n",
     650                 :               (void *) (addr + chunk_offset),
     651                 :               MEM_COMMIT | MEM_RESERVE,
     652               0 :               flProtect);
     653                 :       map_result = (uintptr_t) VirtualAlloc((void *) chunk_addr,
     654                 :                                             NACL_MAP_PAGESIZE,
     655                 :                                             MEM_COMMIT | MEM_RESERVE,
     656               0 :                                             flProtect);
     657               0 :       if (map_result != addr + chunk_offset) {
     658                 :         NaClLog(LOG_FATAL,
     659                 :                 ("Could not VirtualAlloc anonymous memory at"
     660                 :                  " addr 0x%08x with prot %x\n"),
     661               0 :                 addr + chunk_offset, flProtect);
     662                 :       }
     663               0 :     }
     664                 :     NaClLog(3, "NaClHostDescMap: (anon) returning 0x%08"NACL_PRIxPTR"\n",
     665               0 :             start_addr);
     666               0 :     return (uintptr_t) start_addr;
     667                 :   }
     668                 : 
     669               3 :   if (NULL == d) {
     670               0 :     desc_flags = NACL_ABI_O_RDWR;
     671               0 :   } else {
     672               3 :     desc_flags = d->flags;
     673                 :   }
     674                 : 
     675                 :   if (0 != (desc_flags & NACL_ABI_O_APPEND) &&
     676               3 :       0 != (prot & NACL_ABI_PROT_WRITE)) {
     677               0 :     return (uintptr_t) -NACL_ABI_EACCES;
     678                 :   }
     679               3 :   if (NACL_ABI_O_WRONLY == (desc_flags & NACL_ABI_O_ACCMODE)) {
     680               1 :     return (uintptr_t) -NACL_ABI_EACCES;
     681                 :   }
     682                 :   NaClflProtectAndDesiredAccessMap(prot,
     683                 :                                    0 != (flags & NACL_ABI_MAP_PRIVATE),
     684                 :                                    (desc_flags & NACL_ABI_O_ACCMODE),
     685                 :                                    &flMappingProtect,
     686                 :                                    &flProtect,
     687                 :                                    &dwDesiredAccess,
     688               3 :                                    &err_msg);
     689               3 :   if (0 == flProtect) {
     690               2 :     NaClLog(3, "NaClHostDescMap: %s\n", err_msg);
     691               2 :     return (uintptr_t) -NACL_ABI_EACCES;
     692                 :   }
     693                 :   NaClLog(3,
     694                 :           "NaClHostDescMap: flMappingProtect 0x%x,"
     695                 :           " dwDesiredAccess 0x%x, flProtect 0x%x\n",
     696               3 :           flMappingProtect, dwDesiredAccess, flProtect);
     697                 : 
     698               3 :   hFile = (HANDLE) _get_osfhandle(d->d);
     699               3 :   dwMaximumSizeLow = 0;
     700               3 :   dwMaximumSizeHigh = 0;
     701                 : 
     702                 :   /*
     703                 :    * Ensure consistency of the d->flMappingProtect access.
     704                 :    */
     705               3 :   NaClFastMutexLock(&d->mu);
     706               3 :   if (0 != d->flMappingProtect) {
     707               1 :     flMappingProtect = d->flMappingProtect;
     708               1 :     retry_fallback = 0;
     709               1 :   } else {
     710               3 :     retry_fallback = 1;
     711                 :   }
     712               3 :   NaClFastMutexUnlock(&d->mu);
     713                 : 
     714                 :   /*
     715                 :    * Finite retry cycle.  We can fallback from PAGE_EXECUTE_WRITECOPY to
     716                 :    * PAGE_EXECUTE_READ and from having executable permissions to not having
     717                 :    * them.
     718                 :    */
     719               3 :   while (1) {
     720                 :     /*
     721                 :      * If hFile is INVALID_HANDLE_VALUE, the memory is backed by the
     722                 :      * system paging file.  Why does it returns NULL instead of
     723                 :      * INVALID_HANDLE_VALUE when there is an error?
     724                 :      */
     725                 :     hMap = CreateFileMapping(hFile,
     726                 :                              NULL,
     727                 :                              flMappingProtect,
     728                 :                              dwMaximumSizeHigh,
     729                 :                              dwMaximumSizeLow,
     730               3 :                              NULL);
     731               3 :     if (NULL == hMap && retry_fallback) {
     732                 :       /*
     733                 :        * PAGE_EXECUTE_WRITECOPY is not supported on Windows XP so we fallback
     734                 :        * to PAGE_EXECUTE_READ.
     735                 :        */
     736               2 :       if (PAGE_EXECUTE_WRITECOPY == flMappingProtect) {
     737                 :         NaClLog(3,
     738                 :                 "NaClHostDescMap: CreateFileMapping failed, retrying with"
     739               0 :                 " PAGE_EXECUTE_READ instead of PAGE_EXECUTE_WRITECOPY\n");
     740               0 :         flMappingProtect = PAGE_EXECUTE_READ;
     741               0 :         continue;
     742                 :       }
     743                 :       if (0 == (prot & NACL_ABI_PROT_EXEC) &&
     744               2 :           NaClflProtectHasExecute(flMappingProtect)) {
     745                 :         NaClLog(3,
     746                 :                 "NaClHostDescMap: CreateFileMapping failed, retrying without"
     747                 :                 " execute permission.  Original flMappingProtect 0x%x\n",
     748               2 :                 flMappingProtect);
     749                 :         NaClflProtectAndDesiredAccessMap(prot & (~PROT_EXEC),
     750                 :                                          0 != (flags & NACL_ABI_MAP_PRIVATE),
     751                 :                                          (desc_flags & NACL_ABI_O_ACCMODE),
     752                 :                                          &flMappingProtect,
     753                 :                                          &flProtect,
     754                 :                                          &dwDesiredAccess,
     755               2 :                                          &err_msg);
     756               2 :         if (0 == flProtect) {
     757               0 :           NaClLog(3, "NaClHostDescMap: %s\n", err_msg);
     758               0 :           return (uintptr_t) -NACL_ABI_EACCES;
     759                 :         }
     760               2 :         flMappingProtect = NaClflProtectRemoveExecute(flMappingProtect);
     761                 :         NaClLog(3,
     762                 :                 "NaClHostDescMap: fallback flMappingProtect 0x%x,"
     763                 :                 " dwDesiredAccess 0x%x, flProtect 0x%x\n",
     764               2 :                 flMappingProtect, dwDesiredAccess, flProtect);
     765               2 :         continue;
     766                 :       }
     767                 :       NaClLog(3,
     768                 :               "NaClHostDescMap: not retrying, since caller explicitly asked"
     769               1 :               " for NACL_ABI_PROT_EXEC\n");
     770               1 :       break;
     771                 :     }
     772                 :     /*
     773                 :      * Remember successful flProtect used.  Note that this just
     774                 :      * ensures reads of d->flMappingProtect gets a consistent value;
     775                 :      * we have a potential race where two threads perform mmap and in
     776                 :      * parallel determine the replacement flProtect value.  This is
     777                 :      * okay, since those two threads should arrive at the same
     778                 :      * replacement value.  This could be replaced with an atomic
     779                 :      * word.
     780                 :      */
     781               3 :     NaClFastMutexLock(&d->mu);
     782               3 :     d->flMappingProtect = flMappingProtect;
     783               3 :     NaClFastMutexUnlock(&d->mu);
     784               3 :     break;
     785                 :   }
     786                 : 
     787               3 :   if (NULL == hMap) {
     788               1 :     DWORD err = GetLastError();
     789                 :     NaClLog(LOG_INFO,
     790                 :             "NaClHostDescMap: CreateFileMapping failed: %d\n",
     791               1 :             err);
     792               1 :     return -NaClXlateSystemError(err);
     793                 :   }
     794               3 :   NaClLog(3, "NaClHostDescMap: CreateFileMapping got handle %d\n", (int) hMap);
     795               3 :   NaClLog(3, "NaClHostDescMap: dwDesiredAccess 0x%x\n", dwDesiredAccess);
     796                 : 
     797               3 :   retval = (uintptr_t) -NACL_ABI_EINVAL;
     798                 : 
     799                 :   for (chunk_offset = 0;
     800                 :        chunk_offset < len;
     801               3 :        chunk_offset += NACL_MAP_PAGESIZE) {
     802               3 :     uintptr_t chunk_addr = addr + chunk_offset;
     803                 :     nacl_off64_t net_offset;
     804                 :     uint32_t net_offset_high;
     805                 :     uint32_t net_offset_low;
     806                 : 
     807               3 :     (*effp->vtbl->UnmapMemory)(effp, chunk_addr, NACL_MAP_PAGESIZE);
     808                 : 
     809               3 :     chunk_size = size_min(len - chunk_offset, NACL_MAP_PAGESIZE);
     810                 :     /* in case MapViewOfFile cares that we exceed the file size */
     811               3 :     net_offset = offset + chunk_offset;
     812               3 :     net_offset_high = (uint32_t) (net_offset >> 32);
     813               3 :     net_offset_low = (uint32_t) net_offset;
     814                 :     NaClLog(4,
     815                 :             "NaClHostDescMap: MapViewOfFileEx(hMap=%d, dwDesiredAccess=0x%x,"
     816                 :             " net_offset_high = 0x%08x, net_offset_low = 0x%08x,"
     817                 :             " chunk_size = 0x%"NACL_PRIxS", chunk_addr = 0x%"NACL_PRIxPTR"\n",
     818                 :             hMap, dwDesiredAccess, net_offset_high, net_offset_low,
     819               3 :             chunk_size, chunk_addr);
     820                 :     map_result = (uintptr_t) MapViewOfFileEx(hMap,
     821                 :                                              dwDesiredAccess,
     822                 :                                              net_offset_high,
     823                 :                                              net_offset_low,
     824                 :                                              chunk_size,
     825               3 :                                              (void *) chunk_addr);
     826                 :     NaClLog(3,
     827                 :             "NaClHostDescMap: map_result %"NACL_PRIxPTR
     828                 :             ", chunk_addr %"NACL_PRIxPTR
     829                 :             ", addr + chunk_offset %"NACL_PRIxPTR"\n",
     830               3 :             map_result, chunk_addr, (addr + chunk_offset));
     831               3 :     if ((addr + chunk_offset) != map_result) {
     832                 :       /*
     833                 :        * MapViewOfFileEx() failed.  If we are mapping into untrusted
     834                 :        * address space, we opened an mmap hole.  We didn't expect the
     835                 :        * failure, and it's difficult to restore the old mappings that we
     836                 :        * removed, so for safety we must abort with LOG_FATAL.
     837                 :        *
     838                 :        * Otherwise, if this is a trusted mapping, we can return an error
     839                 :        * gracefully.  NaClElfFileMapSegment() currently triggers errors
     840                 :        * here by mapping beyond the file's extent: see
     841                 :        * https://crbug.com/406632.
     842                 :        */
     843                 :       int log_type =
     844               0 :           effp == NaClDescEffectorTrustedMem() ? LOG_ERROR : LOG_FATAL;
     845               0 :       DWORD err = GetLastError();
     846                 :       size_t unmap_offset;
     847                 :       NaClLog(log_type,
     848                 :               "MapViewOfFileEx failed at 0x%08"NACL_PRIxPTR
     849                 :               ", got 0x%08"NACL_PRIxPTR", err %x\n",
     850                 :               addr + chunk_offset,
     851                 :               map_result,
     852               0 :               err);
     853                 :       for (unmap_offset = 0;
     854                 :            unmap_offset < chunk_offset;
     855               0 :            unmap_offset += NACL_MAP_PAGESIZE) {
     856               0 :         (void) UnmapViewOfFile((void *) (addr + unmap_offset));
     857               0 :       }
     858               0 :       retval = (uintptr_t) -NaClXlateSystemError(err);
     859               0 :       goto cleanup;
     860                 :     }
     861                 :     if (!VirtualProtect((void *) map_result,
     862                 :                         NaClRoundPage(chunk_size),
     863                 :                         flProtect,
     864               3 :                         &flOldProtect)) {
     865               0 :         DWORD err = GetLastError();
     866                 :         NaClLog(LOG_INFO,
     867                 :                 "VirtualProtect failed at 0x%08x, err %x\n",
     868               0 :                 addr, err);
     869               0 :         retval = (uintptr_t) -NaClXlateSystemError(err);
     870               0 :         goto cleanup;
     871                 :     }
     872               3 :   }
     873               3 :   retval = (uintptr_t) start_addr;
     874                 : cleanup:
     875               3 :   (void) CloseHandle(hMap);
     876               3 :   NaClLog(3, "NaClHostDescMap: returning %"NACL_PRIxPTR"\n", retval);
     877               3 :   return retval;
     878               3 : }
     879                 : 
     880                 : int NaClHostDescUnmapUnsafe(void    *start_addr,
     881               3 :                             size_t  len) {
     882                 :   uintptr_t addr;
     883                 :   size_t    off;
     884                 : 
     885               3 :   addr = (uintptr_t) start_addr;
     886                 : 
     887               3 :   for (off = 0; off < len; off += NACL_MAP_PAGESIZE) {
     888               3 :     if (!UnmapViewOfFile((void *) (addr + off))) {
     889                 :       NaClLog(LOG_ERROR,
     890                 :               "NaClHostDescUnmap: UnmapViewOfFile(0x%08x) failed\n",
     891               0 :               addr + off);
     892               0 :       return -NACL_ABI_EINVAL;
     893                 :     }
     894               3 :   }
     895               3 :   return 0;
     896               3 : }
     897                 : 
     898                 : static void NaClHostDescCtorIntern(struct NaClHostDesc *hd,
     899                 :                                    int posix_d,
     900               6 :                                    int flags) {
     901                 :   nacl_host_stat_t stbuf;
     902                 : 
     903               6 :   hd->d = posix_d;
     904               6 :   hd->flags = flags;
     905               6 :   hd->flMappingProtect = 0;
     906               6 :   if (_fstat64(posix_d, &stbuf) != 0) {
     907                 :     /* inherited non-fstat'able are IPC channels, e.g., for bootstrap channel */
     908                 :     NaClLog(4,
     909                 :             "NaClHostDescCtorIntern: could not _fstat64,"
     910               0 :             " assuming non-seekable\n");
     911               0 :     hd->protect_filepos = 0;
     912               0 :   } else {
     913               6 :     int file_type = stbuf.st_mode & S_IFMT;
     914                 :     /*
     915                 :      * Inherited stdio are console handles and are not seekable.
     916                 :      *
     917                 :      * Posix descriptors (wrapping Windows HANDLES) opened for
     918                 :      * O_WRONLY | O_APPEND cannot have byte range locks applied, which
     919                 :      * is how the protect_filepos mechanism is implemented.  Luckily,
     920                 :      * this is only needed for O_RDWR | O_APPEND or non-append
     921                 :      * descriptor.
     922                 :      */
     923                 :     hd->protect_filepos = (((S_IFREG == file_type) ||
     924                 :                            (S_IFDIR == file_type)) &&
     925                 :                            !((flags & NACL_ABI_O_APPEND) != 0 &&
     926                 :                              (flags & NACL_ABI_O_ACCMODE) ==
     927               6 :                              NACL_ABI_O_WRONLY));
     928                 :   }
     929               6 :   if (!NaClFastMutexCtor(&hd->mu)) {
     930               0 :     NaClLog(LOG_FATAL, "NaClHostDescCtorIntern: NaClFastMutexCtor failed\n");
     931                 :   }
     932               6 : }
     933                 : 
     934                 : int NaClHostDescOpen(struct NaClHostDesc  *d,
     935                 :                      char const           *path,
     936                 :                      int                  flags,
     937               4 :                      int                  perms) {
     938                 :   DWORD dwDesiredAccess;
     939                 :   DWORD dwCreationDisposition;
     940                 :   DWORD dwFlagsAndAttributes;
     941                 :   int oflags;
     942               4 :   int truncate_after_open = 0;
     943                 :   HANDLE hFile;
     944                 :   DWORD err;
     945                 :   int fd;
     946                 : 
     947               4 :   if (NULL == d) {
     948               0 :     NaClLog(LOG_FATAL, "NaClHostDescOpen: 'this' is NULL\n");
     949                 :   }
     950                 : 
     951                 :   /*
     952                 :    * Sanitize access flags.
     953                 :    */
     954               4 :   if (0 != (flags & ~NACL_ALLOWED_OPEN_FLAGS)) {
     955               0 :     return -NACL_ABI_EINVAL;
     956                 :   }
     957                 : 
     958               4 :   switch (flags & NACL_ABI_O_ACCMODE) {
     959                 :     case NACL_ABI_O_RDONLY:
     960               2 :       dwDesiredAccess = GENERIC_READ | GENERIC_EXECUTE;
     961               2 :       oflags = _O_RDONLY | _O_BINARY;
     962               2 :       break;
     963                 :     case NACL_ABI_O_RDWR:
     964               3 :       oflags = _O_RDWR | _O_BINARY;
     965               3 :       dwDesiredAccess = GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE;
     966               3 :       break;
     967                 :     case NACL_ABI_O_WRONLY:  /* Enforced in the Read call */
     968               2 :       oflags = _O_WRONLY | _O_BINARY;
     969               2 :       dwDesiredAccess = GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE;
     970               2 :       break;
     971                 :     default:
     972                 :       NaClLog(LOG_ERROR,
     973                 :               "NaClHostDescOpen: bad access flags 0x%x.\n",
     974               0 :               flags);
     975               0 :       return -NACL_ABI_EINVAL;
     976                 :   }
     977                 :   /*
     978                 :    * Possibly make the file read-only.  The file attribute only
     979                 :    * applies if the file is created; if it pre-exists, the attributes
     980                 :    * from the file is combined with the FILE_FLAG_* values.
     981                 :    */
     982               4 :   if (0 == (perms & NACL_ABI_S_IWUSR)) {
     983                 :     dwFlagsAndAttributes = (FILE_ATTRIBUTE_READONLY |
     984               2 :                             FILE_FLAG_POSIX_SEMANTICS);
     985               2 :   } else {
     986                 :     dwFlagsAndAttributes = (FILE_ATTRIBUTE_NORMAL |
     987               3 :                             FILE_FLAG_POSIX_SEMANTICS);
     988                 :   }
     989                 :   /*
     990                 :    * Postcondition: flags & NACL_ABI_O_ACCMODE is one of the three
     991                 :    * allowed values.
     992                 :    */
     993               4 :   switch (flags & (NACL_ABI_O_CREAT | NACL_ABI_O_TRUNC)) {
     994                 :     case 0:
     995               2 :       dwCreationDisposition = OPEN_EXISTING;
     996               2 :       break;
     997                 :     case NACL_ABI_O_CREAT:
     998               2 :       dwCreationDisposition = OPEN_ALWAYS;
     999               2 :       break;
    1000                 :     case NACL_ABI_O_TRUNC:
    1001               0 :       dwCreationDisposition = TRUNCATE_EXISTING;
    1002               0 :       truncate_after_open = 1;
    1003               0 :       break;
    1004                 :     case NACL_ABI_O_CREAT | NACL_ABI_O_TRUNC:
    1005               2 :       dwCreationDisposition = OPEN_ALWAYS;
    1006               2 :       truncate_after_open = 1;
    1007                 :   }
    1008               4 :   if (0 != (flags & NACL_ABI_O_APPEND)) {
    1009               1 :     oflags |= _O_APPEND;
    1010                 :   }
    1011                 : 
    1012                 :   NaClLog(1,
    1013                 :           "NaClHostDescOpen: CreateFileA(path=%s, desired_access=0x%x,"
    1014                 :           " share_mode=ALL, security_attributes=NULL, creation_disposition=%d,"
    1015                 :           " flags_and_attributes=%d, template_file=NULL)\n",
    1016               4 :           path, dwDesiredAccess, dwCreationDisposition, dwFlagsAndAttributes);
    1017                 : 
    1018                 :   hFile = CreateFileA(path, dwDesiredAccess,
    1019                 :                       (FILE_SHARE_DELETE |
    1020                 :                        FILE_SHARE_READ |
    1021                 :                        FILE_SHARE_WRITE),
    1022                 :                       NULL,
    1023                 :                       dwCreationDisposition,
    1024                 :                       dwFlagsAndAttributes,
    1025               4 :                       NULL);
    1026               4 :   if (INVALID_HANDLE_VALUE == hFile) {
    1027               0 :     err = GetLastError();
    1028               0 :     NaClLog(3, "NaClHostDescOpen: CreateFile failed %d\n", err);
    1029               0 :     return -NaClXlateSystemError(err);
    1030                 :   }
    1031                 :   if (truncate_after_open &&
    1032               4 :       NACL_ABI_O_RDONLY != (flags & NACL_ABI_O_ACCMODE)) {
    1033               2 :     NaClLog(4, "NaClHostDescOpen: Truncating file\n");
    1034               2 :     if (!SetEndOfFile(hFile)) {
    1035               0 :       err = GetLastError();
    1036                 :       NaClLog(LOG_ERROR,
    1037                 :               "NaClHostDescOpen: could not truncate file:"
    1038                 :               " last error %d.\n",
    1039               0 :               err);
    1040               0 :       if (err == ERROR_USER_MAPPED_FILE) {
    1041                 :         NaClLog(LOG_ERROR,
    1042                 :                 "NaClHostDescOpen: this is due to an existing mapping"
    1043               0 :                 " of the same file.\n");
    1044                 :       }
    1045                 :     }
    1046                 :   }
    1047               4 :   fd = _open_osfhandle((intptr_t) hFile, oflags);
    1048                 :   /*
    1049                 :    * oflags _O_APPEND, _O_RDONLY, and _O_TEXT are meaningful; unclear
    1050                 :    * whether _O_RDWR, _O_WRONLY, etc has any effect.
    1051                 :    */
    1052               4 :   if (-1 == fd) {
    1053                 :     NaClLog(LOG_FATAL, "NaClHostDescOpen failed: err %d\n",
    1054               0 :             GetLastError());
    1055                 :   }
    1056               4 :   NaClHostDescCtorIntern(d, fd, flags);
    1057               4 :   return 0;
    1058               4 : }
    1059                 : 
    1060                 : int NaClHostDescPosixDup(struct NaClHostDesc  *d,
    1061                 :                          int                  posix_d,
    1062               0 :                          int                  flags) {
    1063                 :   int host_desc;
    1064                 : 
    1065                 :   NaClLog(3, "NaClHostDescPosixDup(0x%08x, %d, 0%o)\n",
    1066               0 :           (uintptr_t) d, posix_d, flags);
    1067               0 :   if (NULL == d) {
    1068               0 :     NaClLog(LOG_FATAL, "NaClHostDescPosixDup: 'this' is NULL\n");
    1069                 :   }
    1070                 :   /*
    1071                 :    * Sanitize access flags.
    1072                 :    */
    1073               0 :   if (0 != (flags & ~NACL_ALLOWED_OPEN_FLAGS)) {
    1074               0 :     return -NACL_ABI_EINVAL;
    1075                 :   }
    1076               0 :   switch (flags & NACL_ABI_O_ACCMODE) {
    1077                 :     case NACL_ABI_O_RDONLY:
    1078                 :     case NACL_ABI_O_WRONLY:
    1079                 :     case NACL_ABI_O_RDWR:
    1080               0 :       break;
    1081                 :     default:
    1082                 :       NaClLog(LOG_ERROR,
    1083                 :               "NaClHostDescOpen: bad access flags 0x%x.\n",
    1084               0 :               flags);
    1085               0 :       return -NACL_ABI_EINVAL;
    1086                 :   }
    1087                 : 
    1088               0 :   host_desc = _dup(posix_d);
    1089               0 :   if (-1 == host_desc) {
    1090               0 :     return -GetErrno();
    1091                 :   }
    1092               0 :   NaClHostDescCtorIntern(d, host_desc, flags);
    1093               0 :   return 0;
    1094               0 : }
    1095                 : 
    1096                 : int NaClHostDescPosixTake(struct NaClHostDesc *d,
    1097                 :                           int                 posix_d,
    1098               3 :                           int                 flags) {
    1099               3 :   if (NULL == d) {
    1100               0 :     NaClLog(LOG_FATAL, "NaClHostDescPosixTake: 'this' is NULL\n");
    1101                 :   }
    1102                 :   /*
    1103                 :    * Sanitize access flags.
    1104                 :    */
    1105               3 :   if (0 != (flags & ~NACL_ALLOWED_OPEN_FLAGS)) {
    1106               0 :     return -NACL_ABI_EINVAL;
    1107                 :   }
    1108               3 :   switch (flags & NACL_ABI_O_ACCMODE) {
    1109                 :     case NACL_ABI_O_RDONLY:
    1110                 :     case NACL_ABI_O_WRONLY:
    1111                 :     case NACL_ABI_O_RDWR:
    1112               3 :       break;
    1113                 :     default:
    1114                 :       NaClLog(LOG_ERROR,
    1115                 :               "NaClHostDescOpen: bad access flags 0x%x.\n",
    1116               0 :               flags);
    1117               0 :       return -NACL_ABI_EINVAL;
    1118                 :   }
    1119               3 :   NaClHostDescCtorIntern(d, posix_d, flags);
    1120               3 :   return 0;
    1121               3 : }
    1122                 : 
    1123                 : ssize_t NaClHostDescRead(struct NaClHostDesc  *d,
    1124                 :                          void                 *buf,
    1125               2 :                          size_t               len) {
    1126                 :   /* Windows ReadFile only supports DWORD, so we need
    1127                 :    * to clamp the length. */
    1128                 :   unsigned int actual_len;
    1129                 :   HANDLE fh;
    1130                 :   DWORD bytes_received;
    1131                 :   DWORD err;
    1132                 : 
    1133               2 :   if (len < UINT_MAX) {
    1134               2 :     actual_len = (unsigned int) len;
    1135               2 :   } else {
    1136               0 :     actual_len = UINT_MAX;
    1137                 :   }
    1138                 : 
    1139               2 :   NaClHostDescCheckValidity("NaClHostDescRead", d);
    1140               2 :   if (NACL_ABI_O_WRONLY == (d->flags & NACL_ABI_O_ACCMODE)) {
    1141               1 :     NaClLog(3, "NaClHostDescRead: WRONLY file\n");
    1142               1 :     return -NACL_ABI_EBADF;
    1143                 :   }
    1144                 :   /*
    1145                 :    * We drop into using Windows ReadFile rather than using _read from
    1146                 :    * the POSIX compatibility layer here.  The reason for this is
    1147                 :    * because the pread/pwrite implementation uses ReadFile/WriteFile,
    1148                 :    * it would be more consistent with the pread/pwrite implementation
    1149                 :    * to just also use ReadFile/WriteFile directly here as well.
    1150                 :    *
    1151                 :    * NB: contrary to the documentation available on MSDN, operations
    1152                 :    * on synchronous files with non-NULL LPOVERLAPPED arguments result
    1153                 :    * in the *implicit* file position getting updated before the
    1154                 :    * ReadFile/WriteFile returning, rather than the Offset/OffsetHigh
    1155                 :    * members of the explicit OVERLAPPED structure (!).  In order to
    1156                 :    * support mixed read/pread syscall sequences (and similarly mixed
    1157                 :    * write/pwrite sequences) we must effectively lock the file
    1158                 :    * position from access by other threads and then read/write, so
    1159                 :    * that when pread/pwrite mess up the implicit file position
    1160                 :    * temporarily, it would not be visible.
    1161                 :    */
    1162               2 :   fh = (HANDLE) _get_osfhandle(d->d);
    1163               2 :   CHECK(INVALID_HANDLE_VALUE != fh);
    1164                 : 
    1165                 :   /*
    1166                 :    * Ensure that we do not corrupt shared implicit file position.
    1167                 :    */
    1168               2 :   if (d->protect_filepos) {
    1169               2 :     NaClTakeFilePosLock(fh);
    1170                 :   }
    1171               2 :   if (!ReadFile(fh, buf, actual_len, &bytes_received, NULL)) {
    1172               0 :     err = GetLastError();
    1173               0 :     if (ERROR_HANDLE_EOF == err) {
    1174               0 :       bytes_received = 0;
    1175               0 :     } else {
    1176               0 :       NaClLog(4, "NaClHostDescRead: ReadFile error %d\n", err);
    1177               0 :       bytes_received = -NaClXlateSystemError(err);
    1178                 :     }
    1179                 :   }
    1180               2 :   if (d->protect_filepos) {
    1181               2 :     NaClDropFilePosLock(fh);
    1182                 :   }
    1183                 : 
    1184               2 :   return bytes_received;
    1185               2 : }
    1186                 : 
    1187                 : ssize_t NaClHostDescWrite(struct NaClHostDesc *d,
    1188                 :                           void const          *buf,
    1189               4 :                           size_t              len) {
    1190                 :   /*
    1191                 :    * Windows WriteFile only supports DWORD uint, so we need to clamp
    1192                 :    * the length.
    1193                 :    */
    1194                 :   unsigned int actual_len;
    1195                 :   HANDLE fh;
    1196                 :   DWORD bytes_written;
    1197                 :   DWORD err;
    1198                 :   OVERLAPPED overlap;
    1199               4 :   OVERLAPPED *overlap_ptr = NULL;
    1200                 : 
    1201               4 :   if (NACL_ABI_O_RDONLY == (d->flags & NACL_ABI_O_ACCMODE)) {
    1202               1 :     NaClLog(3, "NaClHostDescWrite: RDONLY file\n");
    1203               1 :     return -NACL_ABI_EBADF;
    1204                 :   }
    1205               4 :   if (len < UINT_MAX) {
    1206               4 :     actual_len = (unsigned int) len;
    1207               4 :   } else {
    1208               0 :     actual_len = UINT_MAX;
    1209                 :   }
    1210                 : 
    1211               4 :   NaClHostDescCheckValidity("NaClHostDescWrite", d);
    1212                 :   /*
    1213                 :    * See discussion in NaClHostDescRead above wrt why we use WriteFile
    1214                 :    * instead of _write below.
    1215                 :    */
    1216               4 :   if (0 != (NACL_ABI_O_APPEND & d->flags)) {
    1217               0 :     nacl_off64_t offset = GG_LONGLONG(0xffffffffffffffff);
    1218               0 :     memset(&overlap, 0, sizeof overlap);
    1219               0 :     overlap.Offset = (DWORD) offset;
    1220               0 :     overlap.OffsetHigh = (DWORD) (offset >> 32);
    1221               0 :     overlap_ptr = &overlap;
    1222                 :   }
    1223               4 :   fh = (HANDLE) _get_osfhandle(d->d);
    1224               4 :   CHECK(INVALID_HANDLE_VALUE != fh);
    1225                 :   /*
    1226                 :    * Ensure that we do not corrupt shared implicit file position.
    1227                 :    */
    1228               4 :   if (d->protect_filepos) {
    1229               4 :     NaClTakeFilePosLock(fh);
    1230                 :   }
    1231               4 :   if (!WriteFile(fh, buf, actual_len, &bytes_written, overlap_ptr)) {
    1232               0 :     err = GetLastError();
    1233               0 :     NaClLog(4, "NaClHostDescWrite: WriteFile error %d\n", err);
    1234                 : 
    1235               0 :     bytes_written = -NaClXlateSystemError(err);
    1236                 :   }
    1237               4 :   if (d->protect_filepos) {
    1238               4 :     NaClDropFilePosLock(fh);
    1239                 :   }
    1240                 : 
    1241               4 :   return bytes_written;
    1242               4 : }
    1243                 : 
    1244                 : nacl_off64_t NaClHostDescSeek(struct NaClHostDesc  *d,
    1245                 :                               nacl_off64_t         offset,
    1246               4 :                               int                  whence) {
    1247                 :   HANDLE hFile;
    1248                 :   nacl_off64_t retval;
    1249                 : 
    1250               4 :   NaClHostDescCheckValidity("NaClHostDescSeek", d);
    1251               4 :   hFile = (HANDLE) _get_osfhandle(d->d);
    1252               4 :   CHECK(INVALID_HANDLE_VALUE != hFile);
    1253               4 :   if (d->protect_filepos) {
    1254               4 :     NaClTakeFilePosLock(hFile);
    1255                 :   }
    1256               4 :   retval = _lseeki64(d->d, offset, whence);
    1257               4 :   if (d->protect_filepos) {
    1258               4 :     NaClDropFilePosLock(hFile);
    1259                 :   }
    1260               4 :   return (-1 == retval) ? -errno : retval;
    1261               4 : }
    1262                 : 
    1263                 : ssize_t NaClHostDescPRead(struct NaClHostDesc *d,
    1264                 :                           void *buf,
    1265                 :                           size_t len,
    1266               1 :                           nacl_off64_t offset) {
    1267                 :   HANDLE fh;
    1268                 :   OVERLAPPED overlap;
    1269                 :   DWORD bytes_received;
    1270                 :   DWORD err;
    1271               1 :   nacl_off64_t orig_pos = 0;
    1272                 : 
    1273               1 :   NaClHostDescCheckValidity("NaClHostDescPRead", d);
    1274               1 :   if (NACL_ABI_O_WRONLY == (d->flags & NACL_ABI_O_ACCMODE)) {
    1275               1 :     NaClLog(3, "NaClHostDescPRead: WRONLY file\n");
    1276               1 :     return -NACL_ABI_EBADF;
    1277                 :   }
    1278               1 :   if (offset < 0) {
    1279               1 :     return -NACL_ABI_EINVAL;
    1280                 :   }
    1281                 :   /*
    1282                 :    * There are reports of driver issues that may require clamping len
    1283                 :    * to a megabyte or so, lest ReadFile returns an error with
    1284                 :    * GetLastError() returning ERROR_INVALID_PARAMETER, but since we
    1285                 :    * do not expect to ever read from / write to anything other than
    1286                 :    * filesystem files, we do not clamp.
    1287                 :    */
    1288               1 :   fh = (HANDLE) _get_osfhandle(d->d);
    1289               1 :   CHECK(INVALID_HANDLE_VALUE != fh);
    1290               1 :   memset(&overlap, 0, sizeof overlap);
    1291               1 :   overlap.Offset = (DWORD) offset;
    1292               1 :   overlap.OffsetHigh = (DWORD) (offset >> 32);
    1293               1 :   if (len > UINT_MAX) {
    1294               0 :     len = UINT_MAX;
    1295                 :   }
    1296               1 :   if (d->protect_filepos) {
    1297               1 :     orig_pos = NaClLockAndGetCurrentFilePos(fh);
    1298                 :   }
    1299               1 :   if (!ReadFile(fh, buf, (DWORD) len, &bytes_received, &overlap)) {
    1300               0 :     err = GetLastError();
    1301               0 :     if (ERROR_HANDLE_EOF == err) {
    1302               0 :       bytes_received = 0;
    1303                 :       /* handle as if returned true. */
    1304               0 :     } else {
    1305               0 :       NaClLog(4, "NaClHostDescPRead: ReadFile failed, error %d\n", err);
    1306               0 :       NaClSetCurrentFilePosAndUnlock(fh, orig_pos);
    1307               0 :       bytes_received = -NaClXlateSystemError(err);
    1308                 :     }
    1309                 :   }
    1310               1 :   if (d->protect_filepos) {
    1311               1 :     NaClSetCurrentFilePosAndUnlock(fh, orig_pos);
    1312                 :   }
    1313               1 :   return bytes_received;
    1314               1 : }
    1315                 : 
    1316                 : ssize_t NaClHostDescPWrite(struct NaClHostDesc *d,
    1317                 :                            void const *buf,
    1318                 :                            size_t len,
    1319               1 :                            nacl_off64_t offset) {
    1320                 :   HANDLE fh;
    1321                 :   OVERLAPPED overlap;
    1322                 :   DWORD bytes_sent;
    1323                 :   DWORD err;
    1324               1 :   nacl_off64_t orig_pos = 0;
    1325                 : 
    1326               1 :   NaClHostDescCheckValidity("NaClHostDescPWrite", d);
    1327               1 :   if (NACL_ABI_O_RDONLY == (d->flags & NACL_ABI_O_ACCMODE)) {
    1328               1 :     NaClLog(3, "NaClHostDescPWrite: RDONLY file\n");
    1329               1 :     return -NACL_ABI_EBADF;
    1330                 :   }
    1331               1 :   if (offset < 0) {
    1332                 :     /*
    1333                 :      * This also avoids the case where having 0xffffffff in both
    1334                 :      * overlap.Offset and overlap.OffsetHigh means append to the file.
    1335                 :      * In Posix, offset does not permit special meanings being encoded
    1336                 :      * like this.
    1337                 :      */
    1338               0 :     return -NACL_ABI_EINVAL;
    1339                 :   }
    1340               1 :   fh = (HANDLE) _get_osfhandle(d->d);
    1341               1 :   CHECK(INVALID_HANDLE_VALUE != fh);
    1342               1 :   memset(&overlap, 0, sizeof overlap);
    1343               1 :   overlap.Offset = (DWORD) offset;
    1344               1 :   overlap.OffsetHigh = (DWORD) (offset >> 32);
    1345               1 :   if (len > UINT_MAX) {
    1346               0 :     len = UINT_MAX;
    1347                 :   }
    1348               1 :   if (d->protect_filepos) {
    1349               1 :     orig_pos = NaClLockAndGetCurrentFilePos(fh);
    1350                 :   }
    1351               1 :   if (!WriteFile(fh, buf, (DWORD) len, &bytes_sent, &overlap)) {
    1352               0 :     err = GetLastError();
    1353               0 :     if (ERROR_HANDLE_EOF == err) {
    1354               0 :       bytes_sent = 0;
    1355                 :       /* handle as if returned true. */
    1356               0 :     } else {
    1357                 :       NaClLog(4,
    1358               0 :               "NaClHostDescPWrite: WriteFile failed, error %d\n", err);
    1359               0 :       bytes_sent = -NaClXlateSystemError(err);
    1360                 :     }
    1361                 :   }
    1362               1 :   if (d->protect_filepos) {
    1363               1 :     NaClSetCurrentFilePosAndUnlock(fh, orig_pos);
    1364                 :   }
    1365               1 :   return bytes_sent;
    1366               1 : }
    1367                 : 
    1368                 : int NaClHostDescFstat(struct NaClHostDesc   *d,
    1369               1 :                       nacl_host_stat_t      *nasp) {
    1370               1 :   NaClHostDescCheckValidity("NaClHostDescFstat", d);
    1371               1 :   if (NACL_HOST_FSTAT64(d->d, nasp) == -1) {
    1372               0 :     return -GetErrno();
    1373                 :   }
    1374                 : 
    1375               1 :   return 0;
    1376               1 : }
    1377                 : 
    1378               0 : int NaClHostDescIsatty(struct NaClHostDesc *d) {
    1379                 :   int retval;
    1380                 : 
    1381               0 :   NaClHostDescCheckValidity("NaClHostDescIsatty", d);
    1382               0 :   retval = _isatty(d->d);
    1383                 :   /* When windows _isatty fails it returns zero, but does not set errno. */
    1384               0 :   return (0 == retval) ? -NACL_ABI_ENOTTY : 1;
    1385               0 : }
    1386                 : 
    1387               6 : int NaClHostDescClose(struct NaClHostDesc *d) {
    1388                 :   int retval;
    1389                 : 
    1390               6 :   NaClHostDescCheckValidity("NaClHostDescClose", d);
    1391               6 :   if (-1 != d->d) {
    1392               6 :     retval = _close(d->d);
    1393               6 :     if (-1 == retval) {
    1394               0 :       return -GetErrno();
    1395                 :     }
    1396               6 :     d->d = -1;
    1397                 :   }
    1398               6 :   NaClFastMutexDtor(&d->mu);
    1399               6 :   return 0;
    1400               6 : }
    1401                 : 
    1402                 : /*
    1403                 :  * This is not a host descriptor function, but is closely related to
    1404                 :  * fstat and should behave similarly.
    1405                 :  */
    1406               1 : int NaClHostDescStat(char const *path, nacl_host_stat_t *nhsp) {
    1407               1 :   if (NACL_HOST_STAT64(path, nhsp) == -1) {
    1408               0 :     return -GetErrno();
    1409                 :   }
    1410                 : 
    1411               1 :   return 0;
    1412               1 : }
    1413                 : 
    1414               0 : int NaClHostDescMkdir(const char *path, int mode) {
    1415                 :   UNREFERENCED_PARAMETER(mode);
    1416               0 :   if (_mkdir(path) != 0)
    1417               0 :     return -NaClXlateErrno(errno);
    1418               0 :   return 0;
    1419               0 : }
    1420                 : 
    1421               0 : int NaClHostDescRmdir(const char *path) {
    1422               0 :   if (_rmdir(path) != 0)
    1423               0 :     return -NaClXlateErrno(errno);
    1424               0 :   return 0;
    1425               0 : }
    1426                 : 
    1427               0 : int NaClHostDescChdir(const char *path) {
    1428               0 :   if (_chdir(path) != 0)
    1429               0 :     return -NaClXlateErrno(errno);
    1430               0 :   return 0;
    1431               0 : }
    1432                 : 
    1433               0 : int NaClHostDescGetcwd(char *path, size_t len) {
    1434               0 :   if (_getcwd(path, (int) len) == NULL)
    1435               0 :     return -NaClXlateErrno(errno);
    1436               0 :   return 0;
    1437               0 : }
    1438                 : 
    1439               0 : int NaClHostDescUnlink(const char *path) {
    1440                 :   /*
    1441                 :    * If the file exists and is not writable we make it writeable
    1442                 :    * before calling _unlink() to match the POSIX semantics where
    1443                 :    * unlink(2) can remove readonly files.
    1444                 :    */
    1445               0 :   if (_access(path, WIN_F_OK) == 0 && _access(path, WIN_W_OK) != 0) {
    1446               0 :     if (_chmod(path, _S_IREAD | S_IWRITE) != 0) {
    1447                 :       /* If _chmod fails just log it and contine on to call _unlink anyway */
    1448               0 :       NaClLog(3, "NaClHostDescUnlink: _chmod failed: %d\n", errno);
    1449                 :     }
    1450                 :   }
    1451                 : 
    1452               0 :   if (_unlink(path) != 0)
    1453               0 :     return -NaClXlateErrno(errno);
    1454                 : 
    1455               0 :   return 0;
    1456               0 : }
    1457                 : 
    1458               0 : int NaClHostDescTruncate(char const *path, nacl_abi_off_t length) {
    1459                 :   LARGE_INTEGER win_length;
    1460                 :   DWORD err;
    1461                 : 
    1462                 :   HANDLE hfile = CreateFileA(path,
    1463                 :       GENERIC_READ | GENERIC_WRITE,
    1464                 :       FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
    1465                 :       NULL,
    1466                 :       OPEN_EXISTING,
    1467                 :       FILE_ATTRIBUTE_NORMAL | FILE_FLAG_POSIX_SEMANTICS,
    1468               0 :       NULL);
    1469                 : 
    1470               0 :   if (INVALID_HANDLE_VALUE == hfile) {
    1471               0 :     err = GetLastError();
    1472               0 :     NaClLog(3, "NaClHostDescTruncate: CreateFile failed %d\n", err);
    1473               0 :     return -NaClXlateSystemError(err);
    1474                 :   }
    1475                 : 
    1476               0 :   win_length.QuadPart = length;
    1477               0 :   if (!SetFilePointerEx(hfile, win_length, NULL, FILE_BEGIN)) {
    1478               0 :     err = GetLastError();
    1479                 :     NaClLog(LOG_ERROR,
    1480                 :             "NaClHostDescTruncate: SetFilePointerEx failed:"
    1481               0 :             " last error %d.\n", err);
    1482               0 :     return -NaClXlateSystemError(err);
    1483                 :   }
    1484                 : 
    1485               0 :   if (!SetEndOfFile(hfile)) {
    1486               0 :     err = GetLastError();
    1487                 :     NaClLog(LOG_ERROR,
    1488                 :             "NaClHostDescTruncate: could not truncate file:"
    1489               0 :             " last error %d.\n", err);
    1490               0 :     if (err == ERROR_USER_MAPPED_FILE) {
    1491                 :       NaClLog(LOG_ERROR,
    1492                 :               "NaClHostDescTruncate: this is due to an existing"
    1493               0 :               " mapping of the same file.\n");
    1494                 :     }
    1495               0 :     return -NaClXlateSystemError(err);
    1496                 :   }
    1497                 : 
    1498               0 :   return 0;
    1499               0 : }
    1500                 : 
    1501               0 : int NaClHostDescLstat(char const *path, nacl_host_stat_t *nhsp) {
    1502                 :   /*
    1503                 :    * Since symlinks don't exist on windows, stat() and lstat()
    1504                 :    * are equivalent.
    1505                 :    */
    1506               0 :   return NaClHostDescStat(path, nhsp);
    1507               0 : }
    1508                 : 
    1509               0 : int NaClHostDescLink(const char *oldpath, const char *newpath) {
    1510                 :   /*
    1511                 :    * Hard linking not implemented for win32
    1512                 :    */
    1513               0 :   NaClLog(1, "NaClHostDescLink: hard linking not supported on windows.\n");
    1514               0 :   return -NACL_ABI_ENOSYS;
    1515               0 : }
    1516                 : 
    1517               0 : int NaClHostDescRename(const char *oldpath, const char *newpath) {
    1518               0 :   if (rename(oldpath, newpath) != 0)
    1519               0 :     return -NaClXlateErrno(errno);
    1520               0 :   return 0;
    1521               0 : }
    1522                 : 
    1523               0 : int NaClHostDescSymlink(const char *oldpath, const char *newpath) {
    1524                 :   /*
    1525                 :    * Symlinks are not supported on win32.
    1526                 :    */
    1527               0 :   NaClLog(1, "NaClHostDescSymlink: symbolic links not supported on windows.\n");
    1528               0 :   return -NACL_ABI_ENOSYS;
    1529               0 : }
    1530                 : 
    1531               0 : int NaClHostDescChmod(const char *path, nacl_abi_mode_t mode) {
    1532               0 :   if (_chmod(path, NaClMapMode(mode)) != 0)
    1533               0 :     return -NaClXlateErrno(errno);
    1534               0 :   return 0;
    1535               0 : }
    1536                 : 
    1537               0 : int NaClHostDescAccess(const char *path, int amode) {
    1538               0 :   if (_access(path, NaClMapAccessMode(amode)) != 0)
    1539               0 :     return -NaClXlateErrno(errno);
    1540               0 :   return 0;
    1541               0 : }
    1542                 : 
    1543               0 : int NaClHostDescReadlink(const char *path, char *buf, size_t bufsize) {
    1544                 :   /*
    1545                 :    * readlink(2) sets errno to EINVAL when the file in question is
    1546                 :    * not a symlink.  Since win32 does not support symlinks we simply
    1547                 :    * return EINVAL in all cases here.
    1548                 :    */
    1549                 :   NaClLog(1,
    1550               0 :           "NaClHostDescReadlink: symbolic links not supported on Windows.\n");
    1551               0 :   return -NACL_ABI_EINVAL;
    1552               0 : }

Generated by: LCOV version 1.7