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

Generated by: LCOV version 1.7