LCOV - code coverage report
Current view: directory - src/trusted/desc - nacl_desc_imc_shm.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 193 98 50.8 %
Date: 2014-06-18 Functions: 0 0 -

       1                 : /*
       2                 :  * Copyright (c) 2012 The Native Client Authors. All rights reserved.
       3                 :  * Use of this source code is governed by a BSD-style license that can be
       4                 :  * found in the LICENSE file.
       5                 :  */
       6                 : 
       7                 : /*
       8                 :  * NaCl Service Runtime.  Transferrable shared memory objects.
       9                 :  */
      10                 : 
      11                 : #include "native_client/src/include/portability.h"
      12                 : #include "native_client/src/include/nacl_platform.h"
      13                 : 
      14                 : #include <stdlib.h>
      15                 : #include <string.h>
      16                 : 
      17                 : #include "native_client/src/shared/imc/nacl_imc_c.h"
      18                 : #include "native_client/src/trusted/desc/nacl_desc_base.h"
      19                 : #include "native_client/src/trusted/desc/nacl_desc_effector.h"
      20                 : #include "native_client/src/trusted/desc/nacl_desc_io.h"
      21                 : #include "native_client/src/trusted/desc/nacl_desc_imc_shm.h"
      22                 : 
      23                 : #include "native_client/src/shared/platform/nacl_find_addrsp.h"
      24                 : #include "native_client/src/shared/platform/nacl_host_desc.h"
      25                 : #include "native_client/src/shared/platform/nacl_log.h"
      26                 : #include "native_client/src/shared/platform/nacl_sync_checked.h"
      27                 : 
      28                 : #include "native_client/src/trusted/service_runtime/include/bits/mman.h"
      29                 : #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
      30                 : #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
      31                 : #include "native_client/src/trusted/service_runtime/include/sys/stat.h"
      32                 : #include "native_client/src/trusted/service_runtime/internal_errno.h"
      33                 : #include "native_client/src/trusted/service_runtime/nacl_config.h"
      34                 : 
      35                 : #ifndef SIZE_T_MAX
      36                 : # define SIZE_T_MAX   (~(size_t) 0)
      37                 : #endif
      38                 : 
      39                 : /*
      40                 :  * This file contains the implementation of the NaClDescImcShm
      41                 :  * subclass of NaClDesc.
      42                 :  *
      43                 :  * NaClDescImcShm is the subclass that wraps IMC shm descriptors.
      44                 :  */
      45                 : 
      46                 : static struct NaClDescVtbl const kNaClDescImcShmVtbl;  /* fwd */
      47                 : 
      48             284 : static int NaClDescImcShmSubclassCtor(struct NaClDescImcShm  *self,
      49             284 :                                       NaClHandle             h,
      50             284 :                                       nacl_off64_t           size) {
      51             284 :   struct NaClDesc *basep = (struct NaClDesc *) self;
      52                 : 
      53                 :   /*
      54                 :    * off_t is signed, but size_t are not; historically size_t is for
      55                 :    * sizeof and similar, and off_t is also used for stat structure
      56                 :    * st_size member.  This runtime test detects large object sizes
      57                 :    * that are silently converted to negative values.
      58                 :    */
      59             568 :   if (size < 0 || SIZE_T_MAX < (uint64_t) size) {
      60               0 :     return 0;
      61                 :   }
      62             284 :   self->h = h;
      63             284 :   self->size = size;
      64             284 :   basep->base.vtbl = (struct NaClRefCountVtbl const *) &kNaClDescImcShmVtbl;
      65             284 :   return 1;
      66             284 : }
      67                 : 
      68             284 : int NaClDescImcShmCtor(struct NaClDescImcShm  *self,
      69             284 :                        NaClHandle             h,
      70             284 :                        nacl_off64_t           size) {
      71             284 :   struct NaClDesc *basep = (struct NaClDesc *) self;
      72             284 :   int rv;
      73                 : 
      74             284 :   basep->base.vtbl = (struct NaClRefCountVtbl const *) NULL;
      75                 : 
      76             284 :   if (!NaClDescCtor(basep)) {
      77               0 :     return 0;
      78                 :   }
      79             284 :   rv = NaClDescImcShmSubclassCtor(self, h, size);
      80             284 :   if (!rv) {
      81                 :     /* NaClDescImcShm construction failed, still a NaClDesc object */
      82               0 :     (*NACL_VTBL(NaClRefCount, basep)->Dtor)((struct NaClRefCount *) basep);
      83               0 :   }
      84             284 :   (*NACL_VTBL(NaClDesc, basep)->SetFlags)(basep, NACL_ABI_O_RDWR);
      85             284 :   return 1;
      86             284 : }
      87                 : 
      88             284 : int NaClDescImcShmAllocCtor(struct NaClDescImcShm  *self,
      89             284 :                             nacl_off64_t           size,
      90             284 :                             int                    executable) {
      91             284 :   NaClHandle h;
      92             284 :   int        rv;
      93                 : 
      94             568 :   if (size < 0 || SIZE_T_MAX < (uint64_t) size) {
      95               0 :     NaClLog(4,
      96                 :             "NaClDescImcShmAllocCtor: requested size 0x%08"NACL_PRIx64
      97                 :             " (0x%08"NACL_PRId64") too large\n",
      98                 :             size, size);
      99               0 :     return 0;
     100                 :   }
     101             284 :   h = NaClCreateMemoryObject((size_t) size, executable);
     102             284 :   if (NACL_INVALID_HANDLE == h) {
     103               0 :     return 0;
     104                 :   }
     105             284 :   if (0 == (rv = NaClDescImcShmCtor(self, h, size))) {
     106               0 :     (void) NaClClose(h);
     107               0 :   }
     108             284 :   return rv;
     109             284 : }
     110                 : 
     111               0 : struct NaClDesc *NaClDescImcShmMake(NaClHandle handle, nacl_off64_t size) {
     112               0 :   struct NaClDescImcShm *desc = malloc(sizeof(*desc));
     113               0 :   if (NULL == desc) {
     114               0 :     return NULL;
     115                 :   }
     116               0 :   if (!NaClDescImcShmCtor(desc, handle, size)) {
     117               0 :     free(desc);
     118               0 :     return NULL;
     119                 :   }
     120               0 :   return &desc->base;
     121               0 : }
     122                 : 
     123               7 : static void NaClDescImcShmDtor(struct NaClRefCount *vself) {
     124               7 :   struct NaClDescImcShm  *self = (struct NaClDescImcShm *) vself;
     125                 : 
     126               7 :   (void) NaClClose(self->h);
     127               7 :   self->h = NACL_INVALID_HANDLE;
     128               7 :   vself->vtbl = (struct NaClRefCountVtbl const *) &kNaClDescVtbl;
     129               7 :   (*vself->vtbl->Dtor)(vself);
     130               7 : }
     131                 : 
     132             377 : static uintptr_t NaClDescImcShmMap(struct NaClDesc         *vself,
     133             377 :                                    struct NaClDescEffector *effp,
     134             377 :                                    void                    *start_addr,
     135             377 :                                    size_t                  len,
     136             377 :                                    int                     prot,
     137             377 :                                    int                     flags,
     138             377 :                                    nacl_off64_t            offset) {
     139             377 :   struct NaClDescImcShm  *self = (struct NaClDescImcShm *) vself;
     140                 : 
     141             377 :   int           nacl_imc_prot;
     142             377 :   int           nacl_imc_flags;
     143             377 :   uintptr_t     addr;
     144             377 :   void          *result;
     145             377 :   nacl_off64_t  tmp_off64;
     146                 : 
     147             377 :   NaClLog(4,
     148                 :           "NaClDescImcShmMmap(,,0x%08"NACL_PRIxPTR",0x%"NACL_PRIxS","
     149                 :           "0x%x,0x%x,0x%08"NACL_PRIxNACL_OFF64")\n",
     150                 :           (uintptr_t) start_addr, len, prot, flags, offset);
     151                 :   /*
     152                 :    * shm must have NACL_ABI_MAP_SHARED in flags, and all calls through
     153                 :    * this API must supply a start_addr, so NACL_ABI_MAP_FIXED is
     154                 :    * assumed.
     155                 :    */
     156             377 :   if (NACL_ABI_MAP_SHARED != (flags & NACL_ABI_MAP_SHARING_MASK)) {
     157               0 :     NaClLog(LOG_INFO,
     158                 :             ("NaClDescImcShmMap: Mapping not NACL_ABI_MAP_SHARED,"
     159                 :              " flags 0x%x\n"),
     160                 :             flags);
     161               0 :     return -NACL_ABI_EINVAL;
     162                 :   }
     163             672 :   if (0 != (NACL_ABI_MAP_FIXED & flags) && NULL == start_addr) {
     164               0 :     NaClLog(LOG_INFO,
     165                 :             ("NaClDescImcShmMap: Mapping NACL_ABI_MAP_FIXED"
     166                 :              " but start_addr is NULL\n"));
     167               0 :   }
     168                 :   /* post-condition: if NULL == start_addr, then NACL_ABI_MAP_FIXED not set */
     169                 : 
     170                 :   /*
     171                 :    * prot must not contain bits other than PROT_{READ|WRITE|EXEC}.
     172                 :    */
     173             377 :   if (0 != (~(NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE | NACL_ABI_PROT_EXEC)
     174                 :             & prot)) {
     175               0 :     NaClLog(LOG_INFO,
     176                 :             "NaClDescImcShmMap: prot has other bits than"
     177                 :             " PROT_{READ|WRITE|EXEC}\n");
     178               0 :     return -NACL_ABI_EINVAL;
     179                 :   }
     180                 :   /*
     181                 :    * Map from NACL_ABI_ prot and flags bits to IMC library flags,
     182                 :    * which will later map back into posix-style prot/flags on *x
     183                 :    * boxen, and to MapViewOfFileEx arguments on Windows.
     184                 :    */
     185             377 :   nacl_imc_prot = 0;
     186             377 :   if (NACL_ABI_PROT_READ & prot) {
     187             118 :     nacl_imc_prot |= NACL_PROT_READ;
     188             118 :   }
     189             377 :   if (NACL_ABI_PROT_WRITE & prot) {
     190             116 :     nacl_imc_prot |= NACL_PROT_WRITE;
     191             116 :   }
     192             377 :   if (NACL_ABI_PROT_EXEC & prot) {
     193               0 :     nacl_imc_prot |= NACL_PROT_EXEC;
     194               0 :   }
     195             377 :   nacl_imc_flags = NACL_MAP_SHARED;
     196             377 :   if (0 == (NACL_ABI_MAP_FIXED & flags)) {
     197                 :     /* start_addr is a hint, and we just ignore the hint... */
     198              82 :     if (!NaClFindAddressSpace(&addr, len)) {
     199               0 :       NaClLog(1, "NaClDescImcShmMap: no address space?!?\n");
     200               0 :       return -NACL_ABI_ENOMEM;
     201                 :     }
     202              82 :     start_addr = (void *) addr;
     203              82 :   }
     204             377 :   nacl_imc_flags |= NACL_MAP_FIXED;
     205                 : 
     206             377 :   tmp_off64 = offset + len;
     207                 :   /* just NaClRoundAllocPage, but in 64 bits */
     208             377 :   tmp_off64 = ((tmp_off64 + NACL_MAP_PAGESIZE - 1)
     209                 :              & ~(uint64_t) (NACL_MAP_PAGESIZE - 1));
     210             377 :   if (tmp_off64 > INT32_MAX) {
     211               0 :     NaClLog(LOG_INFO,
     212                 :             "NaClDescImcShmMap: total offset exceeds 32-bits\n");
     213               0 :     return -NACL_ABI_EOVERFLOW;
     214                 :   }
     215                 : 
     216             377 :   result = NaClMap(effp,
     217                 :                    (void *) start_addr,
     218                 :                    len,
     219                 :                    nacl_imc_prot,
     220                 :                    nacl_imc_flags,
     221                 :                    self->h,
     222                 :                    (off_t) offset);
     223             377 :   if (NACL_MAP_FAILED == result) {
     224               0 :     return -NACL_ABI_E_MOVE_ADDRESS_SPACE;
     225                 :   }
     226             672 :   if (0 != (NACL_ABI_MAP_FIXED & flags) && result != (void *) start_addr) {
     227               0 :     NaClLog(LOG_FATAL,
     228                 :             ("NaClDescImcShmMap: NACL_MAP_FIXED but got %p instead of %p\n"),
     229                 :             result, start_addr);
     230               0 :   }
     231             377 :   return (uintptr_t) start_addr;
     232             377 : }
     233                 : 
     234                 : #if NACL_WINDOWS
     235                 : static int NaClDescImcShmUnmapUnsafe(struct NaClDesc  *vself,
     236                 :                                      void             *start_addr,
     237                 :                                      size_t           len) {
     238                 :   int       retval;
     239                 :   uintptr_t addr;
     240                 :   uintptr_t end_addr;
     241                 : 
     242                 :   UNREFERENCED_PARAMETER(vself);
     243                 : 
     244                 :   retval = -NACL_ABI_EINVAL;
     245                 : 
     246                 :   for (addr = (uintptr_t) start_addr, end_addr = addr + len;
     247                 :        addr < end_addr;
     248                 :        addr += NACL_MAP_PAGESIZE) {
     249                 :     int       status;
     250                 : 
     251                 :     /*
     252                 :      * On windows, we must unmap "properly", since overmapping will
     253                 :      * not tear down existing page mappings.
     254                 :      */
     255                 :     status = NaClUnmap((void *) addr, NACL_MAP_PAGESIZE);
     256                 :     if (0 != status) {
     257                 :       NaClLog(LOG_FATAL, "NaClDescImcShmUnmapCommon: NaClUnmap failed\n");
     258                 :       goto done;
     259                 :     }
     260                 :   }
     261                 :   retval = 0;
     262                 : done:
     263                 :   return retval;
     264                 : }
     265                 : #endif
     266                 : 
     267              44 : static int NaClDescImcShmFstat(struct NaClDesc         *vself,
     268              44 :                                struct nacl_abi_stat    *stbp) {
     269              44 :   struct NaClDescImcShm  *self = (struct NaClDescImcShm *) vself;
     270                 : 
     271              44 :   if (self->size > INT32_MAX) {
     272               0 :     return -NACL_ABI_EOVERFLOW;
     273                 :   }
     274                 : 
     275              44 :   stbp->nacl_abi_st_dev = 0;
     276              44 :   stbp->nacl_abi_st_ino = 0x6c43614e;
     277              44 :   stbp->nacl_abi_st_mode = (NACL_ABI_S_IFSHM |
     278                 :                             NACL_ABI_S_IRUSR |
     279                 :                             NACL_ABI_S_IWUSR);
     280              44 :   stbp->nacl_abi_st_nlink = 1;
     281              44 :   stbp->nacl_abi_st_uid = -1;
     282              44 :   stbp->nacl_abi_st_gid = -1;
     283              44 :   stbp->nacl_abi_st_rdev = 0;
     284              44 :   stbp->nacl_abi_st_size = (nacl_abi_off_t) self->size;
     285              44 :   stbp->nacl_abi_st_blksize = 0;
     286              44 :   stbp->nacl_abi_st_blocks = 0;
     287              44 :   stbp->nacl_abi_st_atime = 0;
     288              44 :   stbp->nacl_abi_st_mtime = 0;
     289              44 :   stbp->nacl_abi_st_ctime = 0;
     290                 : 
     291              44 :   return 0;
     292              44 : }
     293                 : 
     294               0 : static int NaClDescImcShmExternalizeSize(struct NaClDesc *vself,
     295               0 :                                          size_t          *nbytes,
     296               0 :                                          size_t          *nhandles) {
     297               0 :   struct NaClDescImcShm  *self = (struct NaClDescImcShm *) vself;
     298               0 :   int rv;
     299                 : 
     300               0 :   rv = NaClDescExternalizeSize(vself, nbytes, nhandles);
     301               0 :   if (0 != rv) {
     302               0 :     return rv;
     303                 :   }
     304               0 :   *nbytes += sizeof self->size;
     305               0 :   *nhandles += 1;
     306                 : 
     307               0 :   return 0;
     308               0 : }
     309                 : 
     310               0 : static int NaClDescImcShmExternalize(struct NaClDesc           *vself,
     311               0 :                                      struct NaClDescXferState  *xfer) {
     312               0 :   struct NaClDescImcShm  *self = (struct NaClDescImcShm *) vself;
     313               0 :   int rv;
     314                 : 
     315               0 :   rv = NaClDescExternalize(vself, xfer);
     316               0 :   if (0 != rv) {
     317               0 :     return rv;
     318                 :   }
     319               0 :   *xfer->next_handle++ = self->h;
     320               0 :   memcpy(xfer->next_byte, &self->size, sizeof self->size);
     321               0 :   xfer->next_byte += sizeof self->size;
     322               0 :   return 0;
     323               0 : }
     324                 : 
     325                 : static struct NaClDescVtbl const kNaClDescImcShmVtbl = {
     326                 :   {
     327                 :     NaClDescImcShmDtor,
     328                 :   },
     329                 :   NaClDescImcShmMap,
     330                 : #if NACL_WINDOWS
     331                 :   NaClDescImcShmUnmapUnsafe,
     332                 : #else
     333                 :   NACL_DESC_UNMAP_NOT_IMPLEMENTED
     334                 : #endif
     335                 :   NaClDescReadNotImplemented,
     336                 :   NaClDescWriteNotImplemented,
     337                 :   NaClDescSeekNotImplemented,
     338                 :   NaClDescPReadNotImplemented,
     339                 :   NaClDescPWriteNotImplemented,
     340                 :   NaClDescImcShmFstat,
     341                 :   NaClDescGetdentsNotImplemented,
     342                 :   NaClDescImcShmExternalizeSize,
     343                 :   NaClDescImcShmExternalize,
     344                 :   NaClDescLockNotImplemented,
     345                 :   NaClDescTryLockNotImplemented,
     346                 :   NaClDescUnlockNotImplemented,
     347                 :   NaClDescWaitNotImplemented,
     348                 :   NaClDescTimedWaitAbsNotImplemented,
     349                 :   NaClDescSignalNotImplemented,
     350                 :   NaClDescBroadcastNotImplemented,
     351                 :   NaClDescSendMsgNotImplemented,
     352                 :   NaClDescRecvMsgNotImplemented,
     353                 :   NaClDescLowLevelSendMsgNotImplemented,
     354                 :   NaClDescLowLevelRecvMsgNotImplemented,
     355                 :   NaClDescConnectAddrNotImplemented,
     356                 :   NaClDescAcceptConnNotImplemented,
     357                 :   NaClDescPostNotImplemented,
     358                 :   NaClDescSemWaitNotImplemented,
     359                 :   NaClDescGetValueNotImplemented,
     360                 :   NaClDescSetMetadata,
     361                 :   NaClDescGetMetadata,
     362                 :   NaClDescSetFlags,
     363                 :   NaClDescGetFlags,
     364                 :   NaClDescIsattyNotImplemented,
     365                 :   NACL_DESC_SHM,
     366                 : };
     367                 : 
     368               0 : int NaClDescImcShmInternalize(struct NaClDesc               **out_desc,
     369               0 :                               struct NaClDescXferState      *xfer,
     370               0 :                               struct NaClDescQuotaInterface *quota_interface) {
     371               0 :   int                   rv;
     372               0 :   struct NaClDescImcShm *ndisp;
     373               0 :   NaClHandle            h;
     374               0 :   nacl_off64_t          hsize;
     375                 : 
     376               0 :   UNREFERENCED_PARAMETER(quota_interface);
     377               0 :   rv = -NACL_ABI_EIO;
     378                 : 
     379               0 :   ndisp = malloc(sizeof *ndisp);
     380               0 :   if (NULL == ndisp) {
     381               0 :     rv = -NACL_ABI_ENOMEM;
     382               0 :     goto cleanup;
     383                 :   }
     384               0 :   if (!NaClDescInternalizeCtor((struct NaClDesc *) ndisp, xfer)) {
     385               0 :     free(ndisp);
     386               0 :     ndisp = NULL;
     387               0 :     rv = -NACL_ABI_ENOMEM;
     388               0 :     goto cleanup;
     389                 :   }
     390                 : 
     391               0 :   if (xfer->next_handle == xfer->handle_buffer_end) {
     392               0 :     rv = -NACL_ABI_EIO;
     393               0 :     goto cleanup;
     394                 :   }
     395               0 :   if (xfer->next_byte + sizeof ndisp->size > xfer->byte_buffer_end) {
     396               0 :     rv = -NACL_ABI_EIO;
     397               0 :     goto cleanup;
     398                 :   }
     399                 : 
     400               0 :   h = *xfer->next_handle;
     401               0 :   *xfer->next_handle++ = NACL_INVALID_HANDLE;
     402               0 :   memcpy(&hsize, xfer->next_byte, sizeof hsize);
     403               0 :   xfer->next_byte += sizeof hsize;
     404                 : 
     405               0 :   if (!NaClDescImcShmSubclassCtor(ndisp, h, hsize)) {
     406               0 :     rv = -NACL_ABI_EIO;
     407               0 :     goto cleanup;
     408                 :   }
     409                 : 
     410               0 :   *out_desc = (struct NaClDesc *) ndisp;
     411               0 :   rv = 0;
     412                 : 
     413                 : cleanup:
     414               0 :   if (rv < 0) {
     415               0 :     NaClDescSafeUnref((struct NaClDesc *) ndisp);
     416               0 :   }
     417               0 :   return rv;
     418                 : }

Generated by: LCOV version 1.7