LCOV - code coverage report
Current view: directory - src/trusted/desc/posix - nacl_desc_conn_cap.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 155 117 75.5 %
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.  I/O Descriptor / Handle abstraction.
       9                 :  * Connection capabilities.
      10                 :  */
      11                 : 
      12                 : #include <assert.h>
      13                 : #include <errno.h>
      14                 : #include <poll.h>
      15                 : #include <stdlib.h>
      16                 : #include <string.h>
      17                 : #include <sys/socket.h>
      18                 : 
      19                 : #include "native_client/src/include/nacl_macros.h"
      20                 : #include "native_client/src/include/portability.h"
      21                 : 
      22                 : #include "native_client/src/shared/imc/nacl_imc_c.h"
      23                 : #include "native_client/src/shared/platform/nacl_check.h"
      24                 : #include "native_client/src/shared/platform/nacl_log.h"
      25                 : #include "native_client/src/trusted/desc/nacl_desc_base.h"
      26                 : #include "native_client/src/trusted/desc/nacl_desc_conn_cap.h"
      27                 : #include "native_client/src/trusted/desc/nacl_desc_imc.h"
      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                 : #include "native_client/src/trusted/service_runtime/nacl_config.h"
      31                 : 
      32                 : static struct NaClDescVtbl const kNaClDescConnCapFdVtbl;  /* fwd */
      33                 : 
      34             639 : static int NaClDescConnCapFdSubclassCtor(struct NaClDescConnCapFd  *self,
      35             639 :                                          NaClHandle                endpt) {
      36             639 :   struct NaClDesc *basep = (struct NaClDesc *) self;
      37                 : 
      38             639 :   self->connect_fd = endpt;
      39             639 :   basep->base.vtbl = (struct NaClRefCountVtbl const *) &kNaClDescConnCapFdVtbl;
      40             639 :   return 1;
      41                 : }
      42                 : 
      43             586 : int NaClDescConnCapFdCtor(struct NaClDescConnCapFd  *self,
      44             586 :                           NaClHandle                endpt) {
      45             586 :   struct NaClDesc *basep = (struct NaClDesc *) self;
      46             586 :   int rv;
      47                 : 
      48             586 :   basep->base.vtbl = (struct NaClRefCountVtbl const *) NULL;
      49             586 :   if (!NaClDescCtor(basep)) {
      50               0 :     return 0;
      51                 :   }
      52             586 :   rv = NaClDescConnCapFdSubclassCtor(self, endpt);
      53             586 :   if (!rv) {
      54               0 :     (*NACL_VTBL(NaClRefCount, basep)->Dtor)((struct NaClRefCount *) self);
      55               0 :   }
      56             586 :   return rv;
      57             586 : }
      58                 : 
      59              46 : static void NaClDescConnCapFdDtor(struct NaClRefCount *vself) {
      60              46 :   struct NaClDescConnCapFd *self = (struct NaClDescConnCapFd *) vself;
      61                 : 
      62              46 :   (void) NaClClose(self->connect_fd);
      63              46 :   self->connect_fd = NACL_INVALID_HANDLE;
      64              46 :   vself->vtbl = (struct NaClRefCountVtbl const *) &kNaClDescVtbl;
      65              46 :   (*vself->vtbl->Dtor)(vself);
      66              46 :   return;
      67                 : }
      68                 : 
      69               0 : static int NaClDescConnCapFdFstat(struct NaClDesc       *vself,
      70               0 :                                   struct nacl_abi_stat  *statbuf) {
      71               0 :   UNREFERENCED_PARAMETER(vself);
      72                 : 
      73               0 :   memset(statbuf, 0, sizeof *statbuf);
      74               0 :   statbuf->nacl_abi_st_mode = NACL_ABI_S_IFSOCKADDR | NACL_ABI_S_IRWXU;
      75               0 :   return 0;
      76                 : }
      77                 : 
      78              30 : static int NaClDescConnCapFdExternalizeSize(struct NaClDesc *vself,
      79              30 :                                             size_t          *nbytes,
      80              30 :                                             size_t          *nhandles) {
      81              30 :   int rv;
      82                 : 
      83              30 :   rv = NaClDescExternalizeSize(vself, nbytes, nhandles);
      84              30 :   if (0 != rv) {
      85               0 :     return rv;
      86                 :   }
      87                 : 
      88              30 :   *nhandles += 1;
      89              30 :   return 0;
      90              30 : }
      91                 : 
      92              30 : static int NaClDescConnCapFdExternalize(struct NaClDesc          *vself,
      93              30 :                                         struct NaClDescXferState *xfer) {
      94              30 :   struct NaClDescConnCapFd    *self;
      95              30 :   int rv;
      96                 : 
      97              30 :   rv = NaClDescExternalize(vself, xfer);
      98              30 :   if (0 != rv) {
      99               0 :     return rv;
     100                 :   }
     101              30 :   self = (struct NaClDescConnCapFd *) vself;
     102              30 :   *xfer->next_handle++ = self->connect_fd;
     103                 : 
     104              30 :   return 0;
     105              30 : }
     106                 : 
     107              60 : static int NaClDescConnCapFdConnectAddr(struct NaClDesc *vself,
     108              60 :                                         struct NaClDesc **out_desc) {
     109              60 :   struct NaClDescConnCapFd  *self = (struct NaClDescConnCapFd *) vself;
     110              60 :   NaClHandle                sock_pair[2];
     111              60 :   struct NaClDescImcDesc    *connected_socket;
     112              60 :   char                      control_buf[CMSG_SPACE_KHANDLE_COUNT_MAX_INTS];
     113              60 :   struct iovec              iovec;
     114              60 :   struct msghdr             connect_msg;
     115              60 :   struct cmsghdr            *cmsg;
     116              60 :   int                       sent;
     117              60 :   int                       retval;
     118                 : 
     119                 :   assert(CMSG_SPACE(sizeof(int)) <= CMSG_SPACE_KHANDLE_COUNT_MAX_INTS);
     120                 : 
     121              60 :   sock_pair[0] = NACL_INVALID_HANDLE;
     122              60 :   sock_pair[1] = NACL_INVALID_HANDLE;
     123              60 :   connected_socket = (struct NaClDescImcDesc *) NULL;
     124                 : 
     125              60 :   retval = -NACL_ABI_EINVAL;
     126                 : 
     127              60 :   if (0 != NaClSocketPair(sock_pair)) {
     128               0 :     retval = -NACL_ABI_EMFILE;
     129               0 :     goto cleanup;
     130                 :   }
     131                 : 
     132              60 :   iovec.iov_base = "c";
     133              60 :   iovec.iov_len = 1;
     134              60 :   connect_msg.msg_iov = &iovec;
     135              60 :   connect_msg.msg_iovlen = 1;
     136              60 :   connect_msg.msg_name = NULL;
     137              60 :   connect_msg.msg_namelen = 0;
     138              60 :   connect_msg.msg_control = control_buf;
     139              60 :   connect_msg.msg_controllen = sizeof(control_buf);
     140              60 :   connect_msg.msg_flags = 0;
     141                 : 
     142             180 :   cmsg = CMSG_FIRSTHDR(&connect_msg);
     143              60 :   cmsg->cmsg_len = CMSG_LEN(sizeof(int));
     144              60 :   cmsg->cmsg_level = SOL_SOCKET;
     145              60 :   cmsg->cmsg_type = SCM_RIGHTS;
     146                 :   /*
     147                 :    * We use memcpy() rather than assignment through a cast to avoid
     148                 :    * strict-aliasing warnings
     149                 :    */
     150             180 :   memcpy(CMSG_DATA(cmsg), &sock_pair[0], sizeof(int));
     151                 :   /* Set msg_controllen to the actual size of the cmsg. */
     152              60 :   connect_msg.msg_controllen = cmsg->cmsg_len;
     153                 : 
     154              60 :   sent = sendmsg(self->connect_fd, &connect_msg, 0);
     155              60 :   if (1 != sent) {
     156               1 :     retval = -NACL_ABI_EIO;
     157               1 :     goto cleanup;
     158                 :   }
     159                 : 
     160                 :   if (NACL_OSX) {
     161                 :     /*
     162                 :      * Mac OS X has a kernel bug in which a socket descriptor that is
     163                 :      * referenced only from the message queue of another socket can
     164                 :      * get garbage collected.  This causes the socket descriptor not
     165                 :      * to work properly.  To work around this, we don't close our
     166                 :      * reference to the socket until we receive an acknowledgement
     167                 :      * that it has been successfully received.
     168                 :      *
     169                 :      * We cannot receive the acknowledgement through self->connect_fd
     170                 :      * because this FD could be shared between multiple processes.  So
     171                 :      * we receive the acknowledgement through the socket pair that we
     172                 :      * have just created.
     173                 :      *
     174                 :      * However, this creates a risk that we are left hanging if the
     175                 :      * other process dies after our sendmsg() call, because we are
     176                 :      * holding on to the socket that it would use to send the ack.  To
     177                 :      * avoid this problem, we use poll() so that we will be notified
     178                 :      * if self->connect_fd becomes unwritable.
     179                 :      * TODO(mseaborn): Add a test case to simulate that scenario.
     180                 :      *
     181                 :      * See http://code.google.com/p/nativeclient/issues/detail?id=1796
     182                 :      *
     183                 :      * Note that we are relying on a corner case of poll() here.
     184                 :      * Using POLLHUP in "events" is not meaningful on Linux, which is
     185                 :      * documented as ignoring POLLHUP as an input argument and will
     186                 :      * return POLLHUP in "revents" even if it not present in "events".
     187                 :      * On Mac OS X, however, passing events == 0 does not work if we
     188                 :      * want to get POLLHUP.  We are in the unusual situation of
     189                 :      * waiting for a socket to become *un*writable.
     190                 :      */
     191              55 :     struct pollfd poll_fds[2];
     192              55 :     poll_fds[0].fd = self->connect_fd;
     193              55 :     poll_fds[0].events = POLLHUP;
     194              55 :     poll_fds[1].fd = sock_pair[1];
     195              55 :     poll_fds[1].events = POLLIN;
     196              55 :     if (poll(poll_fds, 2, -1) < 0) {
     197               0 :       NaClLog(LOG_ERROR,
     198               0 :               "NaClDescConnCapFdConnectAddr: poll() failed, errno %d\n", errno);
     199               0 :       retval = -NACL_ABI_EIO;
     200               0 :       goto cleanup;
     201                 :     }
     202                 :     /*
     203                 :      * It is not necessarily an error if POLLHUP fires on
     204                 :      * self->connect_fd: The other process could have done
     205                 :      * imc_accept(S) and then closed S.  This means it will have
     206                 :      * received sock_pair[0] successfully, so we can close our
     207                 :      * reference to sock_pair[0] and then receive the ack.
     208                 :      * TODO(mseaborn): Add a test case to cover this scenario.
     209                 :      */
     210                 :   }
     211                 : 
     212              55 :   (void) NaClClose(sock_pair[0]);
     213              55 :   sock_pair[0] = NACL_INVALID_HANDLE;
     214                 : 
     215                 :   if (NACL_OSX) {
     216                 :     /* Receive the acknowledgement.  We do not expect this to block. */
     217              55 :     char ack_buffer[1];
     218              55 :     ssize_t received = recv(sock_pair[1], ack_buffer, sizeof(ack_buffer), 0);
     219             110 :     if (received != 1 || ack_buffer[0] != 'a') {
     220               0 :       retval = -NACL_ABI_EIO;
     221               0 :       goto cleanup;
     222                 :     }
     223                 :   }
     224                 : 
     225              55 :   connected_socket = malloc(sizeof(*connected_socket));
     226              55 :   if (NULL == connected_socket ||
     227              55 :       !NaClDescImcDescCtor(connected_socket, sock_pair[1])) {
     228               0 :     retval = -NACL_ABI_ENOMEM;
     229               0 :     goto cleanup;
     230                 :   }
     231              55 :   sock_pair[1] = NACL_INVALID_HANDLE;
     232                 : 
     233              55 :   *out_desc = (struct NaClDesc *) connected_socket;
     234              55 :   connected_socket = NULL;
     235              55 :   retval = 0;
     236                 : 
     237                 : cleanup:
     238              56 :   NaClSafeCloseNaClHandle(sock_pair[0]);
     239              56 :   NaClSafeCloseNaClHandle(sock_pair[1]);
     240              56 :   free(connected_socket);
     241                 : 
     242              56 :   return retval;
     243                 : }
     244                 : 
     245               0 : static int NaClDescConnCapFdAcceptConn(struct NaClDesc  *vself,
     246               0 :                                        struct NaClDesc  **out_desc) {
     247               0 :   UNREFERENCED_PARAMETER(vself);
     248               0 :   UNREFERENCED_PARAMETER(out_desc);
     249                 : 
     250               0 :   NaClLog(LOG_ERROR, "NaClDescConnCapFdAcceptConn: not IMC\n");
     251               0 :   return -NACL_ABI_EINVAL;
     252                 : }
     253                 : 
     254                 : static struct NaClDescVtbl const kNaClDescConnCapFdVtbl = {
     255                 :   {
     256                 :     NaClDescConnCapFdDtor,
     257                 :   },
     258                 :   NaClDescMapNotImplemented,
     259                 :   NACL_DESC_UNMAP_NOT_IMPLEMENTED
     260                 :   NaClDescReadNotImplemented,
     261                 :   NaClDescWriteNotImplemented,
     262                 :   NaClDescSeekNotImplemented,
     263                 :   NaClDescPReadNotImplemented,
     264                 :   NaClDescPWriteNotImplemented,
     265                 :   NaClDescConnCapFdFstat,
     266                 :   NaClDescGetdentsNotImplemented,
     267                 :   NaClDescConnCapFdExternalizeSize,
     268                 :   NaClDescConnCapFdExternalize,
     269                 :   NaClDescLockNotImplemented,
     270                 :   NaClDescTryLockNotImplemented,
     271                 :   NaClDescUnlockNotImplemented,
     272                 :   NaClDescWaitNotImplemented,
     273                 :   NaClDescTimedWaitAbsNotImplemented,
     274                 :   NaClDescSignalNotImplemented,
     275                 :   NaClDescBroadcastNotImplemented,
     276                 :   NaClDescSendMsgNotImplemented,
     277                 :   NaClDescRecvMsgNotImplemented,
     278                 :   NaClDescLowLevelSendMsgNotImplemented,
     279                 :   NaClDescLowLevelRecvMsgNotImplemented,
     280                 :   NaClDescConnCapFdConnectAddr,
     281                 :   NaClDescConnCapFdAcceptConn,
     282                 :   NaClDescPostNotImplemented,
     283                 :   NaClDescSemWaitNotImplemented,
     284                 :   NaClDescGetValueNotImplemented,
     285                 :   NaClDescSetMetadata,
     286                 :   NaClDescGetMetadata,
     287                 :   NaClDescSetFlags,
     288                 :   NaClDescGetFlags,
     289                 :   NaClDescIsattyNotImplemented,
     290                 :   NACL_DESC_CONN_CAP_FD,
     291                 : };
     292                 : 
     293                 : int NaClDescConnCapFdInternalize(
     294              53 :     struct NaClDesc               **out_desc,
     295              53 :     struct NaClDescXferState      *xfer,
     296              53 :     struct NaClDescQuotaInterface *quota_interface) {
     297              53 :   struct NaClDescConnCapFd *conn_cap;
     298              53 :   int rv;
     299                 : 
     300             106 :   UNREFERENCED_PARAMETER(quota_interface);
     301              53 :   conn_cap = malloc(sizeof(*conn_cap));
     302              53 :   if (NULL == conn_cap) {
     303               0 :     return -NACL_ABI_ENOMEM;
     304                 :   }
     305              53 :   if (!NaClDescInternalizeCtor(&conn_cap->base, xfer)) {
     306               0 :     free(conn_cap);
     307               0 :     conn_cap = NULL;
     308               0 :     rv = -NACL_ABI_ENOMEM;
     309               0 :     goto cleanup;
     310                 :   }
     311              53 :   if (xfer->next_handle == xfer->handle_buffer_end) {
     312               0 :     rv = -NACL_ABI_EIO;
     313               0 :     goto cleanup;
     314                 :   }
     315              53 :   rv = NaClDescConnCapFdSubclassCtor(conn_cap, *xfer->next_handle);
     316              53 :   if (!rv) {
     317               0 :     rv = -NACL_ABI_ENOMEM;
     318               0 :     goto cleanup;
     319                 :   }
     320              53 :   *xfer->next_handle++ = NACL_INVALID_HANDLE;
     321              53 :   *out_desc = &conn_cap->base;
     322              53 :   rv = 0;
     323                 :  cleanup:
     324              53 :   if (rv < 0) {
     325               0 :     NaClDescSafeUnref((struct NaClDesc *) conn_cap);
     326               0 :   }
     327              53 :   return rv;
     328              53 : }

Generated by: LCOV version 1.7