LCOV - code coverage report
Current view: directory - src/trusted/desc - nacl_desc_io.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 186 123 66.1 %
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                 : 
      12                 : #include "native_client/src/include/portability.h"
      13                 : 
      14                 : #if NACL_WINDOWS
      15                 : # include "io.h"
      16                 : # include "fcntl.h"
      17                 : #endif
      18                 : 
      19                 : #include <string.h>
      20                 : 
      21                 : #include "native_client/src/include/nacl_macros.h"
      22                 : #include "native_client/src/shared/imc/nacl_imc_c.h"
      23                 : #include "native_client/src/trusted/desc/nacl_desc_base.h"
      24                 : #include "native_client/src/trusted/desc/nacl_desc_effector.h"
      25                 : #include "native_client/src/trusted/desc/nacl_desc_io.h"
      26                 : 
      27                 : #include "native_client/src/shared/platform/nacl_find_addrsp.h"
      28                 : #include "native_client/src/shared/platform/nacl_host_desc.h"
      29                 : #include "native_client/src/shared/platform/nacl_log.h"
      30                 : 
      31                 : #include "native_client/src/trusted/service_runtime/include/bits/mman.h"
      32                 : #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
      33                 : #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
      34                 : #include "native_client/src/trusted/service_runtime/internal_errno.h"
      35                 : #include "native_client/src/trusted/service_runtime/nacl_config.h"
      36                 : 
      37                 : 
      38                 : /*
      39                 :  * This file contains the implementation for the NaClIoDesc subclass
      40                 :  * of NaClDesc.
      41                 :  *
      42                 :  * NaClDescIoDesc is the subclass that wraps host-OS descriptors
      43                 :  * provided by NaClHostDesc (which gives an OS-independent abstraction
      44                 :  * for host-OS descriptors).
      45                 :  */
      46                 : 
      47                 : static struct NaClDescVtbl const kNaClDescIoDescVtbl;  /* fwd */
      48                 : 
      49                 : static int NaClDescIoDescSubclassCtor(struct NaClDescIoDesc  *self,
      50               3 :                                       struct NaClHostDesc    *hd) {
      51               3 :   struct NaClDesc *basep = (struct NaClDesc *) self;
      52                 : 
      53               3 :   self->hd = hd;
      54               3 :   basep->base.vtbl = (struct NaClRefCountVtbl const *) &kNaClDescIoDescVtbl;
      55               3 :   return 1;
      56               3 : }
      57                 : 
      58                 : /*
      59                 :  * Takes ownership of hd, will close in Dtor.
      60                 :  */
      61                 : int NaClDescIoDescCtor(struct NaClDescIoDesc  *self,
      62               3 :                        struct NaClHostDesc    *hd) {
      63               3 :   struct NaClDesc *basep = (struct NaClDesc *) self;
      64                 :   int rv;
      65                 : 
      66               3 :   basep->base.vtbl = (struct NaClRefCountVtbl const *) NULL;
      67               3 :   if (!NaClDescCtor(basep)) {
      68               0 :     return 0;
      69                 :   }
      70               3 :   rv = NaClDescIoDescSubclassCtor(self, hd);
      71               3 :   if (!rv) {
      72               0 :     (*NACL_VTBL(NaClRefCount, basep)->Dtor)((struct NaClRefCount *) basep);
      73                 :   }
      74                 :   (*NACL_VTBL(NaClDesc, basep)->
      75               3 :    SetFlags)(basep, hd->flags & NACL_ABI_O_ACCMODE);
      76               3 :   return rv;
      77               3 : }
      78                 : 
      79               3 : static void NaClDescIoDescDtor(struct NaClRefCount *vself) {
      80               3 :   struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
      81                 : 
      82                 :   NaClLog(4, "NaClDescIoDescDtor(0x%08"NACL_PRIxPTR").\n",
      83               3 :           (uintptr_t) vself);
      84               3 :   if (0 != NaClHostDescClose(self->hd)) {
      85               0 :     NaClLog(LOG_FATAL, "NaClDescIoDescDtor: NaClHostDescClose failed\n");
      86                 :   }
      87               3 :   free(self->hd);
      88               3 :   self->hd = NULL;
      89               3 :   vself->vtbl = (struct NaClRefCountVtbl const *) &kNaClDescVtbl;
      90               3 :   (*vself->vtbl->Dtor)(vself);
      91               3 : }
      92                 : 
      93               3 : struct NaClDescIoDesc *NaClDescIoDescMake(struct NaClHostDesc *nhdp) {
      94                 :   struct NaClDescIoDesc *ndp;
      95                 : 
      96               3 :   ndp = malloc(sizeof *ndp);
      97               3 :   if (NULL == ndp) {
      98                 :     NaClLog(LOG_FATAL,
      99                 :             "NaClDescIoDescMake: no memory for 0x%08"NACL_PRIxPTR"\n",
     100               0 :             (uintptr_t) nhdp);
     101                 :   }
     102               3 :   if (!NaClDescIoDescCtor(ndp, nhdp)) {
     103                 :     NaClLog(LOG_FATAL,
     104                 :             ("NaClDescIoDescMake:"
     105                 :              " NaClDescIoDescCtor(0x%08"NACL_PRIxPTR",0x%08"NACL_PRIxPTR
     106                 :              ") failed\n"),
     107                 :             (uintptr_t) ndp,
     108               0 :             (uintptr_t) nhdp);
     109                 :   }
     110               3 :   return ndp;
     111               3 : }
     112                 : 
     113                 : struct NaClDesc *NaClDescIoDescFromHandleAllocCtor(NaClHandle handle,
     114               1 :                                                    int flags) {
     115                 :   int posix_d;
     116                 : 
     117                 : #if NACL_WINDOWS
     118               1 :   int win_flags = 0;
     119                 : 
     120               1 :   switch (flags & NACL_ABI_O_ACCMODE) {
     121                 :     case NACL_ABI_O_RDONLY:
     122               1 :       win_flags = _O_RDONLY | _O_BINARY;
     123               1 :       break;
     124                 :     case NACL_ABI_O_WRONLY:
     125               1 :       win_flags = _O_WRONLY | _O_BINARY;
     126               1 :       break;
     127                 :     case NACL_ABI_O_RDWR:
     128               1 :       win_flags = _O_RDWR | _O_BINARY;
     129                 :       break;
     130                 :   }
     131               1 :   if (0 == win_flags) {
     132               0 :     return NULL;
     133                 :   }
     134               1 :   posix_d = _open_osfhandle((intptr_t) handle, win_flags);
     135               1 :   if (-1 == posix_d) {
     136               0 :     return NULL;
     137                 :   }
     138                 : #else
     139                 :   posix_d = handle;
     140                 : #endif
     141               1 :   return NaClDescIoDescFromDescAllocCtor(posix_d, flags);
     142               1 : }
     143                 : 
     144                 : struct NaClDesc *NaClDescIoDescFromDescAllocCtor(int desc,
     145               1 :                                                  int flags) {
     146                 :   struct NaClHostDesc *nhdp;
     147                 : 
     148               1 :   nhdp = NaClHostDescPosixMake(desc, flags);
     149               1 :   if (NULL == nhdp) {
     150                 :     /*
     151                 :      * BUG: In Windows, we leak posix_d representation in the POSIX
     152                 :      * layer, since caller will continue to own |handle| on a failure
     153                 :      * return, but we cannot close |posix_d| without implicitly
     154                 :      * invoking CloseHandle on |handle|.
     155                 :      */
     156               0 :     return NULL;
     157                 :   }
     158               1 :   return (struct NaClDesc *) NaClDescIoDescMake(nhdp);
     159               1 : }
     160                 : 
     161                 : struct NaClDescIoDesc *NaClDescIoDescOpen(char const *path,
     162                 :                                           int mode,
     163               2 :                                           int perms) {
     164                 :   struct NaClHostDesc *nhdp;
     165                 : 
     166               2 :   nhdp = malloc(sizeof *nhdp);
     167               2 :   if (NULL == nhdp) {
     168               0 :     NaClLog(LOG_FATAL, "NaClDescIoDescOpen: no memory for %s\n", path);
     169                 :   }
     170               2 :   if (0 != NaClHostDescOpen(nhdp, path, mode, perms)) {
     171                 :     NaClLog(4,
     172                 :             "NaClDescIoDescOpen: NaClHostDescOpen failed for %s\n",
     173               0 :             path);
     174               0 :     return NULL;
     175                 :   }
     176               2 :   return NaClDescIoDescMake(nhdp);
     177               2 : }
     178                 : 
     179                 : static uintptr_t NaClDescIoDescMap(struct NaClDesc         *vself,
     180                 :                                    struct NaClDescEffector *effp,
     181                 :                                    void                    *start_addr,
     182                 :                                    size_t                  len,
     183                 :                                    int                     prot,
     184                 :                                    int                     flags,
     185               1 :                                    nacl_off64_t            offset) {
     186               1 :   struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
     187                 :   uintptr_t             status;
     188                 :   uintptr_t             addr;
     189                 : 
     190                 :   /*
     191                 :    * prot must only contain NACL_ABI_PROT_* flags.
     192                 :    */
     193               1 :   if (0 != (~(NACL_ABI_PROT_MASK) & prot)) {
     194                 :     NaClLog(LOG_INFO,
     195                 :             ("NaClDescIoDescMap: prot has other bits"
     196               0 :              " than NACL_ABI_PROT_{READ|WRITE|EXEC}\n"));
     197               0 :     return -NACL_ABI_EINVAL;
     198                 :   }
     199                 : 
     200               1 :   if (0 == (NACL_ABI_MAP_FIXED & flags)) {
     201               1 :     if (!NaClFindAddressSpace(&addr, len)) {
     202               0 :       NaClLog(1, "NaClDescIoDescMap: no address space?\n");
     203               0 :       return -NACL_ABI_ENOMEM;
     204                 :     }
     205                 :     NaClLog(4,
     206                 :             "NaClDescIoDescMap: NaClFindAddressSpace"
     207                 :             " returned 0x%"NACL_PRIxPTR"\n",
     208               1 :             addr);
     209               1 :     start_addr = (void *) addr;
     210                 :   }
     211               1 :   flags |= NACL_ABI_MAP_FIXED;
     212                 : 
     213                 :   status = NaClHostDescMap((NULL == self) ? NULL : self->hd,
     214                 :                            effp,
     215                 :                            (void *) start_addr,
     216                 :                            len,
     217                 :                            prot,
     218                 :                            flags,
     219               1 :                            offset);
     220               1 :   NaClLog(4, "NaClDescIoDescMap returning %"NACL_PRIxPTR"\n", status);
     221               1 :   return status;
     222               1 : }
     223                 : 
     224                 : uintptr_t NaClDescIoDescMapAnon(struct NaClDescEffector *effp,
     225                 :                                 void                    *start_addr,
     226                 :                                 size_t                  len,
     227                 :                                 int                     prot,
     228                 :                                 int                     flags,
     229               0 :                                 nacl_off64_t            offset) {
     230                 :   return NaClDescIoDescMap((struct NaClDesc *) NULL, effp, start_addr, len,
     231               0 :                            prot, flags, offset);
     232               0 : }
     233                 : 
     234                 : #if NACL_WINDOWS
     235                 : static int NaClDescIoDescUnmapUnsafe(struct NaClDesc  *vself,
     236                 :                                      void             *start_addr,
     237               0 :                                      size_t           len) {
     238                 :   UNREFERENCED_PARAMETER(vself);
     239               0 :   return NaClHostDescUnmapUnsafe(start_addr, len);
     240               0 : }
     241                 : #endif
     242                 : 
     243                 : static ssize_t NaClDescIoDescRead(struct NaClDesc          *vself,
     244                 :                                   void                     *buf,
     245               1 :                                   size_t                   len) {
     246               1 :   struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
     247                 : 
     248               1 :   return NaClHostDescRead(self->hd, buf, len);
     249               1 : }
     250                 : 
     251                 : static ssize_t NaClDescIoDescWrite(struct NaClDesc         *vself,
     252                 :                                    void const              *buf,
     253               2 :                                    size_t                  len) {
     254               2 :   struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
     255                 : 
     256               2 :   return NaClHostDescWrite(self->hd, buf, len);
     257               2 : }
     258                 : 
     259                 : static nacl_off64_t NaClDescIoDescSeek(struct NaClDesc          *vself,
     260                 :                                        nacl_off64_t             offset,
     261               2 :                                        int                      whence) {
     262               2 :   struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
     263                 : 
     264               2 :   return NaClHostDescSeek(self->hd, offset, whence);
     265               2 : }
     266                 : 
     267                 : static ssize_t NaClDescIoDescPRead(struct NaClDesc *vself,
     268                 :                                    void *buf,
     269                 :                                    size_t len,
     270               0 :                                    nacl_off64_t offset) {
     271               0 :   struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
     272                 : 
     273               0 :   return NaClHostDescPRead(self->hd, buf, len, offset);
     274               0 : }
     275                 : 
     276                 : static ssize_t NaClDescIoDescPWrite(struct NaClDesc *vself,
     277                 :                                     void const *buf,
     278                 :                                     size_t len,
     279               0 :                                     nacl_off64_t offset) {
     280               0 :   struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
     281                 : 
     282               0 :   return NaClHostDescPWrite(self->hd, buf, len, offset);
     283               0 : }
     284                 : 
     285                 : static int NaClDescIoDescFstat(struct NaClDesc         *vself,
     286               0 :                                struct nacl_abi_stat    *statbuf) {
     287               0 :   struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
     288                 :   int                   rv;
     289                 :   nacl_host_stat_t      hstatbuf;
     290                 : 
     291               0 :   rv = NaClHostDescFstat(self->hd, &hstatbuf);
     292               0 :   if (0 != rv) {
     293               0 :     return rv;
     294                 :   }
     295               0 :   return NaClAbiStatHostDescStatXlateCtor(statbuf, &hstatbuf);
     296               0 : }
     297                 : 
     298               0 : static int32_t NaClDescIoIsatty(struct NaClDesc *vself) {
     299               0 :   struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
     300                 : 
     301               0 :   return NaClHostDescIsatty(self->hd);
     302               0 : }
     303                 : 
     304                 : static int NaClDescIoDescExternalizeSize(struct NaClDesc *vself,
     305                 :                                          size_t          *nbytes,
     306               1 :                                          size_t          *nhandles) {
     307               1 :   struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
     308                 :   int rv;
     309                 : 
     310               1 :   rv = NaClDescExternalizeSize(vself, nbytes, nhandles);
     311               1 :   if (0 != rv) {
     312               0 :     return rv;
     313                 :   }
     314               1 :   *nhandles += 1;
     315               1 :   *nbytes += sizeof self->hd->flags;
     316                 :   /* For Windows, we do not need to send flProtect since it is a cache */
     317               1 :   return 0;
     318               1 : }
     319                 : 
     320                 : static int NaClDescIoDescExternalize(struct NaClDesc           *vself,
     321               1 :                                      struct NaClDescXferState  *xfer) {
     322               1 :   struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
     323                 :   int rv;
     324                 : #if NACL_WINDOWS
     325                 :   HANDLE  h;
     326                 : #endif
     327                 : 
     328               1 :   rv = NaClDescExternalize(vself, xfer);
     329               1 :   if (0 != rv) {
     330               0 :     return rv;
     331                 :   }
     332                 : 
     333               1 :   memcpy(xfer->next_byte, &self->hd->flags, sizeof self->hd->flags);
     334               1 :   xfer->next_byte += sizeof self->hd->flags;
     335                 : #if NACL_WINDOWS
     336               1 :   h = (HANDLE) _get_osfhandle(self->hd->d);
     337               1 :   *xfer->next_handle++ = (NaClHandle) h;
     338                 : #else
     339                 :   *xfer->next_handle++ = self->hd->d;
     340                 : #endif
     341               1 :   return 0;
     342               1 : }
     343                 : 
     344                 : static struct NaClDescVtbl const kNaClDescIoDescVtbl = {
     345                 :   {
     346                 :     NaClDescIoDescDtor,
     347                 :   },
     348                 :   NaClDescIoDescMap,
     349                 : #if NACL_WINDOWS
     350                 :   NaClDescIoDescUnmapUnsafe,
     351                 : #else
     352                 :   NACL_DESC_UNMAP_NOT_IMPLEMENTED
     353                 : #endif
     354                 :   NaClDescIoDescRead,
     355                 :   NaClDescIoDescWrite,
     356                 :   NaClDescIoDescSeek,
     357                 :   NaClDescIoDescPRead,
     358                 :   NaClDescIoDescPWrite,
     359                 :   NaClDescIoDescFstat,
     360                 :   NaClDescGetdentsNotImplemented,
     361                 :   NaClDescIoDescExternalizeSize,
     362                 :   NaClDescIoDescExternalize,
     363                 :   NaClDescLockNotImplemented,
     364                 :   NaClDescTryLockNotImplemented,
     365                 :   NaClDescUnlockNotImplemented,
     366                 :   NaClDescWaitNotImplemented,
     367                 :   NaClDescTimedWaitAbsNotImplemented,
     368                 :   NaClDescSignalNotImplemented,
     369                 :   NaClDescBroadcastNotImplemented,
     370                 :   NaClDescSendMsgNotImplemented,
     371                 :   NaClDescRecvMsgNotImplemented,
     372                 :   NaClDescLowLevelSendMsgNotImplemented,
     373                 :   NaClDescLowLevelRecvMsgNotImplemented,
     374                 :   NaClDescConnectAddrNotImplemented,
     375                 :   NaClDescAcceptConnNotImplemented,
     376                 :   NaClDescPostNotImplemented,
     377                 :   NaClDescSemWaitNotImplemented,
     378                 :   NaClDescGetValueNotImplemented,
     379                 :   NaClDescSetMetadata,
     380                 :   NaClDescGetMetadata,
     381                 :   NaClDescSetFlags,
     382                 :   NaClDescGetFlags,
     383                 :   NaClDescIoIsatty,
     384                 :   NACL_DESC_HOST_IO,
     385                 : };
     386                 : 
     387                 : /* set *out_desc to struct NaClDescIo * output */
     388                 : int NaClDescIoInternalize(struct NaClDesc               **out_desc,
     389                 :                           struct NaClDescXferState      *xfer,
     390               1 :                           struct NaClDescQuotaInterface *quota_interface) {
     391                 :   int                   rv;
     392                 :   NaClHandle            h;
     393                 :   int                   d;
     394                 :   int                   flags;
     395                 :   struct NaClHostDesc   *nhdp;
     396                 :   struct NaClDescIoDesc *ndidp;
     397                 : 
     398                 :   UNREFERENCED_PARAMETER(quota_interface);
     399               1 :   rv = -NACL_ABI_EIO;  /* catch-all */
     400               1 :   h = NACL_INVALID_HANDLE;
     401               1 :   nhdp = NULL;
     402               1 :   ndidp = NULL;
     403                 : 
     404               1 :   nhdp = malloc(sizeof *nhdp);
     405               1 :   if (NULL == nhdp) {
     406               0 :     rv = -NACL_ABI_ENOMEM;
     407               0 :     goto cleanup;
     408                 :   }
     409               1 :   ndidp = malloc(sizeof *ndidp);
     410               1 :   if (!ndidp) {
     411               0 :     rv = -NACL_ABI_ENOMEM;
     412               0 :     goto cleanup;
     413                 :   }
     414               1 :   if (!NaClDescInternalizeCtor((struct NaClDesc *) ndidp, xfer)) {
     415               0 :     rv = -NACL_ABI_ENOMEM;
     416               0 :     goto cleanup;
     417                 :   }
     418                 :   if (xfer->next_handle == xfer->handle_buffer_end ||
     419               1 :       xfer->next_byte + sizeof ndidp->hd->flags > xfer->byte_buffer_end) {
     420               0 :     rv = -NACL_ABI_EIO;
     421               0 :     goto cleanup_ndidp_dtor;
     422                 :   }
     423                 : 
     424               1 :   NACL_COMPILE_TIME_ASSERT(sizeof flags == sizeof(ndidp->hd->flags));
     425               1 :   memcpy(&flags, xfer->next_byte, sizeof flags);
     426               1 :   xfer->next_byte += sizeof flags;
     427                 : 
     428               1 :   h = *xfer->next_handle;
     429               1 :   *xfer->next_handle++ = NACL_INVALID_HANDLE;
     430                 : #if NACL_WINDOWS
     431               1 :   if (-1 == (d = _open_osfhandle((intptr_t) h, _O_RDWR | _O_BINARY))) {
     432               0 :     rv = -NACL_ABI_EIO;
     433               0 :     goto cleanup_ndidp_dtor;
     434                 :   }
     435                 : #else
     436                 :   d = h;
     437                 : #endif
     438                 :   /*
     439                 :    * We mark it as read/write, but don't really know for sure until we
     440                 :    * try to make those syscalls (in which case we'd get EBADF).
     441                 :    */
     442               1 :   if ((rv = NaClHostDescPosixTake(nhdp, d, flags)) < 0) {
     443               0 :     goto cleanup_ndidp_dtor;
     444                 :   }
     445               1 :   h = NACL_INVALID_HANDLE;  /* nhdp took ownership of h */
     446                 : 
     447               1 :   if (!NaClDescIoDescSubclassCtor(ndidp, nhdp)) {
     448               0 :     rv = -NACL_ABI_ENOMEM;
     449               0 :     goto cleanup_nhdp_dtor;
     450                 :   }
     451                 :   /*
     452                 :    * ndidp took ownership of nhdp, now give ownership of ndidp to caller.
     453                 :    */
     454               1 :   *out_desc = (struct NaClDesc *) ndidp;
     455               1 :   rv = 0;
     456                 :  cleanup_nhdp_dtor:
     457               1 :   if (rv < 0) {
     458               0 :     if (0 != NaClHostDescClose(nhdp)) {
     459               0 :       NaClLog(LOG_FATAL, "NaClDescIoInternalize: NaClHostDescClose failed\n");
     460                 :     }
     461                 :   }
     462                 :  cleanup_ndidp_dtor:
     463               1 :   if (rv < 0) {
     464               0 :     NaClDescSafeUnref((struct NaClDesc *) ndidp);
     465               0 :     ndidp = NULL;
     466                 :   }
     467                 :  cleanup:
     468               1 :   if (rv < 0) {
     469               0 :     free(nhdp);
     470               0 :     free(ndidp);
     471               0 :     if (NACL_INVALID_HANDLE != h) {
     472               0 :       (void) NaClClose(h);
     473                 :     }
     474                 :   }
     475               1 :   return rv;
     476               1 : }

Generated by: LCOV version 1.7