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

       1                 : /*
       2                 :  * Copyright (c) 2011 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                 :  * Native Client Resource Descriptor Transfer protocol for trusted code.
       9                 :  */
      10                 : 
      11                 : #include <sys/types.h>
      12                 : #include <sys/stat.h>
      13                 : #include <fcntl.h>
      14                 : #include <string.h>
      15                 : 
      16                 : #include "native_client/src/include/portability.h"
      17                 : #include "native_client/src/include/nacl_macros.h"
      18                 : 
      19                 : #include "native_client/src/trusted/desc/nacl_desc_base.h"
      20                 : #include "native_client/src/trusted/desc/nacl_desc_cond.h"
      21                 : #include "native_client/src/trusted/desc/nacl_desc_conn_cap.h"
      22                 : #include "native_client/src/trusted/desc/nacl_desc_effector.h"
      23                 : #include "native_client/src/trusted/desc/nacl_desc_io.h"
      24                 : #include "native_client/src/trusted/desc/nacl_desc_imc.h"
      25                 : #include "native_client/src/trusted/desc/nacl_desc_imc_bound_desc.h"
      26                 : #include "native_client/src/trusted/desc/nacl_desc_imc_shm.h"
      27                 : #include "native_client/src/trusted/desc/nacl_desc_mutex.h"
      28                 : #include "native_client/src/trusted/desc/nacl_desc_dir.h"
      29                 : #include "native_client/src/trusted/desc/nrd_xfer.h"
      30                 : #include "native_client/src/trusted/desc/nrd_xfer_intern.h"
      31                 : 
      32                 : #include "native_client/src/shared/platform/nacl_global_secure_random.h"
      33                 : #include "native_client/src/shared/platform/nacl_log.h"
      34                 : 
      35                 : #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
      36                 : #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
      37                 : #include "native_client/src/trusted/service_runtime/include/sys/nacl_imc_api.h"
      38                 : #include "native_client/src/trusted/service_runtime/include/sys/stat.h"
      39                 : 
      40                 : 
      41                 : /*
      42                 :  * The NRD xfer header that describes the types of NRDs being
      43                 :  * transferred should be rounded to a multiple of 16 bytes in length.
      44                 :  * This allows fast, SSE-based memcpy routines to work, giving us
      45                 :  * 16-bytes-per-cycle memory copies for in-cache data.
      46                 :  */
      47                 : 
      48                 : static INLINE nacl_abi_size_t min_abi_size(nacl_abi_size_t  a,
      49               0 :                                            nacl_abi_size_t  b) {
      50               0 :   if (a < b) return a;
      51               0 :   return b;
      52                 : }
      53                 : 
      54                 : static INLINE size_t min_size(size_t  a,
      55           38309 :                               size_t  b) {
      56           38309 :   if (a < b) return a;
      57           17653 :   return b;
      58                 : }
      59                 : 
      60                 : void NaClNrdXferIncrTagOverhead(size_t *byte_count,
      61               0 :                                 size_t *handle_count) {
      62                 :   UNREFERENCED_PARAMETER(handle_count);
      63               0 :   ++*byte_count;
      64               0 : }
      65                 : 
      66            2109 : enum NaClDescTypeTag NaClNrdXferReadTypeTag(struct NaClDescXferState *xferp) {
      67            2109 :   return (enum NaClDescTypeTag) (0xff & *xferp->next_byte++);
      68                 : }
      69                 : 
      70                 : void NaClNrdXferWriteTypeTag(struct NaClDescXferState *xferp,
      71            1084 :                              struct NaClDesc          *descp) {
      72            1084 :   *xferp->next_byte++ = NACL_VTBL(NaClDesc, descp)->typeTag;
      73            1084 : }
      74                 : 
      75                 : /*
      76                 :  * Returns number of descriptors internalized, or an error code.
      77                 :  * Since only one descriptor can be internalized (out parameter is not
      78                 :  * an array), this means 0 or 1 are non-error conditions.
      79                 :  *
      80                 :  * Returns negative errno (syscall-style) on error.
      81                 :  */
      82                 : int NaClDescInternalizeFromXferBuffer(
      83                 :     struct NaClDesc               **out_desc,
      84                 :     struct NaClDescXferState      *xferp,
      85            2109 :     struct NaClDescQuotaInterface *quota_interface) {
      86                 :   int xfer_status;
      87                 :   size_t type_tag;
      88                 : 
      89            2109 :   type_tag = NaClNrdXferReadTypeTag(xferp);
      90                 :   /* 0 <= type_tag */
      91            2109 :   if (NACL_DESC_TYPE_END_TAG == type_tag) {
      92            1023 :     return 0;
      93                 :   }
      94            1086 :   if (type_tag >= NACL_DESC_TYPE_MAX) {
      95               0 :     NaClLog(4, ("illegal type tag %"NACL_PRIdS" (0x%"NACL_PRIxS")\n"),
      96                 :             type_tag, type_tag);
      97               0 :     return -NACL_ABI_EIO;
      98                 :   }
      99            1086 :   if ((int (*)(struct NaClDesc **, struct NaClDescXferState *,
     100                 :                struct NaClDescQuotaInterface *)) NULL ==
     101                 :       NaClDescInternalize[type_tag]) {
     102               0 :     NaClLog(LOG_FATAL,
     103                 :             "No internalization function for type %"NACL_PRIdS"\n",
     104                 :             type_tag);
     105                 :     /* fatal, but in case we change it later */
     106               0 :     return -NACL_ABI_EIO;
     107                 :   }
     108            1086 :   xfer_status = (*NaClDescInternalize[type_tag])(out_desc, xferp,
     109                 :                                                  quota_interface);
     110                 :   /* constructs new_desc, transferring ownership of any handles consumed */
     111                 : 
     112            1086 :   if (xfer_status != 0) {
     113               0 :     NaClLog(0,
     114                 :             "non-zero xfer_status %d, desc type tag %s (%"NACL_PRIdS")\n",
     115                 :             xfer_status,
     116                 :             NaClDescTypeString(type_tag),
     117                 :             type_tag);
     118                 :   }
     119            1086 :   return 0 == xfer_status;
     120                 : }
     121                 : 
     122                 : int NaClDescExternalizeToXferBuffer(struct NaClDescXferState  *xferp,
     123            1084 :                                     struct NaClDesc           *out) {
     124                 :   /*
     125                 :    * Externalize should expose the object as NaClHandles that must
     126                 :    * be sent, but no ownership is transferred.  The NaClHandle
     127                 :    * objects cannot be deallocated until after the actual SendMsg
     128                 :    * completes, so multithreaded code beware!  By using
     129                 :    * NaClDescRef and NaClDescUnref properly, there shouldn't be
     130                 :    * any problems, since all entries in the ndescv should have had
     131                 :    * their refcount incremented, and the NaClHandles will not be
     132                 :    * closed until the NaClDesc objects' refcount goes to zero.
     133                 :    */
     134            1084 :   NaClNrdXferWriteTypeTag(xferp, out);
     135            1084 :   return (*NACL_VTBL(NaClDesc, out)->Externalize)(out, xferp);
     136                 : }
     137                 : 
     138                 : ssize_t NaClImcSendTypedMessage(struct NaClDesc                 *channel,
     139                 :                                 const struct NaClImcTypedMsgHdr *nitmhp,
     140            9327 :                                 int                              flags) {
     141                 :   int                       supported_flags;
     142            9327 :   ssize_t                   retval = -NACL_ABI_EINVAL;
     143                 :   struct NaClMessageHeader  kern_msg_hdr;  /* xlated interface */
     144                 :   size_t                    i;
     145                 :   /*
     146                 :    * BEWARE: NaClImcMsgIoVec has the same layout as NaClIOVec, so
     147                 :    * there will be type punning below to avoid copying from a struct
     148                 :    * NaClImcMsgIoVec array to a struct NaClIOVec array in order to
     149                 :    * call the IMC library code using kern_msg_hdr.
     150                 :    */
     151                 :   struct NaClImcMsgIoVec    kern_iov[NACL_ABI_IMC_IOVEC_MAX + 1];
     152                 :   struct NaClDesc           **kern_desc;
     153                 :   NaClHandle                kern_handle[NACL_ABI_IMC_DESC_MAX];
     154                 :   size_t                    user_bytes;
     155                 :   size_t                    sys_bytes;
     156                 :   size_t                    sys_handles;
     157                 :   size_t                    desc_bytes;
     158                 :   size_t                    desc_handles;
     159                 :   struct NaClInternalHeader *hdr;
     160                 :   char                      *hdr_buf;
     161                 :   struct NaClDescXferState  xfer_state;
     162                 : 
     163                 :   static struct NaClInternalHeader const kNoHandles = {
     164                 :     { NACL_HANDLE_TRANSFER_PROTOCOL, 0, },
     165                 :     /* and implicit zeros for pad bytes */
     166                 :   };
     167                 : 
     168            9327 :   NaClLog(3,
     169                 :           ("Entered"
     170                 :            " NaClImcSendTypedMessage(0x%08"NACL_PRIxPTR", "
     171                 :            "0x%08"NACL_PRIxPTR", 0x%x)\n"),
     172                 :           (uintptr_t) channel, (uintptr_t) nitmhp, flags);
     173                 :   /*
     174                 :    * What flags do we know now?  If a program was compiled using a
     175                 :    * newer ABI than what this implementation knows, the extra flag
     176                 :    * bits are ignored but will generate a warning.
     177                 :    */
     178            9327 :   supported_flags = NACL_ABI_IMC_NONBLOCK;
     179            9327 :   if (0 != (flags & ~supported_flags)) {
     180               0 :     NaClLog(LOG_WARNING,
     181                 :             "WARNING: NaClImcSendTypedMessage: unknown IMC flag used: 0x%x\n",
     182                 :             flags);
     183               0 :     flags &= supported_flags;
     184                 :   }
     185                 : 
     186                 :   /*
     187                 :    * use (ahem) RTTI -- or a virtual function that's been partially
     188                 :    * evaluated/memoized -- to short circuit the error check, so that
     189                 :    * cleanups are easier (rather than letting it fail at the
     190                 :    * ExternalizeSize virtual function call).
     191                 :    */
     192            9327 :   if (0 != nitmhp->ndesc_length
     193                 :       && NACL_DESC_IMC_SOCKET != NACL_VTBL(NaClDesc, channel)->typeTag) {
     194               0 :     NaClLog(4, "not an IMC socket and trying to send descriptors!\n");
     195               0 :     return -NACL_ABI_EINVAL;
     196                 :   }
     197                 : 
     198            9327 :   if (nitmhp->iov_length > NACL_ABI_IMC_IOVEC_MAX) {
     199               0 :     NaClLog(4, "gather/scatter array too large\n");
     200               0 :     return -NACL_ABI_EINVAL;
     201                 :   }
     202            9327 :   if (nitmhp->ndesc_length > NACL_ABI_IMC_USER_DESC_MAX) {
     203               0 :     NaClLog(4, "handle vector too long\n");
     204               0 :     return -NACL_ABI_EINVAL;
     205                 :   }
     206                 : 
     207            9327 :   memcpy(kern_iov + 1, (void *) nitmhp->iov,
     208                 :          nitmhp->iov_length * sizeof *nitmhp->iov);
     209                 :   /*
     210                 :    * kern_iov[0] is the message header that tells the recipient where
     211                 :    * the user data and capabilities data (e.g., NaClDescConnCap)
     212                 :    * boundary is, as well as types of objects in the handles vector of
     213                 :    * NaClHandle objects, which must be internalized.
     214                 :    *
     215                 :    * NB: we assume that communication is secure, and no external
     216                 :    * entity can listen in or will inject bogus information.  This is a
     217                 :    * strong assumption, since falsification can cause loss of
     218                 :    * type-safety.
     219                 :    */
     220            9327 :   user_bytes = 0;
     221           29625 :   for (i = 0; i < nitmhp->iov_length; ++i) {
     222           20298 :     if (user_bytes > SIZE_T_MAX - kern_iov[i+1].length) {
     223               0 :       return -NACL_ABI_EINVAL;
     224                 :     }
     225           20298 :     user_bytes += kern_iov[i+1].length;
     226                 :   }
     227            9327 :   if (user_bytes > NACL_ABI_IMC_USER_BYTES_MAX) {
     228               0 :     return -NACL_ABI_EINVAL;
     229                 :   }
     230                 : 
     231            9327 :   kern_desc = nitmhp->ndescv;
     232            9327 :   hdr_buf = NULL;
     233                 : 
     234                 :   /*
     235                 :    * NOTE: type punning w/ NaclImcMsgIoVec and NaClIOVec.
     236                 :    * This breaks ansi type aliasing rules and hence we may use
     237                 :    * soemthing like '-fno-strict-aliasing'
     238                 :    */
     239            9327 :   kern_msg_hdr.iov = (struct NaClIOVec *) kern_iov;
     240            9327 :   kern_msg_hdr.iov_length = nitmhp->iov_length + 1;  /* header */
     241                 : 
     242            9327 :   if (0 == nitmhp->ndesc_length) {
     243            8306 :     kern_msg_hdr.handles = NULL;
     244            8306 :     kern_msg_hdr.handle_count = 0;
     245            8306 :     kern_iov[0].base = (void *) &kNoHandles;
     246            8306 :     kern_iov[0].length = sizeof kNoHandles;
     247                 :   } else {
     248                 :     /*
     249                 :      * \forall i \in [0, nitmhp->desc_length): kern_desc[i] != NULL.
     250                 :      */
     251                 : 
     252            1021 :     sys_bytes = 0;
     253            1021 :     sys_handles = 0;
     254                 :     /* nitmhp->desc_length <= NACL_ABI_IMC_USER_DESC_MAX */
     255            2105 :     for (i = 0; i < nitmhp->ndesc_length; ++i) {
     256            1084 :       desc_bytes = 0;
     257            1084 :       desc_handles = 0;
     258            1084 :       retval = (*((struct NaClDescVtbl const *) kern_desc[i]->base.vtbl)->
     259                 :                 ExternalizeSize)(kern_desc[i],
     260                 :                                  &desc_bytes,
     261                 :                                  &desc_handles);
     262            1084 :       if (retval < 0) {
     263               0 :         NaClLog(1,
     264                 :                 ("NaClImcSendTypedMessage: ExternalizeSize"
     265                 :                  " returned %"NACL_PRIdS"\n"),
     266                 :                 retval);
     267               0 :         goto cleanup;
     268                 :       }
     269                 :       /*
     270                 :        * No integer overflow should be possible given the max-handles
     271                 :        * limits and actual resource use per handle involved.
     272                 :        */
     273            1084 :       if (desc_bytes > NACL_ABI_SIZE_T_MAX - 1
     274                 :           || (desc_bytes + 1) > NACL_ABI_SIZE_T_MAX - sys_bytes
     275                 :           || desc_handles > NACL_ABI_SIZE_T_MAX - sys_handles) {
     276               0 :         retval = -NACL_ABI_EOVERFLOW;
     277               0 :         goto cleanup;
     278                 :       }
     279            1084 :       sys_bytes += (1 + desc_bytes);
     280            1084 :       sys_handles += desc_handles;
     281                 :     }
     282            1021 :     if (sys_handles > NACL_ABI_IMC_DESC_MAX) {
     283               0 :       NaClLog(LOG_FATAL, ("User had %"NACL_PRIdNACL_SIZE" descriptors,"
     284                 :                           " which expanded into %"NACL_PRIdS
     285                 :                           "handles, more than"
     286                 :                           " the max of %d.\n"),
     287                 :               nitmhp->ndesc_length, sys_handles,
     288                 :               NACL_ABI_IMC_DESC_MAX);
     289                 :     }
     290                 :     /* a byte for NACL_DESC_TYPE_END_TAG, then rounded up to 0 mod 16 */
     291            1021 :     sys_bytes = (sys_bytes + 1 + 0xf) & ~0xf;
     292                 : 
     293                 :     /* bsy notes that sys_bytes should never exceed NACL_ABI_IMC_DESC_MAX
     294                 :      * times the maximum protocol transfer size, which is currently set to
     295                 :      * NACL_PATH_MAX, so it would be abnormal for this check to fail.
     296                 :      * Including it anyway just in case something changes.
     297                 :      */
     298            1021 :     if (sys_bytes > NACL_ABI_SIZE_T_MAX - sizeof *hdr) {
     299               0 :       NaClLog(LOG_FATAL, "NaClImcSendTypedMessage: "
     300                 :               "Buffer size overflow (%"NACL_PRIdS" bytes)",
     301                 :               sys_bytes);
     302               0 :       retval = -NACL_ABI_EOVERFLOW;
     303               0 :       goto cleanup;
     304                 :     }
     305            1021 :     hdr_buf = malloc(sys_bytes + sizeof *hdr);
     306            1021 :     if (NULL == hdr_buf) {
     307               0 :       NaClLog(4, "NaClImcSendTypedMessage: out of memory for iov");
     308               0 :       retval = -NACL_ABI_ENOMEM;
     309               0 :       goto cleanup;
     310                 :     }
     311            1021 :     kern_iov[0].base = (void *) hdr_buf;
     312                 : 
     313                 :     /* Checked above that sys_bytes <= NACL_ABI_SIZE_T_MAX - sizeof *hdr */
     314            1021 :     kern_iov[0].length = (nacl_abi_size_t)(sys_bytes + sizeof *hdr);
     315                 : 
     316            1021 :     hdr = (struct NaClInternalHeader *) hdr_buf;
     317            1021 :     memset(hdr, 0, sizeof(*hdr));  /* Initilize the struct's padding bytes. */
     318            1021 :     hdr->h.xfer_protocol_version = NACL_HANDLE_TRANSFER_PROTOCOL;
     319                 :     if (sys_bytes > UINT32_MAX) {
     320                 :       /*
     321                 :        * We really want:
     322                 :        * sys_bytes > numeric_limits<typeof(hdr->h.descriptor_data_bytes)>:max()
     323                 :        * in case the type changes.
     324                 :        *
     325                 :        * This should never occur in practice, since
     326                 :        * NACL_ABI_IMC_DESC_MAX * NACL_PATH_MAX is far smaller than
     327                 :        * UINT32_MAX.  Furthermore, NACL_ABI_IMC_DESC_MAX *
     328                 :        * NACL_PATH_MAX + user_bytes <= NACL_ABI_IMC_DESC_MAX *
     329                 :        * NACL_PATH_MAX + NACL_ABI_IMC_USER_BYTES_MAX == max_xfer (so
     330                 :        * max_xfer is upper bound on data transferred), and max_xfer <=
     331                 :        * INT32_MAX = NACL_ABI_SSIZE_MAX <= SSIZE_T_MAX holds.
     332                 :        */
     333                 :       retval = -NACL_ABI_EOVERFLOW;
     334                 :       goto cleanup;
     335                 :     }
     336            1021 :     hdr->h.descriptor_data_bytes = (uint32_t) sys_bytes;
     337                 : 
     338            1021 :     xfer_state.next_byte = (char *) (hdr + 1);
     339            1021 :     xfer_state.byte_buffer_end = xfer_state.next_byte + sys_bytes;
     340            1021 :     xfer_state.next_handle = kern_handle;
     341            1021 :     xfer_state.handle_buffer_end = xfer_state.next_handle
     342                 :         + NACL_ABI_IMC_DESC_MAX;
     343                 : 
     344            2105 :     for (i = 0; i < nitmhp->ndesc_length; ++i) {
     345            1084 :       retval = NaClDescExternalizeToXferBuffer(&xfer_state, kern_desc[i]);
     346            1084 :       if (0 != retval) {
     347               0 :         NaClLog(4,
     348                 :                 ("NaClImcSendTypedMessage: Externalize for"
     349                 :                  " descriptor %"NACL_PRIdS" returned %"NACL_PRIdS"\n"),
     350                 :                 i, retval);
     351               0 :         goto cleanup;
     352                 :       }
     353                 :     }
     354            1021 :     *xfer_state.next_byte++ = (char) NACL_DESC_TYPE_END_TAG;
     355                 :     /*
     356                 :      * zero fill the rest of memory to avoid leaking info from
     357                 :      * otherwise uninitialized malloc'd memory.
     358                 :      */
     359           16273 :     while (xfer_state.next_byte < xfer_state.byte_buffer_end) {
     360           14231 :       *xfer_state.next_byte++ = '\0';
     361                 :     }
     362                 : 
     363            1021 :     kern_msg_hdr.handles = kern_handle;
     364            1021 :     kern_msg_hdr.handle_count = sys_handles;
     365                 :   }
     366                 : 
     367            9327 :   NaClLog(4, "Invoking SendMsg, flags 0x%x\n", flags);
     368                 : 
     369            9327 :   retval = (*((struct NaClDescVtbl const *) channel->base.vtbl)->
     370                 :             SendMsg)(channel, &kern_msg_hdr, flags);
     371            9327 :   NaClLog(4, "SendMsg returned %"NACL_PRIdS"\n", retval);
     372            9327 :   if (NaClSSizeIsNegErrno(&retval)) {
     373                 :     /*
     374                 :      * NaClWouldBlock uses TSD (for both the errno-based and
     375                 :      * GetLastError()-based implementations), so this is threadsafe.
     376                 :      */
     377               0 :     if (0 != (flags & NACL_DONT_WAIT) && NaClWouldBlock()) {
     378               0 :       retval = -NACL_ABI_EAGAIN;
     379               0 :     } else if (-NACL_ABI_EMSGSIZE == retval) {
     380                 :       /*
     381                 :        * Allow the above layer to process when imc_sendmsg calls fail due
     382                 :        * to the OS not supporting a large enough buffer.
     383                 :        */
     384               0 :       retval = -NACL_ABI_EMSGSIZE;
     385                 :     } else {
     386                 :       /*
     387                 :        * TODO(bsy): the else case is some mysterious internal error.
     388                 :        * should we destroy the channel?  Was the failure atomic?  Did
     389                 :        * it send some partial data?  Linux implementation appears
     390                 :        * okay.
     391                 :        *
     392                 :        * We return EIO and let the caller deal with it.
     393                 :        */
     394               0 :       retval = -NACL_ABI_EIO;
     395                 :     }
     396            9327 :   } else if ((unsigned) retval < kern_iov[0].length) {
     397                 :     /*
     398                 :      * retval >= 0, so cast to unsigned is value preserving.
     399                 :      */
     400               0 :     retval = -NACL_ABI_ENOBUFS;
     401                 :   } else {
     402                 :     /*
     403                 :      * The return value (number of bytes sent) should not include the
     404                 :      * "out of band" additional information added by the service runtime.
     405                 :      */
     406            9327 :     retval -= kern_iov[0].length;
     407                 :   }
     408                 : 
     409            9327 : cleanup:
     410                 : 
     411            9327 :   free(hdr_buf);
     412                 : 
     413            9327 :   NaClLog(4, "NaClImcSendTypedMessage: returning %"NACL_PRIdS"\n", retval);
     414                 : 
     415            9327 :   return retval;
     416                 : }
     417                 : 
     418                 : 
     419                 : ssize_t NaClImcRecvTypedMessage(
     420                 :     struct NaClDesc               *channel,
     421                 :     struct NaClImcTypedMsgHdr     *nitmhp,
     422                 :     int                           flags,
     423            9346 :     struct NaClDescQuotaInterface *quota_interface) {
     424                 :   int                       supported_flags;
     425                 :   ssize_t                   retval;
     426                 :   char                      *recv_buf;
     427                 :   size_t                    user_bytes;
     428                 :   NaClHandle                kern_handle[NACL_ABI_IMC_DESC_MAX];
     429                 :   struct NaClIOVec          recv_iov;
     430                 :   struct NaClMessageHeader  recv_hdr;
     431                 :   ssize_t                   total_recv_bytes;
     432                 :   struct NaClInternalHeader intern_hdr;
     433                 :   size_t                    recv_user_bytes_avail;
     434                 :   size_t                    tmp;
     435                 :   char                      *user_data;
     436                 :   size_t                    iov_copy_size;
     437                 :   struct NaClDescXferState  xfer;
     438                 :   struct NaClDesc           *new_desc[NACL_ABI_IMC_DESC_MAX];
     439                 :   int                       xfer_status;
     440                 :   size_t                    i;
     441                 :   size_t                    num_user_desc;
     442                 : 
     443            9346 :   NaClLog(4,
     444                 :           "Entered NaClImcRecvTypedMsg(0x%08"NACL_PRIxPTR", "
     445                 :           "0x%08"NACL_PRIxPTR", %d)\n",
     446                 :           (uintptr_t) channel, (uintptr_t) nitmhp, flags);
     447                 : 
     448            9346 :   supported_flags = NACL_ABI_IMC_NONBLOCK;
     449            9346 :   if (0 != (flags & ~supported_flags)) {
     450               0 :     NaClLog(LOG_WARNING,
     451                 :             "WARNING: NaClImcRecvTypedMsg: unknown IMC flag used: 0x%x\n",
     452                 :             flags);
     453               0 :     flags &= supported_flags;
     454                 :   }
     455                 : 
     456            9346 :   if (nitmhp->iov_length > NACL_ABI_IMC_IOVEC_MAX) {
     457               0 :     NaClLog(4, "gather/scatter array too large\n");
     458               0 :     return -NACL_ABI_EINVAL;
     459                 :   }
     460            9346 :   if (nitmhp->ndesc_length > NACL_ABI_IMC_USER_DESC_MAX) {
     461               0 :     NaClLog(4, "handle vector too long\n");
     462               0 :     return -NACL_ABI_EINVAL;
     463                 :   }
     464                 : 
     465            9346 :   user_bytes = 0;
     466           29182 :   for (i = 0; i < nitmhp->iov_length; ++i) {
     467           19836 :     if (user_bytes > SIZE_T_MAX - nitmhp->iov[i].length) {
     468               0 :       NaClLog(4, "integer overflow in iov length summation\n");
     469               0 :       return -NACL_ABI_EINVAL;
     470                 :     }
     471           19836 :     user_bytes += nitmhp->iov[i].length;
     472                 :   }
     473                 :   /*
     474                 :    * if user_bytes > NACL_ABI_IMC_USER_BYTES_MAX,
     475                 :    * we will just never fill up all the buffer space.
     476                 :    */
     477            9346 :   user_bytes = min_size(user_bytes, NACL_ABI_IMC_USER_BYTES_MAX);
     478                 :   /*
     479                 :    * user_bytes = \min(\sum_{i=0}{nitmhp->iov_length-1} nitmhp->iov[i].length,
     480                 :    *                   NACL_ABI_IMC_USER_BYTES_MAX)
     481                 :    */
     482                 : 
     483            9346 :   recv_buf = NULL;
     484            9346 :   memset(new_desc, 0, sizeof new_desc);
     485                 :   /*
     486                 :    * from here on, set retval and jump to cleanup code.
     487                 :    */
     488                 : 
     489            9346 :   recv_buf = malloc(NACL_ABI_IMC_BYTES_MAX);
     490            9346 :   if (NULL == recv_buf) {
     491               0 :     NaClLog(4, "no memory for receive buffer\n");
     492               0 :     retval = -NACL_ABI_ENOMEM;
     493               0 :     goto cleanup;
     494                 :   }
     495                 : 
     496            9346 :   recv_iov.base = (void *) recv_buf;
     497            9346 :   recv_iov.length = NACL_ABI_IMC_BYTES_MAX;
     498                 : 
     499            9346 :   recv_hdr.iov = &recv_iov;
     500            9346 :   recv_hdr.iov_length = 1;
     501                 : 
     502           84114 :   for (i = 0; i < NACL_ARRAY_SIZE(kern_handle); ++i) {
     503           74768 :     kern_handle[i] = NACL_INVALID_HANDLE;
     504                 :   }
     505                 : 
     506            9346 :   if (NACL_DESC_IMC_SOCKET == ((struct NaClDescVtbl const *)
     507                 :                                channel->base.vtbl)->typeTag) {
     508                 :     /*
     509                 :      * Channel can transfer access rights.
     510                 :      */
     511                 : 
     512            9346 :     recv_hdr.handles = kern_handle;
     513            9346 :     recv_hdr.handle_count = NACL_ARRAY_SIZE(kern_handle);
     514            9346 :     NaClLog(4, "Connected socket, may transfer descriptors\n");
     515                 :   } else {
     516                 :     /*
     517                 :      * Channel cannot transfer access rights.  The syscall would fail
     518                 :      * if recv_iov.length is non-zero.
     519                 :      */
     520                 : 
     521               0 :     recv_hdr.handles = (NaClHandle *) NULL;
     522               0 :     recv_hdr.handle_count = 0;
     523               0 :     NaClLog(4, "Transferable Data Only socket\n");
     524                 :   }
     525                 : 
     526            9346 :   recv_hdr.flags = 0;  /* just to make it obvious; IMC will clear it for us */
     527                 : 
     528            9346 :   total_recv_bytes = (*((struct NaClDescVtbl const *) channel->base.vtbl)->
     529                 :                       RecvMsg)(channel,
     530                 :                                &recv_hdr,
     531                 :                                flags);
     532            9346 :   if (NaClSSizeIsNegErrno(&total_recv_bytes)) {
     533               0 :     NaClLog(1, "RecvMsg failed, returned %"NACL_PRIdS"\n", total_recv_bytes);
     534               0 :     retval = total_recv_bytes;
     535               0 :     goto cleanup;
     536                 :   }
     537                 :   /* total_recv_bytes >= 0 */
     538                 : 
     539                 :   /*
     540                 :    * NB: recv_hdr.flags may already contain NACL_ABI_MESSAGE_TRUNCATED
     541                 :    * and/or NACL_ABI_HANDLES_TRUNCATED.
     542                 :    *
     543                 :    * First, parse the NaClInternalHeader and any subsequent fields to
     544                 :    * extract and internalize the NaClDesc objects from the array of
     545                 :    * NaClHandle values.
     546                 :    *
     547                 :    * Copy out to user buffer.  Possibly additional truncation may occur.
     548                 :    *
     549                 :    * Since total_recv_bytes >= 0, the cast to size_t is value preserving.
     550                 :    */
     551            9346 :   if ((size_t) total_recv_bytes < sizeof intern_hdr) {
     552               8 :     NaClLog(4, ("only received %"NACL_PRIdS" (0x%"NACL_PRIxS") bytes,"
     553                 :                 " but internal header is %"NACL_PRIdS" (0x%"NACL_PRIxS
     554                 :                 ") bytes\n"),
     555                 :             total_recv_bytes, total_recv_bytes,
     556                 :             sizeof intern_hdr, sizeof intern_hdr);
     557               8 :     retval = -NACL_ABI_EIO;
     558               8 :     goto cleanup;
     559                 :   }
     560            9338 :   memcpy(&intern_hdr, recv_buf, sizeof intern_hdr);
     561                 :   /*
     562                 :    * Future code should handle old versions in a backward compatible way.
     563                 :    */
     564            9338 :   if (NACL_HANDLE_TRANSFER_PROTOCOL != intern_hdr.h.xfer_protocol_version) {
     565               0 :     NaClLog(4, ("protocol version mismatch:"
     566                 :                 " got %x, but can only handle %x\n"),
     567                 :             intern_hdr.h.xfer_protocol_version, NACL_HANDLE_TRANSFER_PROTOCOL);
     568                 :     /*
     569                 :      * The returned value should be a special version mismatch error
     570                 :      * code that, along with the recv_buf, permit retrying with later
     571                 :      * decoders.
     572                 :      */
     573               0 :     retval = -NACL_ABI_EIO;
     574               0 :     goto cleanup;
     575                 :   }
     576            9338 :   if ((size_t) total_recv_bytes < (intern_hdr.h.descriptor_data_bytes
     577                 :                                    + sizeof intern_hdr)) {
     578               0 :     NaClLog(4, ("internal header (size %"NACL_PRIdS" (0x%"NACL_PRIxS")) "
     579                 :                 "says there are "
     580                 :                 "%d (0x%x) NRD xfer descriptor bytes, "
     581                 :                 "but we received %"NACL_PRIdS" (0x%"NACL_PRIxS") bytes\n"),
     582                 :             sizeof intern_hdr, sizeof intern_hdr,
     583                 :             intern_hdr.h.descriptor_data_bytes,
     584                 :             intern_hdr.h.descriptor_data_bytes,
     585                 :             total_recv_bytes, total_recv_bytes);
     586               0 :     retval = -NACL_ABI_EIO;
     587               0 :     goto cleanup;
     588                 :   }
     589            9338 :   recv_user_bytes_avail = (total_recv_bytes
     590                 :                            - intern_hdr.h.descriptor_data_bytes
     591                 :                            - sizeof intern_hdr);
     592                 :   /*
     593                 :    * NaCl app asked for user_bytes, and we have recv_user_bytes_avail.
     594                 :    * Set recv_user_bytes_avail to the min of these two values, as well
     595                 :    * as inform the caller if data truncation occurred.
     596                 :    */
     597            9338 :   if (user_bytes < recv_user_bytes_avail) {
     598               3 :     recv_hdr.flags |= NACL_ABI_RECVMSG_DATA_TRUNCATED;
     599                 :   }
     600            9338 :   recv_user_bytes_avail = min_size(recv_user_bytes_avail, user_bytes);
     601                 : 
     602            9338 :   retval = recv_user_bytes_avail;  /* default from hence forth */
     603                 : 
     604                 :   /*
     605                 :    * Let UserDataSize := recv_user_bytes_avail.  (bind to current value)
     606                 :    */
     607                 : 
     608            9338 :   user_data = recv_buf + sizeof intern_hdr + intern_hdr.h.descriptor_data_bytes;
     609                 :   /*
     610                 :    * Let StartUserData := user_data
     611                 :    */
     612                 : 
     613                 :   /*
     614                 :    * Precondition: user_data in [StartUserData, StartUserData + UserDataSize].
     615                 :    *
     616                 :    * Invariant:
     617                 :    *  user_data + recv_user_bytes_avail == StartUserData + UserDataSize
     618                 :    */
     619           28963 :   for (i = 0; i < nitmhp->iov_length && 0 < recv_user_bytes_avail; ++i) {
     620           19625 :     iov_copy_size = min_size(nitmhp->iov[i].length, recv_user_bytes_avail);
     621                 : 
     622           19625 :     memcpy(nitmhp->iov[i].base, user_data, iov_copy_size);
     623                 : 
     624           19625 :     user_data += iov_copy_size;
     625                 :     /*
     626                 :      * subtraction could not underflow due to how recv_user_bytes_avail was
     627                 :      * computed; however, we are paranoid, in case the code changes.
     628                 :      */
     629           19625 :     tmp = recv_user_bytes_avail - iov_copy_size;
     630           19625 :     if (tmp > recv_user_bytes_avail) {
     631               0 :       NaClLog(LOG_FATAL,
     632                 :               "NaClImcRecvTypedMessage: impossible underflow occurred");
     633                 :     }
     634           19625 :     recv_user_bytes_avail = tmp;
     635                 : 
     636                 :   }
     637                 :   /*
     638                 :    * postcondition:  recv_user_bytes_avail == 0.
     639                 :    *
     640                 :    * NB: 0 < recv_user_bytes_avail \rightarrow i < nitmhp->iov_length
     641                 :    * must hold, due to how user_bytes is computed.  We leave the
     642                 :    * unnecessary test in the loop condition to avoid future code
     643                 :    * changes from causing problems as defensive programming.
     644                 :    */
     645                 : 
     646                 :   /*
     647                 :    * Now extract/internalize the NaClHandles as NaClDesc objects.
     648                 :    * Note that we will extract beyond nitmhp->desc_length, since we
     649                 :    * must still destroy the ones that are dropped.
     650                 :    */
     651            9338 :   xfer.next_byte = recv_buf + sizeof intern_hdr;
     652            9338 :   xfer.byte_buffer_end = xfer.next_byte + intern_hdr.h.descriptor_data_bytes;
     653            9338 :   xfer.next_handle = kern_handle;
     654            9338 :   xfer.handle_buffer_end = kern_handle + recv_hdr.handle_count;
     655                 : 
     656            9338 :   i = 0;
     657           19762 :   while (xfer.next_byte < xfer.byte_buffer_end) {
     658                 :     struct NaClDesc *out;
     659                 : 
     660            2109 :     xfer_status = NaClDescInternalizeFromXferBuffer(&out, &xfer,
     661                 :                                                     quota_interface);
     662            2109 :     NaClLog(4, "NaClDescInternalizeFromXferBuffer: returned %d\n", xfer_status);
     663            2109 :     if (0 == xfer_status) {
     664                 :       /* end of descriptors reached */
     665            1023 :       break;
     666                 :     }
     667            1086 :     if (i >= NACL_ARRAY_SIZE(new_desc)) {
     668               0 :       NaClLog(LOG_FATAL,
     669                 :               ("NaClImcRecvTypedMsg: trusted peer tried to send too many"
     670                 :                " descriptors!\n"));
     671                 :     }
     672            1086 :     if (1 != xfer_status) {
     673                 :       /* xfer_status < 0, out did not receive output */
     674               0 :       retval = -NACL_ABI_EIO;
     675               0 :       goto cleanup;
     676                 :     }
     677            1086 :     new_desc[i] = out;
     678            1086 :     out = NULL;
     679            1086 :     ++i;
     680                 :   }
     681            9338 :   num_user_desc = i;  /* actual number of descriptors received */
     682            9338 :   if (nitmhp->ndesc_length < num_user_desc) {
     683               2 :     nitmhp->flags |= NACL_ABI_RECVMSG_DESC_TRUNCATED;
     684               2 :     num_user_desc = nitmhp->ndesc_length;
     685                 :   }
     686                 : 
     687                 :   /* transfer ownership to nitmhp->ndescv; some may be left behind */
     688           10408 :   for (i = 0; i < num_user_desc; ++i) {
     689            1070 :     nitmhp->ndescv[i] = new_desc[i];
     690            1070 :     new_desc[i] = NULL;
     691                 :   }
     692                 : 
     693                 :   /* cast is safe because we clamped num_user_desc earlier to
     694                 :    * be no greater than the original value of nithmp->ndesc_length.
     695                 :    */
     696            9338 :   nitmhp->ndesc_length = (nacl_abi_size_t)num_user_desc;
     697                 : 
     698                 :   /* retval is number of bytes received */
     699                 : 
     700            9346 : cleanup:
     701            9346 :   free(recv_buf);
     702                 : 
     703                 :   /*
     704                 :    * Note that we must exercise discipline when constructing NaClDesc
     705                 :    * objects from NaClHandles -- the NaClHandle values *must* be set
     706                 :    * to NACL_INVALID_HANDLE after the construction of the NaClDesc
     707                 :    * where ownership of the NaClHandle is transferred into the NaCDesc
     708                 :    * object. Otherwise, between new_desc and kern_handle cleanup code,
     709                 :    * a NaClHandle might be closed twice.
     710                 :    */
     711           84114 :   for (i = 0; i < NACL_ARRAY_SIZE(new_desc); ++i) {
     712           74768 :     if (NULL != new_desc[i]) {
     713              16 :       NaClDescUnref(new_desc[i]);
     714              16 :       new_desc[i] = NULL;
     715                 :     }
     716                 :   }
     717           84114 :   for (i = 0; i < NACL_ARRAY_SIZE(kern_handle); ++i) {
     718           74768 :     if (NACL_INVALID_HANDLE != kern_handle[i]) {
     719               0 :       (void) NaClClose(kern_handle[i]);
     720                 :     }
     721                 :   }
     722                 : 
     723            9346 :   NaClLog(3, "NaClImcRecvTypedMsg: returning %"NACL_PRIdS"\n", retval);
     724            9346 :   return retval;
     725                 : }
     726                 : 
     727               0 : int32_t NaClCommonDescSocketPair(struct NaClDesc *pair[2]) {
     728               0 :   int32_t                         retval = -NACL_ABI_EIO;
     729                 :   struct NaClDescXferableDataDesc *d0;
     730                 :   struct NaClDescXferableDataDesc *d1;
     731                 :   NaClHandle                      sock_pair[2];
     732                 : 
     733                 :   /*
     734                 :    * mark resources to enable easy cleanup
     735                 :    */
     736               0 :   d0 = NULL;
     737               0 :   d1 = NULL;
     738               0 :   sock_pair[0] = NACL_INVALID_HANDLE;
     739               0 :   sock_pair[1] = NACL_INVALID_HANDLE;
     740                 : 
     741               0 :   if (0 != NaClSocketPair(sock_pair)) {
     742               0 :     NaClLog(1,
     743                 :             "NaClCommonSysImc_Socket_Pair: IMC socket pair creation failed\n");
     744               0 :     retval = -NACL_ABI_ENFILE;
     745               0 :     goto cleanup;
     746                 :   }
     747               0 :   if (NULL == (d0 = malloc(sizeof *d0))) {
     748               0 :     retval = -NACL_ABI_ENOMEM;
     749               0 :     goto cleanup;
     750                 :   }
     751               0 :   if (NULL == (d1 = malloc(sizeof *d1))) {
     752               0 :     free((void *) d0);
     753               0 :     d0 = NULL;
     754               0 :     retval = -NACL_ABI_ENOMEM;
     755               0 :     goto cleanup;
     756                 :   }
     757               0 :   if (!NaClDescXferableDataDescCtor(d0, sock_pair[0])) {
     758               0 :     free((void *) d0);
     759               0 :     d0 = NULL;
     760               0 :     free((void *) d1);
     761               0 :     d1 = NULL;
     762               0 :     retval = -NACL_ABI_ENFILE;
     763               0 :     goto cleanup;
     764                 :   }
     765               0 :   sock_pair[0] = NACL_INVALID_HANDLE;  /* ctor took ownership */
     766               0 :   if (!NaClDescXferableDataDescCtor(d1, sock_pair[1])) {
     767               0 :     free((void *) d1);
     768               0 :     d1 = NULL;
     769               0 :     retval = -NACL_ABI_ENFILE;
     770               0 :     goto cleanup;
     771                 :   }
     772               0 :   sock_pair[1] = NACL_INVALID_HANDLE;  /* ctor took ownership */
     773                 : 
     774               0 :   pair[0] = (struct NaClDesc *) d0;
     775               0 :   d0 = NULL;
     776                 : 
     777               0 :   pair[1] = (struct NaClDesc *) d1;
     778               0 :   d1 = NULL;
     779                 : 
     780               0 :   retval = 0;
     781                 : 
     782               0 :  cleanup:
     783                 :   /*
     784                 :    * pre: d0 and d1 must either be NULL or point to fully constructed
     785                 :    * NaClDesc objects
     786                 :    */
     787               0 :   if (NULL != d0) {
     788               0 :     NaClDescUnref((struct NaClDesc *) d0);
     789                 :   }
     790               0 :   if (NULL != d1) {
     791               0 :     NaClDescUnref((struct NaClDesc *) d1);
     792                 :   }
     793               0 :   if (NACL_INVALID_HANDLE != sock_pair[0]) {
     794               0 :     (void) NaClClose(sock_pair[0]);
     795                 :   }
     796               0 :   if (NACL_INVALID_HANDLE != sock_pair[1]) {
     797               0 :     (void) NaClClose(sock_pair[1]);
     798                 :   }
     799                 : 
     800               0 :   free(d0);
     801               0 :   free(d1);
     802                 : 
     803               0 :   return retval;
     804                 : }

Generated by: LCOV version 1.7