LCOV - code coverage report
Current view: directory - src/trusted/desc - nacl_desc_imc.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 123 43 35.0 %
Date: 2012-02-16 Functions: 0 0 -

       1                 : /*
       2                 :  * Copyright 2008 The Native Client Authors. All rights reserved.
       3                 :  * Use of this source code is governed by a BSD-style license that can
       4                 :  * be found in the LICENSE file.
       5                 :  */
       6                 : 
       7                 : /*
       8                 :  * NaCl Service Runtime.  I/O Descriptor / Handle abstraction.
       9                 :  */
      10                 : 
      11                 : #include <stdlib.h>
      12                 : #include <string.h>
      13                 : #include <errno.h>
      14                 : 
      15                 : #include "native_client/src/include/portability.h"
      16                 : 
      17                 : #include "native_client/src/trusted/desc/nacl_desc_base.h"
      18                 : #include "native_client/src/trusted/desc/nacl_desc_imc.h"
      19                 : 
      20                 : #include "native_client/src/shared/platform/nacl_log.h"
      21                 : #include "native_client/src/shared/platform/nacl_sync.h"
      22                 : #include "native_client/src/shared/platform/nacl_sync_checked.h"
      23                 : 
      24                 : #if NACL_WINDOWS
      25                 : # include "native_client/src/shared/platform/win/xlate_system_error.h"
      26                 : #endif
      27                 : 
      28                 : #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
      29                 : #include "native_client/src/trusted/service_runtime/include/sys/stat.h"
      30                 : 
      31                 : /*
      32                 :  * This file contains the implementation of the NaClDescImcDesc
      33                 :  * subclass of NaClDesc.
      34                 :  *
      35                 :  * NaClDescImcDesc is the subclass that wraps IMC socket descriptors.
      36                 :  */
      37                 : 
      38                 : /* fwd */
      39                 : static struct NaClDescVtbl const kNaClDescImcConnectedDescVtbl;
      40                 : static struct NaClDescVtbl const kNaClDescImcDescVtbl;
      41                 : static struct NaClDescVtbl const kNaClDescXferableDataDescVtbl;
      42                 : 
      43                 : int NaClDescImcConnectedDescCtor(struct NaClDescImcConnectedDesc  *self,
      44              84 :                                  NaClHandle                       h) {
      45              84 :   struct NaClDesc *basep = (struct NaClDesc *) self;
      46                 : 
      47              84 :   basep->base.vtbl = (struct NaClRefCountVtbl const *) NULL;
      48                 : 
      49              84 :   if (!NaClDescCtor(basep)) {
      50               0 :     return 0;
      51                 :   }
      52              84 :   self->h = h;
      53              84 :   basep->base.vtbl = (struct NaClRefCountVtbl const *)
      54                 :       &kNaClDescImcConnectedDescVtbl;
      55                 : 
      56              84 :   return 1;
      57                 : }
      58                 : 
      59              75 : static void NaClDescImcConnectedDescDtor(struct NaClRefCount *vself) {
      60                 :   struct NaClDescImcConnectedDesc *self = ((struct NaClDescImcConnectedDesc *)
      61              75 :                                            vself);
      62              75 :   (void) NaClClose(self->h);
      63              75 :   self->h = NACL_INVALID_HANDLE;
      64              75 :   vself->vtbl = (struct NaClRefCountVtbl const *) &kNaClDescVtbl;
      65              75 :   (*vself->vtbl->Dtor)(vself);
      66              75 : }
      67                 : 
      68                 : int NaClDescImcDescCtor(struct NaClDescImcDesc  *self,
      69              84 :                         NaClHandle              h) {
      70                 :   int retval;
      71                 : 
      72              84 :   retval = NaClDescImcConnectedDescCtor(&self->base, h);
      73              84 :   if (!retval) {
      74               0 :     return 0;
      75                 :   }
      76              84 :   if (!NaClMutexCtor(&self->sendmsg_mu)) {
      77               0 :     NaClDescUnref((struct NaClDesc *) self);
      78               0 :     return 0;
      79                 :   }
      80              84 :   if (!NaClMutexCtor(&self->recvmsg_mu)) {
      81               0 :     NaClMutexDtor(&self->sendmsg_mu);
      82               0 :     NaClDescUnref((struct NaClDesc *) self);
      83               0 :     return 0;
      84                 :   }
      85              84 :   self->base.base.base.vtbl = (struct NaClRefCountVtbl const *)
      86                 :       &kNaClDescImcDescVtbl;
      87                 : 
      88              84 :   return retval;
      89                 : }
      90                 : 
      91              75 : static void NaClDescImcDescDtor(struct NaClRefCount *vself) {
      92                 :   struct NaClDescImcDesc *self = ((struct NaClDescImcDesc *)
      93              75 :                                   vself);
      94              75 :   NaClMutexDtor(&self->sendmsg_mu);
      95              75 :   NaClMutexDtor(&self->recvmsg_mu);
      96                 : 
      97              75 :   vself->vtbl = (struct NaClRefCountVtbl const *)
      98                 :       &kNaClDescImcConnectedDescVtbl;
      99              75 :   (*vself->vtbl->Dtor)(vself);
     100              75 : }
     101                 : 
     102                 : int NaClDescXferableDataDescCtor(struct NaClDescXferableDataDesc  *self,
     103               0 :                                  NaClHandle                       h) {
     104                 :   int retval;
     105               0 :   retval = NaClDescImcConnectedDescCtor(&self->base, h);
     106               0 :   if (!retval) {
     107               0 :     return 0;
     108                 :   }
     109               0 :   self->base.base.base.vtbl = (struct NaClRefCountVtbl const *)
     110                 :       &kNaClDescXferableDataDescVtbl;
     111                 : 
     112               0 :   return retval;
     113                 : }
     114                 : 
     115               0 : static void NaClDescXferableDataDescDtor(struct NaClRefCount *vself) {
     116               0 :   vself->vtbl = (struct NaClRefCountVtbl const *)
     117                 :       &kNaClDescImcConnectedDescVtbl;
     118               0 :   (*vself->vtbl->Dtor)(vself);
     119               0 : }
     120                 : 
     121                 : int NaClDescImcDescFstat(struct NaClDesc          *vself,
     122               0 :                          struct nacl_abi_stat     *statbuf) {
     123                 :   UNREFERENCED_PARAMETER(vself);
     124                 : 
     125               0 :   memset(statbuf, 0, sizeof *statbuf);
     126               0 :   statbuf->nacl_abi_st_mode = (NACL_ABI_S_IFSOCK |
     127                 :                                NACL_ABI_S_IRUSR |
     128                 :                                NACL_ABI_S_IWUSR);
     129               0 :   return 0;
     130                 : }
     131                 : 
     132                 : static int NaClDescXferableDataDescFstat(struct NaClDesc          *vself,
     133               0 :                                          struct nacl_abi_stat     *statbuf) {
     134                 :   UNREFERENCED_PARAMETER(vself);
     135                 : 
     136               0 :   memset(statbuf, 0, sizeof *statbuf);
     137               0 :   statbuf->nacl_abi_st_mode = NACL_ABI_S_IFDSOCK;
     138               0 :   return 0;
     139                 : }
     140                 : 
     141                 : static int NaClDescXferableDataDescExternalizeSize(struct NaClDesc  *vself,
     142                 :                                                    size_t           *nbytes,
     143               0 :                                                    size_t           *nhandles) {
     144                 :   UNREFERENCED_PARAMETER(vself);
     145               0 :   NaClLog(4, "Entered NaClDescXferableDataDescExternalizeSize\n");
     146               0 :   *nbytes = 0;
     147               0 :   *nhandles = 1;
     148                 : 
     149               0 :   return 0;
     150                 : }
     151                 : 
     152                 : static int NaClDescXferableDataDescExternalize(struct NaClDesc          *vself,
     153               0 :                                                struct NaClDescXferState *xfer) {
     154                 :   struct NaClDescXferableDataDesc *self = ((struct NaClDescXferableDataDesc *)
     155               0 :                                            vself);
     156                 : 
     157               0 :   NaClLog(4, "Entered NaClDescXferableDataDescExternalize\n");
     158               0 :   *xfer->next_handle++ = self->base.h;
     159               0 :   return 0;
     160                 : }
     161                 : 
     162                 : 
     163                 : /*
     164                 :  * In the level of NaClDescImcDescSendMsg, we do not know what
     165                 :  * protocol is implemented by NaClSendDatagram (and indeed, in the
     166                 :  * Windows implementation, the access rights transfer involves a more
     167                 :  * complex protocol to get the peer process id).  Because the
     168                 :  * underlying low-level IMC implementation does not provide thread
     169                 :  * safety, this is the source of race conditions: two simultaneous
     170                 :  * imc_sendmsg syscalls to the same descriptor could get their various
     171                 :  * protcol bits interleaved, so the receiver will get garbled data
     172                 :  * that cause the wrong underlying host OS descriptor to be made
     173                 :  * available to the NaCl module.
     174                 :  *
     175                 :  * In order to address this issue, we (1) make descriptors that can
     176                 :  * transfer other descriptors non-transferable, and (2) we use locking
     177                 :  * so that only one thread can be performing (the low level bits of)
     178                 :  * imc_msgsend at a time.  The non-transferability of such descriptors
     179                 :  * addresses the multi-module scenario, as opposed to the
     180                 :  * multi-threaded scenario, where a sender race cause receiver
     181                 :  * confusion.
     182                 :  */
     183                 : static ssize_t NaClDescImcDescSendMsg(struct NaClDesc                *vself,
     184                 :                                       struct NaClMessageHeader const *dgram,
     185            9327 :                                int                            flags) {
     186                 :   struct NaClDescImcDesc *self = ((struct NaClDescImcDesc *)
     187            9327 :                                   vself);
     188                 :   int result;
     189                 : 
     190            9327 :   NaClXMutexLock(&self->sendmsg_mu);
     191            9327 :   result = NaClSendDatagram(self->base.h, dgram, flags);
     192            9327 :   NaClXMutexUnlock(&self->sendmsg_mu);
     193                 : 
     194            9327 :   if (-1 == result) {
     195                 : #if NACL_WINDOWS
     196                 :     return -NaClXlateSystemError(GetLastError());
     197                 : #elif NACL_LINUX || NACL_OSX
     198               0 :     return -NaClXlateErrno(errno);
     199                 : #else
     200                 : # error "Unknown target platform: cannot translate error code(s) from SendMsg"
     201                 : #endif
     202                 :   }
     203            9327 :   return result;
     204                 : }
     205                 : 
     206                 : 
     207                 : /*
     208                 :  * NaClDescXferableDataDescSendMsg implements imc_sendmsg For
     209                 :  * data-only descriptors.  We assume that whatever protocol exists at
     210                 :  * the NaClSendDatagram level is still not thread safe, but that the
     211                 :  * lack of thread safety will not have a significant impact on
     212                 :  * security.  This is still somewhat brittle: the low-level Windows
     213                 :  * IMC code can be convinced to do the wrong thing still via sender
     214                 :  * races, but the receiver, because it expects zero handles, will have
     215                 :  * called ReceiveDatagram in such a way that any "received handles"
     216                 :  * are closed.  This implies that arbitrary Windows handles can be
     217                 :  * made to be closed, including those not accessible by NaCl modules,
     218                 :  * but fortunately this should only result in a denial of service as
     219                 :  * the error caused by the use of an invalid handle is detected by the
     220                 :  * service runtime and cause an abort.
     221                 :  *
     222                 :  * Note that it is still an application error to send or receive data
     223                 :  * with a transferable data-only descriptor from two threads (or two
     224                 :  * modules) simultaneously.
     225                 :  */
     226                 : static ssize_t
     227                 : NaClDescXferableDataDescSendMsg(struct NaClDesc                *vself,
     228                 :                                 struct NaClMessageHeader const *dgram,
     229               0 :                                 int                            flags) {
     230                 :   struct NaClDescXferableDataDesc *self = ((struct NaClDescXferableDataDesc *)
     231               0 :                                            vself);
     232                 :   int result;
     233                 : 
     234               0 :   if (0 != dgram->handle_count) {
     235                 :     /*
     236                 :      * A transferable descriptor cannot be used to transfer other
     237                 :      * descriptors.
     238                 :      */
     239               0 :     NaClLog(2,
     240                 :             ("NaClDescXferableDataDescSendMsg: tranferable and"
     241                 :              " non-zero handle_count\n"));
     242               0 :     return -NACL_ABI_EINVAL;
     243                 :   }
     244                 : 
     245               0 :   result = NaClSendDatagram(self->base.h, dgram, flags);
     246                 : 
     247               0 :   if (-1 == result) {
     248                 : #if NACL_WINDOWS
     249                 :     return -NaClXlateSystemError(GetLastError());
     250                 : #elif NACL_LINUX || NACL_OSX
     251               0 :     return -NaClXlateErrno(errno);
     252                 : #else
     253                 : # error "Unknown target platform: cannot translate error code(s) from SendMsg"
     254                 : #endif
     255                 :   }
     256               0 :   return result;
     257                 : }
     258                 : 
     259                 : 
     260                 : /*
     261                 :  * See discussion at NaClDescImcDescSendMsg for details.  An
     262                 :  * imc_recvmsg race is not substantively different from an imc_sendmsg
     263                 :  * race.
     264                 :  */
     265                 : static ssize_t NaClDescImcDescRecvMsg(struct NaClDesc          *vself,
     266                 :                                       struct NaClMessageHeader *dgram,
     267            9346 :                                       int                      flags) {
     268                 :   struct NaClDescImcDesc *self = ((struct NaClDescImcDesc *)
     269            9346 :                                   vself);
     270                 :   int result;
     271                 : 
     272            9346 :   NaClLog(4, "Entered NaClDescImcDescRecvMsg, h=%d\n", self->base.h);
     273            9346 :   NaClXMutexLock(&self->recvmsg_mu);
     274            9346 :   result = NaClReceiveDatagram(self->base.h, dgram, flags);
     275            9346 :   NaClXMutexUnlock(&self->recvmsg_mu);
     276                 : 
     277            9346 :   if (-1 == result) {
     278                 : #if NACL_WINDOWS
     279                 :     return -NaClXlateSystemError(GetLastError());
     280                 : #elif NACL_LINUX || NACL_OSX
     281               0 :     return -errno;
     282                 : #else
     283                 : # error "Unknown target platform: cannot translate error code(s) from RecvMsg"
     284                 : #endif
     285                 :   }
     286            9346 :   return result;
     287                 : }
     288                 : 
     289                 : 
     290                 : /*
     291                 :  * See discussion at NaClDescXferableDataDescSendMsg for details.  An
     292                 :  * imc_recvmsg race is not substantively different from an imc_sendmsg
     293                 :  * race.
     294                 :  */
     295                 : static ssize_t NaClDescXferableDataDescRecvMsg(struct NaClDesc          *vself,
     296                 :                                                struct NaClMessageHeader *dgram,
     297               0 :                                                int                      flags) {
     298                 :   struct NaClDescXferableDataDesc *self = ((struct NaClDescXferableDataDesc *)
     299               0 :                                            vself);
     300                 :   int                             result;
     301                 : 
     302               0 :   NaClLog(4, "Entered NaClDescXferableDataDescRecvMsg, h = %d\n", self->base.h);
     303               0 :   if (0 != dgram->handle_count) {
     304                 :     /*
     305                 :      * A transferable descriptor is data-only, and it is an error to
     306                 :      * try to receive any I/O descriptors with it.
     307                 :      */
     308               0 :     NaClLog(2,
     309                 :             "NaClDescXferableDataDescRecvMsg:"
     310                 :             " tranferable and non-zero handle_count\n");
     311               0 :     return -NACL_ABI_EINVAL;
     312                 :   }
     313                 : 
     314               0 :   result = NaClReceiveDatagram(self->base.h, dgram, flags);
     315                 : 
     316               0 :   if (-1 == result) {
     317                 : #if NACL_WINDOWS
     318                 :     return -NaClXlateSystemError(GetLastError());
     319                 : #elif NACL_LINUX || NACL_OSX
     320               0 :     return -errno;
     321                 : #else
     322                 : # error "Unknown target platform: cannot translate error code(s) from RecvMsg"
     323                 : #endif
     324                 :   }
     325               0 :   return result;
     326                 : }
     327                 : 
     328                 : 
     329                 : static struct NaClDescVtbl const kNaClDescImcConnectedDescVtbl = {
     330                 :   {
     331                 :     NaClDescImcConnectedDescDtor,
     332                 :   },
     333                 :   NaClDescMapNotImplemented,
     334                 :   NaClDescUnmapUnsafeNotImplemented,
     335                 :   NaClDescUnmapNotImplemented,
     336                 :   NaClDescReadNotImplemented,
     337                 :   NaClDescWriteNotImplemented,
     338                 :   NaClDescSeekNotImplemented,
     339                 :   NaClDescIoctlNotImplemented,
     340                 :   NaClDescFstatNotImplemented,
     341                 :   NaClDescGetdentsNotImplemented,
     342                 :   NACL_DESC_CONNECTED_SOCKET,
     343                 :   NaClDescExternalizeSizeNotImplemented,
     344                 :   NaClDescExternalizeNotImplemented,
     345                 :   NaClDescLockNotImplemented,
     346                 :   NaClDescTryLockNotImplemented,
     347                 :   NaClDescUnlockNotImplemented,
     348                 :   NaClDescWaitNotImplemented,
     349                 :   NaClDescTimedWaitAbsNotImplemented,
     350                 :   NaClDescSignalNotImplemented,
     351                 :   NaClDescBroadcastNotImplemented,
     352                 :   NaClDescSendMsgNotImplemented,
     353                 :   NaClDescRecvMsgNotImplemented,
     354                 :   NaClDescConnectAddrNotImplemented,
     355                 :   NaClDescAcceptConnNotImplemented,
     356                 :   NaClDescPostNotImplemented,
     357                 :   NaClDescSemWaitNotImplemented,
     358                 :   NaClDescGetValueNotImplemented,
     359                 : };
     360                 : 
     361                 : 
     362                 : static struct NaClDescVtbl const kNaClDescImcDescVtbl = {
     363                 :   {
     364                 :     NaClDescImcDescDtor,  /* diff */
     365                 :   },
     366                 :   NaClDescMapNotImplemented,
     367                 :   NaClDescUnmapUnsafeNotImplemented,
     368                 :   NaClDescUnmapNotImplemented,
     369                 :   NaClDescReadNotImplemented,
     370                 :   NaClDescWriteNotImplemented,
     371                 :   NaClDescSeekNotImplemented,
     372                 :   NaClDescIoctlNotImplemented,
     373                 :   NaClDescImcDescFstat,  /* diff */
     374                 :   NaClDescGetdentsNotImplemented,
     375                 :   NACL_DESC_IMC_SOCKET,  /* diff */
     376                 :   NaClDescExternalizeSizeNotImplemented,
     377                 :   NaClDescExternalizeNotImplemented,
     378                 :   NaClDescLockNotImplemented,
     379                 :   NaClDescTryLockNotImplemented,
     380                 :   NaClDescUnlockNotImplemented,
     381                 :   NaClDescWaitNotImplemented,
     382                 :   NaClDescTimedWaitAbsNotImplemented,
     383                 :   NaClDescSignalNotImplemented,
     384                 :   NaClDescBroadcastNotImplemented,
     385                 :   NaClDescImcDescSendMsg,  /* diff */
     386                 :   NaClDescImcDescRecvMsg,  /* diff */
     387                 :   NaClDescConnectAddrNotImplemented,
     388                 :   NaClDescAcceptConnNotImplemented,
     389                 :   NaClDescPostNotImplemented,
     390                 :   NaClDescSemWaitNotImplemented,
     391                 :   NaClDescGetValueNotImplemented,
     392                 : };
     393                 : 
     394                 : 
     395                 : static struct NaClDescVtbl const kNaClDescXferableDataDescVtbl = {
     396                 :   {
     397                 :     NaClDescXferableDataDescDtor,  /* diff */
     398                 :   },
     399                 :   NaClDescMapNotImplemented,
     400                 :   NaClDescUnmapUnsafeNotImplemented,
     401                 :   NaClDescUnmapNotImplemented,
     402                 :   NaClDescReadNotImplemented,
     403                 :   NaClDescWriteNotImplemented,
     404                 :   NaClDescSeekNotImplemented,
     405                 :   NaClDescIoctlNotImplemented,
     406                 :   NaClDescXferableDataDescFstat,  /* diff */
     407                 :   NaClDescGetdentsNotImplemented,
     408                 :   NACL_DESC_TRANSFERABLE_DATA_SOCKET,  /* diff */
     409                 :   NaClDescXferableDataDescExternalizeSize,  /* diff */
     410                 :   NaClDescXferableDataDescExternalize,  /* diff */
     411                 :   NaClDescLockNotImplemented,
     412                 :   NaClDescTryLockNotImplemented,
     413                 :   NaClDescUnlockNotImplemented,
     414                 :   NaClDescWaitNotImplemented,
     415                 :   NaClDescTimedWaitAbsNotImplemented,
     416                 :   NaClDescSignalNotImplemented,
     417                 :   NaClDescBroadcastNotImplemented,
     418                 :   NaClDescXferableDataDescSendMsg,  /* diff */
     419                 :   NaClDescXferableDataDescRecvMsg,  /* diff */
     420                 :   NaClDescConnectAddrNotImplemented,
     421                 :   NaClDescAcceptConnNotImplemented,
     422                 :   NaClDescPostNotImplemented,
     423                 :   NaClDescSemWaitNotImplemented,
     424                 :   NaClDescGetValueNotImplemented,
     425                 : };
     426                 : 
     427                 : 
     428                 : int NaClDescXferableDataDescInternalize(
     429                 :     struct NaClDesc               **baseptr,
     430                 :     struct NaClDescXferState      *xfer,
     431               0 :     struct NaClDescQuotaInterface *quota_interface) {
     432                 :   int                             rv;
     433                 :   struct NaClDescXferableDataDesc *ndxdp;
     434                 : 
     435                 :   UNREFERENCED_PARAMETER(quota_interface);
     436               0 :   NaClLog(4, "Entered NaClDescXferableDataDescInternalize\n");
     437               0 :   rv = -NACL_ABI_EIO;
     438               0 :   ndxdp = NULL;
     439                 : 
     440               0 :   if (xfer->next_handle == xfer->handle_buffer_end) {
     441               0 :     NaClLog(LOG_ERROR,
     442                 :             ("NaClXferableDataDescInternalize: no descriptor"
     443                 :              " left in xfer state\n"));
     444               0 :     rv = -NACL_ABI_EIO;
     445               0 :     goto cleanup;
     446                 :   }
     447               0 :   ndxdp = malloc(sizeof *ndxdp);
     448               0 :   if (NULL == ndxdp) {
     449               0 :     NaClLog(LOG_ERROR,
     450                 :             "NaClXferableDataDescInternalize: no memory\n");
     451               0 :     rv = -NACL_ABI_ENOMEM;
     452               0 :     goto cleanup;
     453                 :   }
     454               0 :   if (!NaClDescXferableDataDescCtor(ndxdp,
     455                 :                                     *xfer->next_handle)) {
     456               0 :     NaClLog(LOG_ERROR,
     457                 :             "NaClXferableDataDescInternalize: descriptor ctor error\n");
     458               0 :     rv = -NACL_ABI_EIO;
     459               0 :     goto cleanup;
     460                 :   }
     461               0 :   *xfer->next_handle++ = NACL_INVALID_HANDLE;
     462               0 :   *baseptr = (struct NaClDesc *) ndxdp;
     463               0 :   rv = 0;
     464                 : 
     465               0 : cleanup:
     466               0 :   if (rv < 0) {
     467               0 :     free(ndxdp);
     468                 :   }
     469               0 :   return rv;
     470                 : }

Generated by: LCOV version 1.7