LCOV - code coverage report
Current view: directory - src/trusted/desc - nrd_xfer.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 304 185 60.9 %
Date: 2014-09-25 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                 : static INLINE size_t min_size(size_t  a,
      50               4 :                               size_t  b) {
      51               4 :   if (a < b) return a;
      52               4 :   return b;
      53               4 : }
      54                 : 
      55                 : void NaClNrdXferIncrTagOverhead(size_t *byte_count,
      56               0 :                                 size_t *handle_count) {
      57                 :   UNREFERENCED_PARAMETER(handle_count);
      58               0 :   ++*byte_count;
      59               0 : }
      60                 : 
      61               2 : enum NaClDescTypeTag NaClNrdXferReadTypeTag(struct NaClDescXferState *xferp) {
      62               2 :   return (enum NaClDescTypeTag) (0xff & *xferp->next_byte++);
      63               2 : }
      64                 : 
      65                 : void NaClNrdXferWriteTypeTag(struct NaClDescXferState *xferp,
      66               2 :                              struct NaClDesc          *descp) {
      67               2 :   *xferp->next_byte++ = NACL_VTBL(NaClDesc, descp)->typeTag;
      68               2 : }
      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                 :     struct NaClDesc               **out_desc,
      79                 :     struct NaClDescXferState      *xferp,
      80               2 :     struct NaClDescQuotaInterface *quota_interface) {
      81                 :   int xfer_status;
      82                 :   size_t type_tag;
      83                 : 
      84               2 :   type_tag = NaClNrdXferReadTypeTag(xferp);
      85                 :   /* 0 <= type_tag */
      86               2 :   if (NACL_DESC_TYPE_END_TAG == type_tag) {
      87               2 :     return 0;
      88                 :   }
      89               2 :   if (type_tag >= NACL_DESC_TYPE_MAX) {
      90                 :     NaClLog(4, ("illegal type tag %"NACL_PRIuS" (0x%"NACL_PRIxS")\n"),
      91               0 :             type_tag, type_tag);
      92               0 :     return -NACL_ABI_EIO;
      93                 :   }
      94                 :   if ((int (*)(struct NaClDesc **, struct NaClDescXferState *,
      95                 :                struct NaClDescQuotaInterface *)) NULL ==
      96               2 :       NaClDescInternalize[type_tag]) {
      97                 :     NaClLog(LOG_FATAL,
      98                 :             "No internalization function for type %"NACL_PRIuS"\n",
      99               0 :             type_tag);
     100                 :     /* fatal, but in case we change it later */
     101               0 :     return -NACL_ABI_EIO;
     102                 :   }
     103                 :   xfer_status = (*NaClDescInternalize[type_tag])(out_desc, xferp,
     104               2 :                                                  quota_interface);
     105                 :   /* constructs new_desc, transferring ownership of any handles consumed */
     106                 : 
     107               2 :   if (xfer_status != 0) {
     108                 :     NaClLog(0,
     109                 :             "non-zero xfer_status %d, desc type tag %s (%"NACL_PRIuS")\n",
     110                 :             xfer_status,
     111                 :             NaClDescTypeString(type_tag),
     112               0 :             type_tag);
     113                 :   }
     114               2 :   return 0 == xfer_status;
     115               2 : }
     116                 : 
     117                 : int NaClDescExternalizeToXferBuffer(struct NaClDescXferState  *xferp,
     118               2 :                                     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               2 :   NaClNrdXferWriteTypeTag(xferp, out);
     130               2 :   return (*NACL_VTBL(NaClDesc, out)->Externalize)(out, xferp);
     131               2 : }
     132                 : 
     133                 : ssize_t NaClImcSendTypedMessage(struct NaClDesc                 *channel,
     134                 :                                 const struct NaClImcTypedMsgHdr *nitmhp,
     135               4 :                                 int                              flags) {
     136                 :   int                       supported_flags;
     137               4 :   ssize_t                   retval = -NACL_ABI_EINVAL;
     138                 :   struct NaClMessageHeader  kern_msg_hdr;  /* xlated interface */
     139                 :   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                 :   struct NaClImcMsgIoVec    kern_iov[NACL_ABI_IMC_IOVEC_MAX + 1];
     147                 :   struct NaClDesc           **kern_desc;
     148                 :   NaClHandle                kern_handle[NACL_ABI_IMC_DESC_MAX];
     149                 :   size_t                    user_bytes;
     150                 :   size_t                    sys_bytes;
     151                 :   size_t                    sys_handles;
     152                 :   size_t                    desc_bytes;
     153                 :   size_t                    desc_handles;
     154                 :   struct NaClInternalHeader *hdr;
     155                 :   char                      *hdr_buf;
     156                 :   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                 :   NaClLog(3,
     164                 :           ("Entered"
     165                 :            " NaClImcSendTypedMessage(0x%08"NACL_PRIxPTR", "
     166                 :            "0x%08"NACL_PRIxPTR", 0x%x)\n"),
     167               4 :           (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               4 :   supported_flags = NACL_ABI_IMC_NONBLOCK;
     174               4 :   if (0 != (flags & ~supported_flags)) {
     175                 :     NaClLog(LOG_WARNING,
     176                 :             "WARNING: NaClImcSendTypedMessage: unknown IMC flag used: 0x%x\n",
     177               0 :             flags);
     178               0 :     flags &= supported_flags;
     179                 :   }
     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                 :   if (0 != nitmhp->ndesc_length
     188               4 :       && 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               4 :   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               4 :   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                 :   memcpy(kern_iov + 1, (void *) nitmhp->iov,
     203               4 :          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               4 :   user_bytes = 0;
     216               4 :   for (i = 0; i < nitmhp->iov_length; ++i) {
     217               3 :     if (user_bytes > SIZE_T_MAX - kern_iov[i+1].length) {
     218               0 :       return -NACL_ABI_EINVAL;
     219                 :     }
     220               3 :     user_bytes += kern_iov[i+1].length;
     221               3 :   }
     222               4 :   if (user_bytes > NACL_ABI_IMC_USER_BYTES_MAX) {
     223               0 :     return -NACL_ABI_EINVAL;
     224                 :   }
     225                 : 
     226               4 :   kern_desc = nitmhp->ndescv;
     227               4 :   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               4 :   kern_msg_hdr.iov = (struct NaClIOVec *) kern_iov;
     235               4 :   kern_msg_hdr.iov_length = nitmhp->iov_length + 1;  /* header */
     236                 : 
     237               4 :   if (0 == nitmhp->ndesc_length) {
     238               3 :     kern_msg_hdr.handles = NULL;
     239               3 :     kern_msg_hdr.handle_count = 0;
     240               3 :     kern_iov[0].base = (void *) &kNoHandles;
     241               3 :     kern_iov[0].length = sizeof kNoHandles;
     242               3 :   } else {
     243                 :     /*
     244                 :      * \forall i \in [0, nitmhp->desc_length): kern_desc[i] != NULL.
     245                 :      */
     246                 : 
     247               2 :     sys_bytes = 0;
     248               2 :     sys_handles = 0;
     249                 :     /* nitmhp->desc_length <= NACL_ABI_IMC_USER_DESC_MAX */
     250               2 :     for (i = 0; i < nitmhp->ndesc_length; ++i) {
     251               2 :       desc_bytes = 0;
     252               2 :       desc_handles = 0;
     253                 :       retval = (*((struct NaClDescVtbl const *) kern_desc[i]->base.vtbl)->
     254                 :                 ExternalizeSize)(kern_desc[i],
     255                 :                                  &desc_bytes,
     256               2 :                                  &desc_handles);
     257               2 :       if (retval < 0) {
     258                 :         NaClLog(1,
     259                 :                 ("NaClImcSendTypedMessage: ExternalizeSize"
     260                 :                  " returned %"NACL_PRIdS"\n"),
     261               0 :                 retval);
     262               0 :         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                 :       if (desc_bytes > NACL_ABI_SIZE_T_MAX - 1
     269                 :           || (desc_bytes + 1) > NACL_ABI_SIZE_T_MAX - sys_bytes
     270               2 :           || desc_handles > NACL_ABI_SIZE_T_MAX - sys_handles) {
     271               0 :         retval = -NACL_ABI_EOVERFLOW;
     272               0 :         goto cleanup;
     273                 :       }
     274               2 :       sys_bytes += (1 + desc_bytes);
     275               2 :       sys_handles += desc_handles;
     276               2 :     }
     277               2 :     if (sys_handles > NACL_ABI_IMC_DESC_MAX) {
     278                 :       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               0 :               NACL_ABI_IMC_DESC_MAX);
     284                 :     }
     285                 :     /* a byte for NACL_DESC_TYPE_END_TAG, then rounded up to 0 mod 16 */
     286               2 :     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               2 :     if (sys_bytes > NACL_ABI_SIZE_T_MAX - sizeof *hdr) {
     294                 :       NaClLog(LOG_FATAL, "NaClImcSendTypedMessage: "
     295                 :               "Buffer size overflow (%"NACL_PRIuS" bytes)",
     296               0 :               sys_bytes);
     297               0 :       retval = -NACL_ABI_EOVERFLOW;
     298               0 :       goto cleanup;
     299                 :     }
     300               2 :     hdr_buf = malloc(sys_bytes + sizeof *hdr);
     301               2 :     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               2 :     kern_iov[0].base = (void *) hdr_buf;
     307                 : 
     308                 :     /* Checked above that sys_bytes <= NACL_ABI_SIZE_T_MAX - sizeof *hdr */
     309               2 :     kern_iov[0].length = (nacl_abi_size_t)(sys_bytes + sizeof *hdr);
     310                 : 
     311               2 :     hdr = (struct NaClInternalHeader *) hdr_buf;
     312               2 :     memset(hdr, 0, sizeof(*hdr));  /* Initilize the struct's padding bytes. */
     313               2 :     hdr->h.xfer_protocol_version = NACL_HANDLE_TRANSFER_PROTOCOL;
     314               2 :     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               2 :     hdr->h.descriptor_data_bytes = (uint32_t) sys_bytes;
     332                 : 
     333               2 :     xfer_state.next_byte = (char *) (hdr + 1);
     334               2 :     xfer_state.byte_buffer_end = xfer_state.next_byte + sys_bytes;
     335               2 :     xfer_state.next_handle = kern_handle;
     336                 :     xfer_state.handle_buffer_end = xfer_state.next_handle
     337               2 :         + NACL_ABI_IMC_DESC_MAX;
     338                 : 
     339               2 :     for (i = 0; i < nitmhp->ndesc_length; ++i) {
     340               2 :       retval = NaClDescExternalizeToXferBuffer(&xfer_state, kern_desc[i]);
     341               2 :       if (0 != retval) {
     342                 :         NaClLog(4,
     343                 :                 ("NaClImcSendTypedMessage: Externalize for"
     344                 :                  " descriptor %"NACL_PRIuS" returned %"NACL_PRIdS"\n"),
     345               0 :                 i, retval);
     346               0 :         goto cleanup;
     347                 :       }
     348               2 :     }
     349               2 :     *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               2 :     while (xfer_state.next_byte < xfer_state.byte_buffer_end) {
     355               2 :       *xfer_state.next_byte++ = '\0';
     356               2 :     }
     357                 : 
     358               2 :     kern_msg_hdr.handles = kern_handle;
     359               2 :     kern_msg_hdr.handle_count = (uint32_t) sys_handles;
     360                 :   }
     361                 : 
     362               4 :   NaClLog(4, "Invoking LowLevelSendMsg, flags 0x%x\n", flags);
     363                 : 
     364                 :   retval = (*((struct NaClDescVtbl const *) channel->base.vtbl)->
     365               4 :             LowLevelSendMsg)(channel, &kern_msg_hdr, flags);
     366               4 :   NaClLog(4, "LowLevelSendMsg returned %"NACL_PRIdS"\n", retval);
     367               4 :   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               0 :     }
     391               4 :   } 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               4 :     retval -= kern_iov[0].length;
     402                 :   }
     403                 : 
     404                 : cleanup:
     405                 : 
     406               4 :   free(hdr_buf);
     407                 : 
     408               4 :   NaClLog(4, "NaClImcSendTypedMessage: returning %"NACL_PRIdS"\n", retval);
     409                 : 
     410               4 :   return retval;
     411               4 : }
     412                 : 
     413                 : 
     414                 : ssize_t NaClImcRecvTypedMessage(
     415                 :     struct NaClDesc               *channel,
     416                 :     struct NaClImcTypedMsgHdr     *nitmhp,
     417                 :     int                           flags,
     418               4 :     struct NaClDescQuotaInterface *quota_interface) {
     419                 :   int                       supported_flags;
     420                 :   ssize_t                   retval;
     421                 :   char                      *recv_buf;
     422                 :   size_t                    user_bytes;
     423                 :   NaClHandle                kern_handle[NACL_ABI_IMC_DESC_MAX];
     424                 :   struct NaClIOVec          recv_iov;
     425                 :   struct NaClMessageHeader  recv_hdr;
     426                 :   ssize_t                   total_recv_bytes;
     427                 :   struct NaClInternalHeader intern_hdr;
     428                 :   size_t                    recv_user_bytes_avail;
     429                 :   size_t                    tmp;
     430                 :   char                      *user_data;
     431                 :   size_t                    iov_copy_size;
     432                 :   struct NaClDescXferState  xfer;
     433                 :   struct NaClDesc           *new_desc[NACL_ABI_IMC_DESC_MAX];
     434                 :   int                       xfer_status;
     435                 :   size_t                    i;
     436                 :   size_t                    num_user_desc;
     437                 : 
     438                 :   NaClLog(4,
     439                 :           "Entered NaClImcRecvTypedMsg(0x%08"NACL_PRIxPTR", "
     440                 :           "0x%08"NACL_PRIxPTR", %d)\n",
     441               4 :           (uintptr_t) channel, (uintptr_t) nitmhp, flags);
     442                 : 
     443               4 :   supported_flags = NACL_ABI_IMC_NONBLOCK;
     444               4 :   if (0 != (flags & ~supported_flags)) {
     445                 :     NaClLog(LOG_WARNING,
     446                 :             "WARNING: NaClImcRecvTypedMsg: unknown IMC flag used: 0x%x\n",
     447               0 :             flags);
     448               0 :     flags &= supported_flags;
     449                 :   }
     450                 : 
     451               4 :   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               4 :   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               4 :   user_bytes = 0;
     461               4 :   for (i = 0; i < nitmhp->iov_length; ++i) {
     462               3 :     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               3 :     user_bytes += nitmhp->iov[i].length;
     467               3 :   }
     468                 :   /*
     469                 :    * if user_bytes > NACL_ABI_IMC_USER_BYTES_MAX,
     470                 :    * we will just never fill up all the buffer space.
     471                 :    */
     472               4 :   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               4 :   recv_buf = NULL;
     479               4 :   memset(new_desc, 0, sizeof new_desc);
     480                 :   /*
     481                 :    * from here on, set retval and jump to cleanup code.
     482                 :    */
     483                 : 
     484               4 :   recv_buf = malloc(NACL_ABI_IMC_BYTES_MAX);
     485               4 :   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               4 :   recv_iov.base = (void *) recv_buf;
     492               4 :   recv_iov.length = NACL_ABI_IMC_BYTES_MAX;
     493                 : 
     494               4 :   recv_hdr.iov = &recv_iov;
     495               4 :   recv_hdr.iov_length = 1;
     496                 : 
     497               4 :   for (i = 0; i < NACL_ARRAY_SIZE(kern_handle); ++i) {
     498               4 :     kern_handle[i] = NACL_INVALID_HANDLE;
     499               4 :   }
     500                 : 
     501                 :   if (NACL_DESC_IMC_SOCKET == ((struct NaClDescVtbl const *)
     502               4 :                                channel->base.vtbl)->typeTag) {
     503                 :     /*
     504                 :      * Channel can transfer access rights.
     505                 :      */
     506                 : 
     507               4 :     recv_hdr.handles = kern_handle;
     508               4 :     recv_hdr.handle_count = NACL_ARRAY_SIZE(kern_handle);
     509               4 :     NaClLog(4, "Connected socket, may transfer descriptors\n");
     510               4 :   } else {
     511                 :     /*
     512                 :      * Channel cannot transfer access rights.  The syscall would fail
     513                 :      * if recv_iov.length is non-zero.
     514                 :      */
     515                 : 
     516               0 :     recv_hdr.handles = (NaClHandle *) NULL;
     517               0 :     recv_hdr.handle_count = 0;
     518               0 :     NaClLog(4, "Transferable Data Only socket\n");
     519                 :   }
     520                 : 
     521               4 :   recv_hdr.flags = 0;  /* just to make it obvious; IMC will clear it for us */
     522                 : 
     523                 :   total_recv_bytes = (*((struct NaClDescVtbl const *) channel->base.vtbl)->
     524                 :                       LowLevelRecvMsg)(channel,
     525                 :                                        &recv_hdr,
     526               4 :                                        flags);
     527               4 :   if (NaClSSizeIsNegErrno(&total_recv_bytes)) {
     528                 :     NaClLog(1, "LowLevelRecvMsg failed, returned %"NACL_PRIdS"\n",
     529               2 :             total_recv_bytes);
     530               2 :     retval = total_recv_bytes;
     531               2 :     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               4 :   if ((size_t) total_recv_bytes < sizeof intern_hdr) {
     548                 :     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               0 :             sizeof intern_hdr, sizeof intern_hdr);
     553               0 :     retval = -NACL_ABI_EIO;
     554               0 :     goto cleanup;
     555                 :   }
     556               4 :   memcpy(&intern_hdr, recv_buf, sizeof intern_hdr);
     557                 :   /*
     558                 :    * Future code should handle old versions in a backward compatible way.
     559                 :    */
     560               4 :   if (NACL_HANDLE_TRANSFER_PROTOCOL != intern_hdr.h.xfer_protocol_version) {
     561                 :     NaClLog(4, ("protocol version mismatch:"
     562                 :                 " got %x, but can only handle %x\n"),
     563               0 :             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                 :   if ((size_t) total_recv_bytes < (intern_hdr.h.descriptor_data_bytes
     573               4 :                                    + sizeof intern_hdr)) {
     574                 :     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               0 :             total_recv_bytes, (size_t) total_recv_bytes);
     582               0 :     retval = -NACL_ABI_EIO;
     583               0 :     goto cleanup;
     584                 :   }
     585                 :   recv_user_bytes_avail = (total_recv_bytes
     586                 :                            - intern_hdr.h.descriptor_data_bytes
     587               4 :                            - 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               4 :   if (user_bytes < recv_user_bytes_avail) {
     594               1 :     recv_hdr.flags |= NACL_ABI_RECVMSG_DATA_TRUNCATED;
     595                 :   }
     596               4 :   recv_user_bytes_avail = min_size(recv_user_bytes_avail, user_bytes);
     597                 : 
     598               4 :   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               4 :   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               4 :   for (i = 0; i < nitmhp->iov_length && 0 < recv_user_bytes_avail; ++i) {
     616               3 :     iov_copy_size = min_size(nitmhp->iov[i].length, recv_user_bytes_avail);
     617                 : 
     618               3 :     memcpy(nitmhp->iov[i].base, user_data, iov_copy_size);
     619                 : 
     620               3 :     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               3 :     tmp = recv_user_bytes_avail - iov_copy_size;
     626               3 :     if (tmp > recv_user_bytes_avail) {
     627                 :       NaClLog(LOG_FATAL,
     628               0 :               "NaClImcRecvTypedMessage: impossible underflow occurred");
     629                 :     }
     630               3 :     recv_user_bytes_avail = tmp;
     631                 : 
     632               3 :   }
     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               4 :   xfer.next_byte = recv_buf + sizeof intern_hdr;
     648               4 :   xfer.byte_buffer_end = xfer.next_byte + intern_hdr.h.descriptor_data_bytes;
     649               4 :   xfer.next_handle = kern_handle;
     650               4 :   xfer.handle_buffer_end = kern_handle + recv_hdr.handle_count;
     651                 : 
     652               4 :   i = 0;
     653               4 :   while (xfer.next_byte < xfer.byte_buffer_end) {
     654                 :     struct NaClDesc *out;
     655                 : 
     656                 :     xfer_status = NaClDescInternalizeFromXferBuffer(&out, &xfer,
     657               2 :                                                     quota_interface);
     658               2 :     NaClLog(4, "NaClDescInternalizeFromXferBuffer: returned %d\n", xfer_status);
     659               2 :     if (0 == xfer_status) {
     660                 :       /* end of descriptors reached */
     661               2 :       break;
     662                 :     }
     663               2 :     if (i >= NACL_ARRAY_SIZE(new_desc)) {
     664                 :       NaClLog(LOG_FATAL,
     665                 :               ("NaClImcRecvTypedMsg: trusted peer tried to send too many"
     666               0 :                " descriptors!\n"));
     667                 :     }
     668               2 :     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               2 :     new_desc[i] = out;
     674               2 :     out = NULL;
     675               2 :     ++i;
     676               2 :   }
     677               4 :   num_user_desc = i;  /* actual number of descriptors received */
     678               4 :   if (nitmhp->ndesc_length < num_user_desc) {
     679               1 :     nitmhp->flags |= NACL_ABI_RECVMSG_DESC_TRUNCATED;
     680               1 :     num_user_desc = nitmhp->ndesc_length;
     681                 :   }
     682                 : 
     683                 :   /* transfer ownership to nitmhp->ndescv; some may be left behind */
     684               4 :   for (i = 0; i < num_user_desc; ++i) {
     685               2 :     nitmhp->ndescv[i] = new_desc[i];
     686               2 :     new_desc[i] = NULL;
     687               2 :   }
     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               4 :   nitmhp->ndesc_length = (nacl_abi_size_t)num_user_desc;
     693                 : 
     694                 :   /* retval is number of bytes received */
     695                 : 
     696                 : cleanup:
     697               4 :   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               4 :   for (i = 0; i < NACL_ARRAY_SIZE(new_desc); ++i) {
     708               4 :     if (NULL != new_desc[i]) {
     709               1 :       NaClDescUnref(new_desc[i]);
     710               1 :       new_desc[i] = NULL;
     711                 :     }
     712               4 :   }
     713               4 :   for (i = 0; i < NACL_ARRAY_SIZE(kern_handle); ++i) {
     714               4 :     if (NACL_INVALID_HANDLE != kern_handle[i]) {
     715               0 :       (void) NaClClose(kern_handle[i]);
     716                 :     }
     717               4 :   }
     718                 : 
     719               4 :   NaClLog(3, "NaClImcRecvTypedMsg: returning %"NACL_PRIdS"\n", retval);
     720               4 :   return retval;
     721               4 : }
     722                 : 
     723               0 : int32_t NaClCommonDescSocketPair(struct NaClDesc *pair[2]) {
     724               0 :   int32_t                         retval = -NACL_ABI_EIO;
     725                 :   struct NaClDescXferableDataDesc *d0;
     726                 :   struct NaClDescXferableDataDesc *d1;
     727                 :   NaClHandle                      sock_pair[2];
     728                 : 
     729                 :   /*
     730                 :    * mark resources to enable easy cleanup
     731                 :    */
     732               0 :   d0 = NULL;
     733               0 :   d1 = NULL;
     734               0 :   sock_pair[0] = NACL_INVALID_HANDLE;
     735               0 :   sock_pair[1] = NACL_INVALID_HANDLE;
     736                 : 
     737               0 :   if (0 != NaClSocketPair(sock_pair)) {
     738                 :     NaClLog(1,
     739               0 :             "NaClCommonSysImc_Socket_Pair: IMC socket pair creation failed\n");
     740               0 :     retval = -NACL_ABI_ENFILE;
     741               0 :     goto cleanup;
     742                 :   }
     743               0 :   if (NULL == (d0 = malloc(sizeof *d0))) {
     744               0 :     retval = -NACL_ABI_ENOMEM;
     745               0 :     goto cleanup;
     746                 :   }
     747               0 :   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               0 :   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               0 :   sock_pair[0] = NACL_INVALID_HANDLE;  /* ctor took ownership */
     762               0 :   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               0 :   sock_pair[1] = NACL_INVALID_HANDLE;  /* ctor took ownership */
     769                 : 
     770               0 :   pair[0] = (struct NaClDesc *) d0;
     771               0 :   d0 = NULL;
     772                 : 
     773               0 :   pair[1] = (struct NaClDesc *) d1;
     774               0 :   d1 = NULL;
     775                 : 
     776               0 :   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               0 :   if (NULL != d0) {
     784               0 :     NaClDescUnref((struct NaClDesc *) d0);
     785                 :   }
     786               0 :   if (NULL != d1) {
     787               0 :     NaClDescUnref((struct NaClDesc *) d1);
     788                 :   }
     789               0 :   if (NACL_INVALID_HANDLE != sock_pair[0]) {
     790               0 :     (void) NaClClose(sock_pair[0]);
     791                 :   }
     792               0 :   if (NACL_INVALID_HANDLE != sock_pair[1]) {
     793               0 :     (void) NaClClose(sock_pair[1]);
     794                 :   }
     795                 : 
     796               0 :   free(d0);
     797               0 :   free(d1);
     798                 : 
     799               0 :   return retval;
     800               0 : }

Generated by: LCOV version 1.7