LCOV - code coverage report
Current view: directory - src/shared/srpc - nacl_srpc_message.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 459 369 80.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                 : #include <stdio.h>
       8                 : #include <stdlib.h>
       9                 : #include <string.h>
      10                 : #include <sys/types.h>
      11                 : 
      12                 : #include "native_client/src/include/portability.h"
      13                 : #include "native_client/src/include/nacl_macros.h"
      14                 : #include "native_client/src/shared/platform/nacl_check.h"
      15                 : /*
      16                 :  * #including nacl_srpc_message.h before nacl_host_desc.h currently
      17                 :  * fails with nacl-glibc because it leaves nacl_abi_time_t undeclared.
      18                 :  * TODO(mseaborn): Fix problems with these headers.
      19                 :  */
      20                 : #include "native_client/src/shared/platform/nacl_host_desc.h"
      21                 : #include "native_client/src/shared/srpc/nacl_srpc_message.h"
      22                 : #include "native_client/src/shared/srpc/nacl_srpc.h"
      23                 : #include "native_client/src/shared/srpc/nacl_srpc_internal.h"
      24                 : 
      25                 : #ifdef __native_client__
      26                 : # define NaClImcMsgIoVec NaClAbiNaClImcMsgIoVec
      27                 : /*
      28                 :  * We cannot currently #include service_runtime/include/sys/errno.h
      29                 :  * with nacl-glibc because it #includes sys/reent.h, which is a
      30                 :  * newlibism that glibc does not provide.
      31                 :  * TODO(mseaborn): Fix problems with these headers.
      32                 :  */
      33                 : # include <errno.h>
      34                 : # define NACL_ABI_EIO EIO
      35                 : # define NACL_ABI_EINVAL EINVAL
      36                 : # include "native_client/src/public/imc_syscalls.h"
      37                 : #else
      38                 : # include "native_client/src/trusted/desc/nacl_desc_base.h"
      39                 : # include "native_client/src/trusted/service_runtime/include/sys/errno.h"
      40                 : #endif
      41                 : 
      42                 : #ifndef SIZE_T_MAX
      43                 : # define SIZE_T_MAX (~((size_t) 0))
      44                 : #endif
      45                 : 
      46           81230 : static size_t size_min(size_t a, size_t b) {
      47           81230 :   if (a < b) {
      48           11199 :     return a;
      49                 :   } else {
      50           70031 :     return b;
      51                 :   }
      52           81230 : }
      53                 : 
      54                 : /*
      55                 :  * Defines for the executable portions of the differences between trusted
      56                 :  * and untrusted code.
      57                 :  */
      58                 : #ifdef __native_client__
      59                 : 
      60                 : static const NaClSrpcMessageDesc   kInvalidDesc = -1;
      61                 : 
      62                 : static ssize_t ImcSendmsg(NaClSrpcMessageDesc desc,
      63                 :                           const NaClSrpcMessageHeader* header,
      64                 :                           int flags) {
      65                 :   nacl_abi_ssize_t retval = imc_sendmsg(desc, header, flags);
      66                 :   if (-1 == retval) {
      67                 :     return -errno;
      68                 :   }
      69                 :   return retval;
      70                 : }
      71                 : 
      72                 : static ssize_t ImcRecvmsg(NaClSrpcMessageDesc desc,
      73                 :                           NaClSrpcMessageHeader* header,
      74                 :                           int flags) {
      75                 :   nacl_abi_ssize_t retval = imc_recvmsg(desc, header, flags);
      76                 :   if (-1 == retval) {
      77                 :     return -errno;
      78                 :   }
      79                 :   return retval;
      80                 : }
      81                 : 
      82                 : #else  /* trusted code */
      83                 : 
      84                 : /* These are defined by default in untrusted code. */
      85                 : # define IMC_USER_DESC_MAX         NACL_ABI_IMC_USER_DESC_MAX
      86                 : # define IMC_USER_BYTES_MAX        NACL_ABI_IMC_USER_BYTES_MAX
      87                 : static const NaClSrpcMessageDesc   kInvalidDesc = NULL;
      88                 : 
      89            9421 : static ssize_t ImcSendmsg(NaClSrpcMessageDesc desc,
      90            9421 :                           const NaClSrpcMessageHeader* header,
      91            9421 :                           int flags) {
      92            9421 :   return NACL_VTBL(NaClDesc, desc)->SendMsg(desc, header, flags);
      93                 : }
      94                 : 
      95            9446 : static ssize_t ImcRecvmsg(NaClSrpcMessageDesc desc,
      96            9446 :                           NaClSrpcMessageHeader* header,
      97            9446 :                           int flags) {
      98                 :   /* Quota management is not supported in trusted SRPC. */
      99            9446 :   return NACL_VTBL(NaClDesc, desc)->RecvMsg(
     100                 :       desc, header, flags, (struct NaClDescQuotaInterface *) NULL);
     101                 : }
     102                 : 
     103                 : #endif  /* __native_client__ */
     104                 : 
     105                 : struct PortableDesc {
     106                 :   NaClSrpcMessageDesc raw_desc;
     107                 : };
     108                 : 
     109                 : /*
     110                 :  * A wrapper class for NaClSrpcMessageDesc that allows clients to ignore
     111                 :  * implementation differences.
     112                 :  */
     113              76 : static int PortableDescCtor(struct PortableDesc* self,
     114              76 :                             NaClSrpcMessageDesc desc) {
     115              76 :   if (kInvalidDesc == desc) {
     116               0 :     return 0;
     117                 :   }
     118                 : #ifdef __native_client__
     119                 :   self->raw_desc = desc;
     120                 : #else
     121              76 :   self->raw_desc = NaClDescRef(desc);
     122                 : #endif  /* __native_client__ */
     123              76 :   return 1;
     124              76 : }
     125                 : 
     126              58 : static void PortableDescDtor(struct PortableDesc* self) {
     127                 : #ifndef __native_client__
     128              58 :   NaClDescSafeUnref(self->raw_desc);
     129                 : #endif  /* __native_client__ */
     130              58 :   self->raw_desc = kInvalidDesc;
     131              58 : }
     132                 : 
     133                 : /*
     134                 :  * The length descriptor type for messages.  Messages may be fragmented into
     135                 :  * multiple calls to ImcSendmsg/ImcRecvmsg.  The first fragment contains two
     136                 :  * LengthHeaders; one gives the total byte and desc count, and the other
     137                 :  * indicates the first fragment's byte and desc count.  All subsequent
     138                 :  * fragments contain just the fragment's byte and desc count.  These need to
     139                 :  * be platform-independent types, because the sender and receiver may have
     140                 :  * a different notion of how big size_t is.
     141                 :  */
     142                 : typedef struct {
     143                 :   nacl_abi_size_t byte_count;
     144                 :   nacl_abi_size_t desc_count;
     145                 : } LengthHeader;
     146                 : #define FRAGMENT_OVERHEAD ((ssize_t) (sizeof(LengthHeader)))
     147                 : 
     148                 : enum FragmentPosition {
     149                 :   FIRST_FRAGMENT,
     150                 :   LATER_FRAGMENT
     151                 : };
     152                 : 
     153                 : size_t const kFragmentHeaderCount[] = {
     154                 :   2,
     155                 :   1
     156                 : };
     157                 : 
     158                 : size_t const kFragmentOverhead[] = {
     159                 :   2 * FRAGMENT_OVERHEAD,
     160                 :   FRAGMENT_OVERHEAD
     161                 : };
     162                 : 
     163                 : struct NaClSrpcMessageChannel {
     164                 :   struct PortableDesc desc;
     165                 :   /* The below members are used to buffer a single message, for use by peek. */
     166                 :   char bytes[NACL_ABI_IMC_USER_BYTES_MAX];
     167                 :   size_t byte_count;
     168                 :   NaClSrpcMessageDesc descs[NACL_ABI_IMC_USER_DESC_MAX];
     169                 :   size_t desc_count;
     170                 : };
     171                 : 
     172                 : struct NaClSrpcMessageChannel* NaClSrpcMessageChannelNew(
     173              76 :     NaClSrpcMessageDesc desc) {
     174              76 :   struct NaClSrpcMessageChannel* channel = NULL;
     175                 : 
     176              76 :   channel = (struct NaClSrpcMessageChannel*) malloc(sizeof *channel);
     177              76 :   if (NULL == channel) {
     178               0 :     return NULL;
     179                 :   }
     180              76 :   if (!PortableDescCtor(&channel->desc, desc)) {
     181               0 :     free(channel);
     182               0 :     return NULL;
     183                 :   }
     184              76 :   channel->byte_count = 0;
     185              76 :   channel->desc_count = 0;
     186              76 :   return channel;
     187              76 : }
     188                 : 
     189              61 : void NaClSrpcMessageChannelDelete(struct NaClSrpcMessageChannel* channel) {
     190              61 :   if (NULL != channel) {
     191              58 :     PortableDescDtor(&channel->desc);
     192              58 :     free(channel);
     193              58 :   }
     194              61 : }
     195                 : 
     196                 : /*
     197                 :  * Read the next fragment of a message into channel's buffer.
     198                 :  */
     199                 : static uint32_t MessageChannelBufferFirstFragment(
     200             255 :     struct NaClSrpcMessageChannel* channel) {
     201             255 :   ssize_t imc_ret = -1;
     202             255 :   NaClSrpcMessageHeader buffer_header;
     203             255 :   struct NaClImcMsgIoVec iovec[1];
     204                 : 
     205             255 :   NaClSrpcLog(3,
     206                 :               "MessageChannelBufferFirstFragment: waiting for message.\n");
     207                 :   /* Read the entire first fragment into channel's buffer. */
     208             255 :   buffer_header.iov = iovec;
     209             255 :   buffer_header.iov_length = NACL_ARRAY_SIZE(iovec);
     210             255 :   buffer_header.NACL_SRPC_MESSAGE_HEADER_DESCV = channel->descs;
     211             255 :   buffer_header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH =
     212                 :       NACL_ARRAY_SIZE(channel->descs);
     213             255 :   buffer_header.iov[0].base = channel->bytes;
     214             255 :   buffer_header.iov[0].length = NACL_ARRAY_SIZE(channel->bytes);
     215             255 :   buffer_header.flags = 0;
     216                 :   /*
     217                 :    * The message receive should return at least
     218                 :    * kFragmentOverhead[FIRST_FRAGMENT] bytes.
     219                 :    */
     220             255 :   imc_ret = ImcRecvmsg(channel->desc.raw_desc, &buffer_header, 0);
     221             492 :   if ((imc_ret < (ssize_t) kFragmentOverhead[FIRST_FRAGMENT]) ||
     222                 :       (buffer_header.flags != 0)) {
     223              18 :     NaClSrpcLog(3,
     224                 :                 "MessageChannelBufferFirstFragment: read failed (%"
     225                 :                 NACL_PRIdS").\n",
     226                 :                 imc_ret);
     227              18 :     return 0;
     228                 :   }
     229             237 :   NaClSrpcLog(3,
     230                 :               "MessageChannelBufferFirstFragment: buffered message: "
     231                 :               "bytes %"NACL_PRIdS", descs %"NACL_PRIuS".\n",
     232                 :               imc_ret,
     233                 :               (size_t) buffer_header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH);
     234             237 :   channel->byte_count = imc_ret;
     235             237 :   channel->desc_count = buffer_header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH;
     236             237 :   return 1;
     237             255 : }
     238                 : 
     239                 : /*
     240                 :  * Read from channel's buffer.
     241                 :  */
     242            1729 : static ssize_t MessageChannelBufferRead(struct NaClSrpcMessageChannel* channel,
     243            1729 :                                         NaClSrpcMessageHeader* header,
     244            1729 :                                         int peeking) {
     245            1729 :   size_t i;
     246            1729 :   size_t byte_count = 0;
     247            1729 :   size_t iov_read_size;
     248            1729 :   size_t descv_read_count;
     249                 : 
     250                 :   /*
     251                 :    * If there are no bytes or descriptors in the buffer, fill the buffer
     252                 :    * by reading the first fragment.
     253                 :    */
     254            2988 :   if (channel->byte_count == 0 && channel->desc_count == 0) {
     255            1259 :     if (!peeking) {
     256                 :       /* A read with an empty buffer just reads. */
     257             997 :       return ImcRecvmsg(channel->desc.raw_desc, header, 0);
     258                 :     }
     259                 :     /* Peeking needs to read the first fragment into the buffer. */
     260             255 :     if (!MessageChannelBufferFirstFragment(channel)) {
     261              18 :       NaClSrpcLog(3,
     262                 :                   "MessageChannelBufferRead: couldn't buffer.\n");
     263              18 :       return -1;
     264                 :     }
     265             237 :   }
     266             707 :   header->flags = 0;
     267             707 :   NaClSrpcLog(3,
     268                 :               "MessageChannelBufferRead: channel->byte_count=%"NACL_PRIuS".\n",
     269                 :               channel->byte_count);
     270            6178 :   for (i = 0; i < header->iov_length; ++i) {
     271            2805 :     NaClSrpcLog(3,
     272                 :                 "MessageChannelBufferRead: bytes %"NACL_PRIuS" chan %"
     273                 :                 NACL_PRIuS".\n",
     274                 :                 byte_count,
     275                 :                 channel->byte_count);
     276            2805 :     if (channel->byte_count < byte_count) {
     277               0 :       NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     278                 :                   "MessageChannelBufferRead: overflow.\n");
     279               0 :       return -1;
     280                 :     }
     281                 :     iov_read_size =
     282            2805 :         size_min(channel->byte_count - byte_count, header->iov[i].length);
     283            2805 :     if (SIZE_T_MAX - byte_count < iov_read_size) {
     284               0 :       NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     285                 :                   "MessageChannelBufferRead: overflow.\n");
     286               0 :       return -1;
     287                 :     }
     288            8415 :     memcpy(header->iov[i].base, channel->bytes + byte_count, iov_read_size);
     289            2805 :     byte_count += iov_read_size;
     290            2805 :     if (byte_count == channel->byte_count) {
     291                 :       /* We have read the entire contents of the buffer. */
     292             423 :       NaClSrpcLog(3,
     293                 :                   "MessageChannelBufferRead: break\n");
     294             423 :       break;
     295                 :     }
     296            2382 :   }
     297             707 :   if (byte_count < channel->byte_count) {
     298             284 :     header->flags |= NACL_ABI_RECVMSG_DATA_TRUNCATED;
     299             284 :   }
     300                 :   descv_read_count =
     301             707 :       size_min(channel->desc_count,
     302                 :                header->NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH);
     303                 :   /* channel->desc_count <= NACL_ABI_SIZE_T_MAX, so casts are safe. */
     304             707 :   if (SIZE_T_MAX / sizeof(NaClSrpcMessageDesc) < descv_read_count) {
     305                 :     /* Descriptor descv_read_count * sizeof would overflow. */
     306               0 :     return -1;
     307                 :   }
     308            2121 :   memcpy(header->NACL_SRPC_MESSAGE_HEADER_DESCV,
     309                 :          channel->descs,
     310                 :          descv_read_count * sizeof(NaClSrpcMessageDesc));
     311             707 :   header->NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = (nacl_abi_size_t)
     312                 :       descv_read_count;
     313             707 :   if (descv_read_count < channel->desc_count) {
     314              64 :     header->flags |= NACL_ABI_RECVMSG_DESC_TRUNCATED;
     315              64 :   }
     316                 :   /* Reading clears the fragment from the buffer. */
     317             707 :   if (!peeking) {
     318             236 :     channel->byte_count = 0;
     319             236 :     channel->desc_count = 0;
     320             236 :   }
     321             707 :   return (ssize_t) byte_count;
     322            1722 : }
     323                 : 
     324           32955 : static ssize_t IovTotalBytes(const struct NaClImcMsgIoVec* iov,
     325           32955 :                              size_t iov_length,
     326           32955 :                              size_t entries_to_skip) {
     327           32955 :   size_t i;
     328           32955 :   size_t byte_count = 0;
     329          178296 :   for (i = entries_to_skip; i < iov_length; ++i) {
     330           56193 :     if (SIZE_T_MAX - iov[i].length < byte_count) {
     331               0 :       return -1;
     332                 :     }
     333           56193 :     byte_count += iov[i].length;
     334           56193 :   }
     335                 :   /* Clamp the result to be representable as a nacl_abi_ssize_t. */
     336           32955 :   if (NACL_ABI_SSIZE_T_MAX < byte_count) {
     337               0 :     return -1;
     338                 :   }
     339           32955 :   return (ssize_t) byte_count;
     340           32955 : }
     341                 : 
     342           29992 : static ssize_t HeaderTotalBytes(const NaClSrpcMessageHeader* header,
     343           29992 :                                 size_t entries_to_skip) {
     344           29992 :   return IovTotalBytes(header->iov, header->iov_length, entries_to_skip);
     345                 : }
     346                 : 
     347            9421 : static int ComputeFragmentSizes(const NaClSrpcMessageHeader* header,
     348            9421 :                                 enum FragmentPosition fragment_position,
     349            9421 :                                 LengthHeader* fragment_size) {
     350            9421 :   size_t byte_count;
     351            9421 :   size_t max_user_bytes;
     352                 : 
     353            9421 :   if (0 == NaClSrpcMaxImcSendmsgSize) {
     354               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     355                 :                 "ComputeFragmentSizes: NaClSrpcModuleInit not called.\n");
     356               0 :     return 0;
     357                 :   }
     358                 :   /* NaClSrpcMaxImcSendmsgSize is guaranteed to to avoid underflow. */
     359            9421 :   max_user_bytes =
     360                 :       NaClSrpcMaxImcSendmsgSize - kFragmentOverhead[fragment_position];
     361                 :   byte_count = (size_t)
     362            9421 :       HeaderTotalBytes(header, kFragmentHeaderCount[fragment_position]);
     363            9421 :   if (-1 == (ssize_t) byte_count) {
     364               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     365                 :                 "ComputeFragmentSizes: byte_count was incorrect.\n");
     366               0 :     return 0;
     367                 :   }
     368                 :   /* NaClSrpcMaxImcSendmsgSize <= NACL_ABI_SIZE_T_MAX, so cast is safe. */
     369                 :   fragment_size->byte_count = (nacl_abi_size_t)
     370            9421 :       size_min(byte_count, max_user_bytes);
     371                 :   /* SRPC_DESC_MAX <= NACL_ABI_SIZE_T_MAX, so cast is safe. */
     372                 :   fragment_size->desc_count = (nacl_abi_size_t)
     373            9421 :       size_min(SRPC_DESC_MAX, header->NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH);
     374            9421 :   return 1;
     375            9421 : }
     376                 : 
     377                 : /*
     378                 :  * Send and receive destructively update the iov.  This builds a copy that
     379                 :  * can be used to destructively update, including adding the entries that
     380                 :  * are prepended for message lengths.
     381                 :  */
     382            2963 : static struct NaClImcMsgIoVec* CopyAndAddIovs(const struct NaClImcMsgIoVec* iov,
     383            2963 :                                               size_t iov_length,
     384            2963 :                                               size_t extra_entries) {
     385            2963 :   struct NaClImcMsgIoVec* copy;
     386                 : 
     387                 :   /* Check for arithmetic overflows. */
     388            5926 :   if (SIZE_T_MAX - iov_length < extra_entries ||
     389                 :       SIZE_T_MAX / sizeof *iov < iov_length + extra_entries) {
     390               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     391                 :                 "CopyAndAddIovs: overflows.\n");
     392               0 :     return NULL;
     393                 :   }
     394                 :   /* Check for total bytes exceeding NACL_ABI_SSIZE_T_MAX. */
     395            2963 :   if (-1 == IovTotalBytes(iov, iov_length, extra_entries)) {
     396               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     397                 :                 "CopyAndAddIovs: total bytes overflows.\n");
     398               0 :     return NULL;
     399                 :   }
     400                 :   /* Copy the iov, adding extra_entries elements. */
     401            2963 :   copy = (struct NaClImcMsgIoVec*) malloc((iov_length + extra_entries) *
     402                 :                                           sizeof *iov);
     403            2963 :   if (NULL == copy) {
     404               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     405                 :                 "CopyAndAddIovs: copy malloc failed.\n");
     406               0 :     return NULL;
     407                 :   }
     408            8889 :   memcpy(copy + extra_entries, iov, iov_length * sizeof *iov);
     409            2963 :   return copy;
     410            2963 : }
     411                 : 
     412            9421 : static int BuildFragmentHeader(NaClSrpcMessageHeader* header,
     413            9421 :                                LengthHeader* fragment_size,
     414            9421 :                                size_t entries_to_skip,
     415            9421 :                                NaClSrpcMessageHeader* frag_hdr) {
     416            9421 :   size_t i;
     417            9421 :   size_t total_bytes = 0;
     418            9421 :   const size_t kMaxIovEntries = SIZE_T_MAX / sizeof *frag_hdr->iov;
     419                 : 
     420            9421 :   if (NACL_ABI_SIZE_T_MAX < header->iov_length) {
     421               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     422                 :                 "BuildFragmentHeader: iov_length too large.\n");
     423               0 :     return 0;
     424                 :   }
     425                 :   /* Copy the entire iovec, even though only part may be used. */
     426            9421 :   frag_hdr->iov_length = header->iov_length;
     427            9421 :   if (kMaxIovEntries < header->iov_length) {
     428               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     429                 :                 "BuildFragmentHeader: iov_length > kMaxIovEntries.\n");
     430               0 :     return 0;
     431                 :   }
     432                 :   frag_hdr->iov = (struct NaClImcMsgIoVec*)
     433            9421 :       malloc(header->iov_length * sizeof *frag_hdr->iov);
     434            9421 :   if (frag_hdr->iov == NULL) {
     435               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     436                 :                 "BuildFragmentHeader: iov malloc failed.\n");
     437               0 :     return 0;
     438                 :   }
     439           28263 :   memcpy(frag_hdr->iov,
     440                 :          header->iov,
     441                 :          frag_hdr->iov_length * sizeof *frag_hdr->iov);
     442                 :   /* Update the iov[i].length entries. */
     443           39240 :   for (i = entries_to_skip; i < header->iov_length; ++i) {
     444           10199 :     size_t bytes_this_iov =
     445           10199 :         size_min(fragment_size->byte_count - total_bytes,
     446                 :                  frag_hdr->iov[i].length);
     447           10199 :     if (bytes_this_iov == 0) {
     448                 :       /* header->iov_length was checked at entry to make this safe. */
     449             192 :       frag_hdr->iov_length = (nacl_abi_size_t) i;
     450             192 :     }
     451           10199 :     frag_hdr->iov[i].length = bytes_this_iov;
     452                 :     /* Ensure that total_bytes increment doesn't overflow. */
     453           10199 :     if (SIZE_T_MAX - bytes_this_iov < total_bytes) {
     454               0 :       NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     455                 :                   "BuildFragmentHeader: total bytes overflows.\n");
     456               0 :       return 0;
     457                 :     }
     458           10199 :     total_bytes += bytes_this_iov;
     459           10199 :   }
     460            9421 :   frag_hdr->NACL_SRPC_MESSAGE_HEADER_DESCV =
     461                 :       header->NACL_SRPC_MESSAGE_HEADER_DESCV;
     462            9421 :   frag_hdr->NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = fragment_size->desc_count;
     463            9421 :   return 1;
     464            9421 : }
     465                 : 
     466           18841 : static void ConsumeFragment(NaClSrpcMessageHeader* header,
     467           18841 :                             LengthHeader* fragment_size,
     468           18841 :                             size_t guaranteed_entries) {
     469           18841 :   size_t descs_read;
     470                 :   /*
     471                 :    * The caller has already checked that the number of bytes read is sufficient
     472                 :    * to ensure that the first "guaranteed_entries" iov entries were satisfied.
     473                 :    * guaranteed_entries is passed as a constant 1 or 2, so cast is safe.
     474                 :    */
     475           18841 :   header->iov += (nacl_abi_size_t) guaranteed_entries;
     476           18841 :   header->iov_length -= (nacl_abi_size_t) guaranteed_entries;
     477                 :   /* Update to reflect the fragment's descriptors that were consumed. */
     478                 :   descs_read =
     479           18841 :       size_min(fragment_size->desc_count,
     480                 :                header->NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH);
     481                 :   /* Post-condition: descs_read <= NACL_ABI_SIZE_T_MAX. */
     482           18841 :   header->NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH -= (nacl_abi_size_t) descs_read;
     483           18841 :   header->NACL_SRPC_MESSAGE_HEADER_DESCV += (nacl_abi_size_t) descs_read;
     484           18841 :   fragment_size->desc_count -= (nacl_abi_size_t) descs_read;
     485                 :   /*
     486                 :    * Update the header and iov vector to reflect which entries are already
     487                 :    * satisfied.
     488                 :    */
     489           61166 :   while ((header->iov_length > 0) && (fragment_size->byte_count > 0)) {
     490           19922 :     size_t bytes_for_this_entry;
     491                 :     bytes_for_this_entry =
     492           19922 :         size_min(header->iov[0].length, fragment_size->byte_count);
     493                 :     /* Post-condition: bytes_for_this_entry <= NACL_ABI_SIZE_T_MAX. */
     494           19922 :     header->iov[0].length -= (nacl_abi_size_t) bytes_for_this_entry;
     495           19922 :     fragment_size->byte_count -= (nacl_abi_size_t) bytes_for_this_entry;
     496           19922 :     if (header->iov[0].length > 0) {
     497                 :       /* The fragment was exhausted, but didn't satisfy this iov entry. */
     498           16360 :       header->iov[0].base = (char*) header->iov[0].base + bytes_for_this_entry;
     499           16360 :       break;
     500                 :     }
     501                 :     /* This iov entry was satisfied. Remove it from the vector. */
     502            3562 :     header->iov++;
     503            3562 :     header->iov_length--;
     504            3562 :   }
     505           18841 :   if (fragment_size->byte_count > 0) {
     506               3 :     header->flags |= NACL_ABI_RECVMSG_DATA_TRUNCATED;
     507               3 :   }
     508           18841 :   if (fragment_size->desc_count > 0) {
     509               2 :     header->flags |= NACL_ABI_RECVMSG_DESC_TRUNCATED;
     510               2 :   }
     511           18841 : }
     512                 : 
     513            9890 : static int32_t FragmentLengthIsSane(LengthHeader* fragment_size,
     514            9890 :                                     size_t bytes_received,
     515            9890 :                                     size_t descs_received) {
     516                 :   /*
     517                 :    * bytes_received and descs_received are dependent on the message headers
     518                 :    * passed in from the client.  The client can request fewer than are present
     519                 :    * in the fragment.
     520                 :    */
     521           19780 :   if (fragment_size->byte_count < bytes_received - FRAGMENT_OVERHEAD ||
     522                 :       fragment_size->desc_count < descs_received) {
     523               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     524                 :                 "FragmentLengthIsSane: Descriptor mismatch:"
     525                 :                 " bytes %"NACL_PRIuNACL_SIZE" < %"NACL_PRIuS
     526                 :                 " or descs %"NACL_PRIuNACL_SIZE" < %"NACL_PRIuS".\n",
     527                 :                 fragment_size->byte_count,
     528                 :                 (size_t) (bytes_received - FRAGMENT_OVERHEAD),
     529                 :                 fragment_size->desc_count,
     530                 :                 descs_received);
     531               0 :     return 0;
     532                 :   }
     533                 :   /*
     534                 :    * Every fragment needs to pass at least one byte or one desc.
     535                 :    * This ensures that each fragment is "making progress" towards finishing
     536                 :    * the total message.
     537                 :    */
     538            9898 :   if (fragment_size->byte_count == 0 && fragment_size->desc_count == 0) {
     539               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     540                 :                 "FragmentLengthIsSane: empty fragment. Terminating.\n");
     541               0 :     return 0;
     542                 :   }
     543            9890 :   return 1;
     544            9890 : }
     545                 : 
     546            1704 : static int32_t MessageLengthsAreSane(LengthHeader* total_size,
     547            1704 :                                      LengthHeader* fragment_size,
     548            1704 :                                      size_t bytes_received,
     549            1704 :                                      size_t descs_received) {
     550                 :   /*
     551                 :    * Empty messages are not allowed.
     552                 :    */
     553            1706 :   if (total_size->byte_count == 0 && total_size->desc_count == 0) {
     554               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     555                 :                 "MessageLengthsAreSane: Descriptor mismatch:"
     556                 :                 " bytes %"NACL_PRIdNACL_SIZE" == 0 or descs %"
     557                 :                 NACL_PRIdNACL_SIZE" == 0.\n",
     558                 :                 fragment_size->byte_count,
     559                 :                 fragment_size->desc_count);
     560               0 :     return 0;
     561                 :   }
     562                 :   /*
     563                 :    * The first fragment must constitute a subset (not necessarily proper)
     564                 :    * of the total message.
     565                 :    */
     566            3408 :   if (fragment_size->byte_count > total_size->byte_count ||
     567                 :       fragment_size->desc_count > total_size->desc_count) {
     568               1 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     569                 :                 "MessageLengthsAreSane: Descriptor mismatch:"
     570                 :                 " bytes %"NACL_PRIdNACL_SIZE" > %"NACL_PRIdNACL_SIZE
     571                 :                 " or descs %"NACL_PRIdNACL_SIZE" > %"NACL_PRIdNACL_SIZE".\n",
     572                 :                 fragment_size->byte_count,
     573                 :                 total_size->byte_count,
     574                 :                 fragment_size->desc_count,
     575                 :                 total_size->desc_count);
     576               1 :     return 0;
     577                 :   }
     578                 :   /*
     579                 :    * And the first fragment must be correct.
     580                 :    * Decrement bytes_received to remove the total_size header.
     581                 :    */
     582            1703 :   return FragmentLengthIsSane(fragment_size,
     583                 :                               bytes_received - FRAGMENT_OVERHEAD,
     584                 :                               descs_received);
     585            1704 : }
     586                 : 
     587              18 : static ssize_t ErrnoFromImcRet(ssize_t imc_ret) {
     588              18 :   if (0 > imc_ret) {
     589              18 :     return imc_ret;
     590                 :   } else {
     591               0 :     return -NACL_ABI_EIO;
     592                 :   }
     593              18 : }
     594                 : 
     595                 : /*
     596                 :  * Peek a message from channel.  Reads the first fragment of the message and
     597                 :  * leaves it available for future calls to Peek or Receive.
     598                 :  */
     599             496 : ssize_t NaClSrpcMessageChannelPeek(struct NaClSrpcMessageChannel* channel,
     600             496 :                                    NaClSrpcMessageHeader* header) {
     601                 :   /*
     602                 :    * TODO(sehr): Most of this function is common with Receive.
     603                 :    * Find a way to merge them.
     604                 :    */
     605             496 :   struct NaClImcMsgIoVec* iovec = NULL;
     606             496 :   NaClSrpcMessageHeader header_copy;
     607             496 :   LengthHeader total_size;
     608             496 :   LengthHeader fragment_size;
     609             496 :   ssize_t imc_ret;
     610             496 :   ssize_t retval = -NACL_ABI_EINVAL;
     611                 : 
     612                 :   /* Append the fragment headers to the iov. */
     613             496 :   iovec = CopyAndAddIovs(header->iov, header->iov_length, 2);
     614             496 :   if (NULL == iovec) {
     615               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     616                 :                 "NaClSrpcMessageChannelPeek: CopyAndAddIovs failed.\n");
     617               0 :     return -1;
     618                 :   }
     619             496 :   header_copy.iov = iovec;
     620             496 :   header_copy.iov_length = header->iov_length + 2;
     621             496 :   header_copy.NACL_SRPC_MESSAGE_HEADER_DESCV =
     622                 :       header->NACL_SRPC_MESSAGE_HEADER_DESCV;
     623                 :   /* SRPC_DESC_MAX <= NACL_ABI_SIZE_T_MAX, so the cast is safe. */
     624                 :   header_copy.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = (nacl_abi_size_t)
     625             496 :       size_min(SRPC_DESC_MAX, header->NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH);
     626             496 :   header_copy.iov[0].base = &total_size;
     627             496 :   header_copy.iov[0].length = sizeof total_size;
     628             496 :   header_copy.iov[1].base = &fragment_size;
     629             496 :   header_copy.iov[1].length = sizeof fragment_size;
     630             496 :   header_copy.flags = 0;
     631             496 :   if (-1 == HeaderTotalBytes(&header_copy, 0)) {
     632               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     633                 :                 "NaClSrpcMessageChannelPeek: header size overflow.\n");
     634               0 :     goto done;
     635                 :   }
     636             489 :   NaClSrpcLog(3,
     637                 :               "NaClSrpcMessageChannelPeek: read message bytes %"
     638                 :               NACL_PRIuS", descs %"NACL_PRIuS".\n",
     639                 :               channel->byte_count,
     640                 :               channel->desc_count);
     641             489 :   imc_ret = MessageChannelBufferRead(channel, &header_copy, 1);
     642             489 :   if (imc_ret < (ssize_t) kFragmentOverhead[FIRST_FRAGMENT]) {
     643              18 :     NaClSrpcLog(3,
     644                 :                 "NaClSrpcMessageChannelPeek: read failed (%"NACL_PRIdS").\n",
     645                 :                 imc_ret);
     646              18 :     retval = ErrnoFromImcRet(imc_ret);
     647              18 :     goto done;
     648                 :   }
     649             471 :   header->flags = header_copy.flags;
     650             471 :   header->NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH =
     651                 :       header_copy.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH;
     652             471 :   NaClSrpcLog(3,
     653                 :               "NaClSrpcMessageChannelPeek: flags %x.\n",
     654                 :               header->flags);
     655             471 :   if (!MessageLengthsAreSane(
     656                 :            &total_size,
     657                 :            &fragment_size,
     658                 :            (size_t) imc_ret,
     659                 :            header_copy.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH)) {
     660               1 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     661                 :                 "NaClSrpcMessageChannelPeek: message length mismatch.\n");
     662               1 :     retval = -NACL_ABI_EIO;
     663               1 :     goto done;
     664                 :   }
     665                 :   /* Comparison above guarantees no underflow. */
     666             470 :   retval = imc_ret - kFragmentOverhead[FIRST_FRAGMENT];
     667                 : 
     668                 :  done:
     669             489 :   free(iovec);
     670             489 :   return retval;
     671             489 : }
     672                 : 
     673                 : /*
     674                 :  * Receive a message from channel.  On success it returns the number of
     675                 :  * bytes read; otherwise, returns -1.
     676                 :  */
     677            1233 : ssize_t NaClSrpcMessageChannelReceive(struct NaClSrpcMessageChannel* channel,
     678            1233 :                                       NaClSrpcMessageHeader* header) {
     679                 :   /*
     680                 :    * TODO(sehr): A large prefix of this function is common with Peek.
     681                 :    * Find a way to merge them.
     682                 :    */
     683            1233 :   ssize_t imc_ret = -1;
     684            1233 :   NaClSrpcMessageHeader header_copy;
     685            1233 :   struct NaClImcMsgIoVec* iovec = NULL;
     686            1233 :   LengthHeader total_size;
     687            1233 :   LengthHeader fragment_size;
     688            1233 :   LengthHeader processed_size;
     689            1233 :   size_t bytes_received;
     690            1233 :   size_t descs_received;
     691            1233 :   ssize_t retval = -NACL_ABI_EINVAL;
     692                 : 
     693            1233 :   NaClSrpcLog(3, "NaClSrpcMessageChannelReceive: waiting for message.\n");
     694                 :   /*
     695                 :    * The first fragment consists of two LengthHeaders and a fraction of the
     696                 :    * bytes (starting at 0) and the fraction of descs (starting at 0).
     697                 :    */
     698            1233 :   iovec = CopyAndAddIovs(header->iov, header->iov_length, 2);
     699            1233 :   if (NULL == iovec) {
     700               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     701                 :                 "NaClSrpcMessageChannelReceive: CopyAndAddIovs failed.\n");
     702               0 :     goto done;
     703                 :   }
     704            1233 :   header_copy.iov = iovec;
     705            1233 :   header_copy.iov_length = header->iov_length + 2;
     706            1233 :   header_copy.NACL_SRPC_MESSAGE_HEADER_DESCV =
     707                 :       header->NACL_SRPC_MESSAGE_HEADER_DESCV;
     708                 :   /* SRPC_DESC_MAX <= NACL_ABI_SIZE_T_MAX, so the cast is safe. */
     709                 :   header_copy.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = (nacl_abi_size_t)
     710            1233 :       size_min(SRPC_DESC_MAX, header->NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH);
     711            1233 :   header_copy.iov[0].base = &total_size;
     712            1233 :   header_copy.iov[0].length = sizeof total_size;
     713            1233 :   header_copy.iov[1].base = &fragment_size;
     714            1233 :   header_copy.iov[1].length = sizeof fragment_size;
     715            1233 :   header_copy.flags = 0;
     716            1233 :   if (-1 == HeaderTotalBytes(&header_copy, 0)) {
     717               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     718                 :                 "NaClSrpcMessageChannelReceive: header size overflow.\n");
     719               0 :     goto done;
     720                 :   }
     721                 :   /*
     722                 :    * The message receive should return at least
     723                 :    * kFragmentOverhead[FIRST_FRAGMENT] bytes.
     724                 :    */
     725            1233 :   imc_ret = MessageChannelBufferRead(channel, &header_copy, 0);
     726            1233 :   if (imc_ret < (ssize_t) kFragmentOverhead[FIRST_FRAGMENT]) {
     727               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     728                 :                 "NaClSrpcMessageChannelReceive: read failed (%"NACL_PRIdS").\n",
     729                 :                 imc_ret);
     730               0 :     retval = ErrnoFromImcRet(imc_ret);
     731               0 :     goto done;
     732                 :   }
     733                 :   /* Comparison above guarantees no underflow. */
     734            1233 :   bytes_received = imc_ret - kFragmentOverhead[FIRST_FRAGMENT];
     735            1233 :   descs_received = header_copy.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH;
     736            1233 :   if (!MessageLengthsAreSane(
     737                 :           &total_size,
     738                 :           &fragment_size,
     739                 :           (size_t) imc_ret,
     740                 :           header_copy.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH)) {
     741               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     742                 :                 "NaClSrpcMessageChannelReceive:"
     743                 :                 " first fragment descriptor check failed.\n");
     744               0 :     retval = -NACL_ABI_EIO;
     745               0 :     goto done;
     746                 :   }
     747            1233 :   NaClSrpcLog(3,
     748                 :               "NaClSrpcMessageChannelReceive:"
     749                 :               " new message, bytes %"NACL_PRIdNACL_SIZE
     750                 :               ", descs %"NACL_PRIdNACL_SIZE".\n",
     751                 :               total_size.byte_count,
     752                 :               total_size.desc_count);
     753            1233 :   NaClSrpcLog(3,
     754                 :               "NaClSrpcMessageChannelReceive:"
     755                 :               " first fragment, bytes %"NACL_PRIdNACL_SIZE
     756                 :               ", descs %"NACL_PRIdNACL_SIZE".\n",
     757                 :               fragment_size.byte_count,
     758                 :               fragment_size.desc_count);
     759            1233 :   processed_size = fragment_size;
     760            1233 :   ConsumeFragment(&header_copy, &fragment_size, 2);
     761                 :   /*
     762                 :    * Get the remaining fragments.
     763                 :    */
     764           21312 :   while (processed_size.byte_count < total_size.byte_count ||
     765                 :          processed_size.desc_count < total_size.desc_count) {
     766                 :     /*
     767                 :      * The non-first fragments consist of a single LengthHeader and a
     768                 :      * portion of the remaining iov entries and descv entries.  We add the
     769                 :      * fragment length descriptor to the preceding iov entry, which is safe,
     770                 :      * because we know that ConsumeFragment always consumes at least the
     771                 :      * fragment length descriptor from last time.
     772                 :      */
     773            8187 :     header_copy.iov = header_copy.iov - 1;
     774            8187 :     header_copy.iov_length = header_copy.iov_length + 1;
     775            8187 :     header_copy.iov[0].base = &fragment_size;
     776            8187 :     header_copy.iov[0].length = sizeof fragment_size;
     777            8187 :     header_copy.NACL_SRPC_MESSAGE_HEADER_DESCV =
     778                 :         header->NACL_SRPC_MESSAGE_HEADER_DESCV + descs_received;
     779                 :     header_copy.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = (nacl_abi_size_t)
     780            8187 :         size_min(SRPC_DESC_MAX,
     781                 :                  (header->NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH -
     782                 :                   descs_received));
     783            8187 :     if (-1 == HeaderTotalBytes(&header_copy, 0)) {
     784               0 :       NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     785                 :                   "NaClSrpcMessageChannelReceive: header size overflow.\n");
     786               0 :       goto done;
     787                 :     }
     788                 :     /*
     789                 :      * The message receive should return at least
     790                 :      * kFragmentOverhead[LATER_FRAGMENT] bytes.  This is needed to make sure
     791                 :      * that we can correctly maintain the index into bytes and descs.
     792                 :      */
     793            8187 :     imc_ret = ImcRecvmsg(channel->desc.raw_desc, &header_copy, 0);
     794            8187 :     if (imc_ret < (ssize_t) kFragmentOverhead[LATER_FRAGMENT]) {
     795               0 :       NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     796                 :                   "NaClSrpcMessageChannelReceive: read failed (%"
     797                 :                   NACL_PRIdS").\n",
     798                 :                   imc_ret);
     799               0 :       retval = ErrnoFromImcRet(imc_ret);
     800               0 :       goto done;
     801                 :     }
     802                 :     /* Comparison above guarantees no underflow. */
     803            8187 :     bytes_received += imc_ret - kFragmentOverhead[LATER_FRAGMENT];
     804            8187 :     descs_received += header_copy.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH;
     805            8187 :     if (!FragmentLengthIsSane(
     806                 :             &fragment_size,
     807                 :             (size_t) imc_ret,
     808                 :             header_copy.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH)) {
     809               0 :       NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     810                 :                   "NaClSrpcMessageChannelReceive:"
     811                 :                   " other fragment descriptor check failed.\n");
     812               0 :       retval = -NACL_ABI_EIO;
     813               0 :       goto done;
     814                 :     }
     815            8187 :     NaClSrpcLog(3,
     816                 :                 "NaClSrpcMessageChannelReceive:"
     817                 :                 " next fragment, bytes %"NACL_PRIdNACL_SIZE
     818                 :                 ", descs %"NACL_PRIdNACL_SIZE".\n",
     819                 :                 fragment_size.byte_count,
     820                 :                 fragment_size.desc_count);
     821            8187 :     processed_size.byte_count += fragment_size.byte_count;
     822            8187 :     processed_size.desc_count += fragment_size.desc_count;
     823            8187 :     ConsumeFragment(&header_copy, &fragment_size, 1);
     824            8187 :   }
     825            1233 :   NaClSrpcLog(3,
     826                 :               "NaClSrpcMessageChannelReceive:"
     827                 :               " succeeded, read %"NACL_PRIuS" bytes and %"
     828                 :               NACL_PRIdNACL_SIZE" descs.\n",
     829                 :               bytes_received,
     830                 :               processed_size.desc_count);
     831            1233 :   retval = (ssize_t) bytes_received;
     832            1233 :   header->NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH =
     833                 :       (nacl_abi_size_t) descs_received;
     834            1233 :   header->flags = header_copy.flags;
     835                 : 
     836                 :  done:
     837            1233 :   free(iovec);
     838            1233 :   return retval;
     839                 : }
     840                 : 
     841                 : /*
     842                 :  * Sends message over the channel. It returns 1 if successful, or 0 otherwise.
     843                 :  */
     844            1234 : ssize_t NaClSrpcMessageChannelSend(struct NaClSrpcMessageChannel* channel,
     845            1234 :                                    const NaClSrpcMessageHeader* header) {
     846            1234 :   ssize_t imc_ret;
     847            1234 :   struct NaClImcMsgIoVec* iovec = NULL;
     848            1234 :   NaClSrpcMessageHeader remaining;
     849            1234 :   NaClSrpcMessageHeader frag_hdr;
     850            1234 :   LengthHeader total_size;
     851            1234 :   LengthHeader fragment_size;
     852            1234 :   size_t expected_bytes_sent;
     853            1234 :   ssize_t retval = -NACL_ABI_EINVAL;
     854                 : 
     855            1234 :   iovec = CopyAndAddIovs(header->iov, header->iov_length, 2);
     856            1234 :   if (NULL == iovec) {
     857               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     858                 :                 "NaClSrpcMessageChannelSend: CopyAndAddIovs failed.\n");
     859               0 :     goto done;
     860                 :   }
     861            1234 :   remaining.iov = iovec;
     862            1234 :   remaining.iov_length = header->iov_length + 2;
     863            1234 :   remaining.NACL_SRPC_MESSAGE_HEADER_DESCV =
     864                 :       header->NACL_SRPC_MESSAGE_HEADER_DESCV;
     865            1234 :   remaining.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH =
     866                 :       header->NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH;
     867            1234 :   remaining.iov[0].base = &total_size;
     868            1234 :   remaining.iov[0].length = sizeof total_size;
     869            1234 :   remaining.iov[1].base = &fragment_size;
     870            1234 :   remaining.iov[1].length = sizeof fragment_size;
     871            1234 :   if (-1 == HeaderTotalBytes(&remaining, 0)) {
     872               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     873                 :                 "NaClSrpcMessageChannelSend: header size overflow.\n");
     874               0 :     goto done;
     875                 :   }
     876                 :   /*
     877                 :    * Send the first (possibly only) fragment.
     878                 :    * HeaderTotalBytes returns -1 if the total is greater than
     879                 :    * NACL_ABI_SSIZE_T_MAX.
     880                 :    */
     881            1234 :   total_size.byte_count = (nacl_abi_size_t) HeaderTotalBytes(&remaining, 2);
     882            1234 :   if (-1 == (nacl_abi_ssize_t) total_size.byte_count) {
     883               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     884                 :                 "NaClSrpcMessageChannelSend: HeaderTotalBytes failed.\n");
     885               0 :     goto done;
     886                 :   }
     887            1234 :   total_size.desc_count = header->NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH;
     888                 :   /*
     889                 :    * Compute the first fragment's message descriptor and fragment descriptor,
     890                 :    * limiting the bytes and descriptors sent in the first fragment to preset
     891                 :    * amounts.
     892                 :    */
     893            1234 :   if (!ComputeFragmentSizes(&remaining, FIRST_FRAGMENT, &fragment_size)) {
     894               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     895                 :                 "NaClSrpcMessageChannelSend:"
     896                 :                 " first ComputeFragmentSize failed.\n");
     897               0 :     goto done;
     898                 :   }
     899            1234 :   NaClSrpcLog(3,
     900                 :               "NaClSrpcMessageChannelSend: new message, bytes %"
     901                 :               NACL_PRIdNACL_SIZE", descs %"NACL_PRIdNACL_SIZE".\n",
     902                 :               total_size.byte_count,
     903                 :               total_size.desc_count);
     904            1234 :   NaClSrpcLog(3,
     905                 :               "NaClSrpcMessageChannelSend: first fragment, bytes %"
     906                 :               NACL_PRIdNACL_SIZE", descs %"NACL_PRIdNACL_SIZE".\n",
     907                 :               fragment_size.byte_count,
     908                 :               fragment_size.desc_count);
     909            1234 :   if (NACL_ABI_SSIZE_T_MAX - kFragmentOverhead[FIRST_FRAGMENT] <
     910                 :       fragment_size.byte_count) {
     911               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     912                 :                 "NaClSrpcMessageChannelSend:"
     913                 :                 " fragment size would cause overflow.\n");
     914               0 :     goto done;
     915                 :   }
     916            1234 :   expected_bytes_sent =
     917                 :       fragment_size.byte_count + kFragmentOverhead[FIRST_FRAGMENT];
     918            1234 :   if (expected_bytes_sent > NaClSrpcMaxImcSendmsgSize) {
     919               0 :     NaClSrpcLog(NACL_SRPC_LOG_FATAL,
     920                 :                 "NaClSrpcMessageChannelSend: expected bytes %"
     921                 :                 NACL_PRIuS" exceed maximum allowed %"NACL_PRIdNACL_SIZE"\n",
     922                 :                 expected_bytes_sent, NaClSrpcMaxImcSendmsgSize);
     923               0 :   }
     924            1234 :   if (!BuildFragmentHeader(&remaining, &fragment_size, 2, &frag_hdr)) {
     925               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     926                 :                 "NaClSrpcMessageChannelSend:"
     927                 :                 " could not build fragment header.\n");
     928               0 :     goto done;
     929                 :   }
     930                 :   /*
     931                 :    * The first message has at least three iov entries: one for the (message)
     932                 :    * total_size descriptor, one for the fragment_size descriptor, and at
     933                 :    * least one for the first fragment's bytes and descs.
     934                 :    */
     935            1234 :   imc_ret = ImcSendmsg(channel->desc.raw_desc, &frag_hdr, 0);
     936            1234 :   free(frag_hdr.iov);
     937            1234 :   if ((size_t) imc_ret != expected_bytes_sent) {
     938               0 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     939                 :                 "NaClSrpcMessageChannelSend: first send failed, %"
     940                 :                 NACL_PRIuS" != %"NACL_PRIdS".\n",
     941                 :                 expected_bytes_sent,
     942                 :                 imc_ret);
     943               0 :     retval = ErrnoFromImcRet(imc_ret);
     944               0 :     goto done;
     945                 :   }
     946            1234 :   ConsumeFragment(&remaining, &fragment_size, 2);
     947            1234 :   NaClSrpcLog(3,
     948                 :               "NaClSrpcMessageChannelSend: first send succeeded.\n");
     949                 :   /*
     950                 :    * Each subsequent fragment contains the bytes starting at next_byte and
     951                 :    * the descs starting at next_desc.
     952                 :    */
     953           21316 :   while (remaining.iov_length > 0 ||
     954                 :          remaining.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH > 0) {
     955            8187 :     NaClSrpcMessageHeader frag_hdr;
     956                 :     /*
     957                 :      * Each subsequent message has two iov entries: one for the fragment_size
     958                 :      * descriptor, and one for the fragment's bytes and descs.
     959                 :      * We add the fragment length descriptor to the preceding iov entry,
     960                 :      * which is safe, because we know that ConsumeFragment always consumes
     961                 :      * at least the fragment length descriptor from last time.
     962                 :      */
     963            8187 :     remaining.iov = remaining.iov - 1;
     964            8187 :     remaining.iov_length = remaining.iov_length + 1;
     965            8187 :     remaining.iov[0].base = &fragment_size;
     966            8187 :     remaining.iov[0].length = sizeof fragment_size;
     967            8187 :     if (-1 == HeaderTotalBytes(&remaining, 0)) {
     968               0 :       NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     969                 :                   "NaClSrpcMessageChannelSend: header size overflow.\n");
     970               0 :       goto done;
     971                 :     }
     972                 :     /*
     973                 :      * The fragment sizes are again limited.
     974                 :      */
     975            8187 :     if (!ComputeFragmentSizes(&remaining, LATER_FRAGMENT, &fragment_size)) {
     976               0 :       NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     977                 :                   "NaClSrpcMessageChannelSend:"
     978                 :                   " other ComputeFragmentSize failed.\n");
     979               0 :       retval = -NACL_ABI_EIO;
     980               0 :       goto done;
     981                 :     }
     982            8187 :     NaClSrpcLog(3,
     983                 :                 "NaClSrpcMessageChannelSend: next fragment, bytes %"
     984                 :                 NACL_PRIdNACL_SIZE", descs %"NACL_PRIdNACL_SIZE".\n",
     985                 :                 fragment_size.byte_count,
     986                 :                 fragment_size.desc_count);
     987            8187 :     if (!BuildFragmentHeader(&remaining, &fragment_size, 1, &frag_hdr)) {
     988               0 :       NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     989                 :                   "NaClSrpcMessageChannelSend:"
     990                 :                   " could not build fragment header.\n");
     991               0 :       retval = -NACL_ABI_EIO;
     992               0 :       goto done;
     993                 :     }
     994                 :     /*
     995                 :      * Send the fragment.
     996                 :      */
     997            8187 :     if (NACL_ABI_SSIZE_T_MAX - kFragmentOverhead[LATER_FRAGMENT] <
     998                 :         fragment_size.byte_count) {
     999               0 :       NaClSrpcLog(NACL_SRPC_LOG_ERROR,
    1000                 :                   "NaClSrpcMessageChannelSend:"
    1001                 :                   " fragment size would cause overflow.\n");
    1002               0 :       goto done;
    1003                 :     }
    1004            8187 :     expected_bytes_sent =
    1005                 :         fragment_size.byte_count + kFragmentOverhead[LATER_FRAGMENT];
    1006            8187 :     if (expected_bytes_sent > NaClSrpcMaxImcSendmsgSize) {
    1007               0 :       NaClSrpcLog(NACL_SRPC_LOG_FATAL,
    1008                 :                   "NaClSrpcMessageChannelSend: expected bytes %"
    1009                 :                   NACL_PRIuS" exceed maximum allowed %"NACL_PRIdNACL_SIZE"\n",
    1010                 :                   expected_bytes_sent, NaClSrpcMaxImcSendmsgSize);
    1011               0 :     }
    1012            8187 :     imc_ret = ImcSendmsg(channel->desc.raw_desc, &frag_hdr, 0);
    1013            8187 :     free(frag_hdr.iov);
    1014            8187 :     if ((size_t) imc_ret != expected_bytes_sent) {
    1015               0 :       NaClSrpcLog(NACL_SRPC_LOG_ERROR,
    1016                 :                   "NaClSrpcMessageChannelSend: send error.\n");
    1017               0 :       retval = ErrnoFromImcRet(imc_ret);
    1018               0 :       goto done;
    1019                 :     }
    1020            8187 :     ConsumeFragment(&remaining, &fragment_size, 1);
    1021            8187 :   }
    1022            1234 :   NaClSrpcLog(3,
    1023                 :               "NaClSrpcMessageChannelSend: complete send, sent %"
    1024                 :               NACL_PRIdNACL_SIZE" bytes and %"NACL_PRIdNACL_SIZE" descs.\n",
    1025                 :               total_size.byte_count,
    1026                 :               total_size.desc_count);
    1027            1234 :   retval = (ssize_t) total_size.byte_count;
    1028                 : 
    1029                 :  done:
    1030            1234 :   free(iovec);
    1031            1234 :   return retval;
    1032                 : }

Generated by: LCOV version 1.7