LCOV - code coverage report
Current view: directory - src/shared/srpc - nacl_srpc_message.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 397 303 76.3 %
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                 : #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               3 : static size_t size_min(size_t a, size_t b) {
      47               3 :   if (a < b) {
      48               3 :     return a;
      49                 :   } else {
      50               3 :     return b;
      51                 :   }
      52               3 : }
      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                 : static ssize_t ImcSendmsg(NaClSrpcMessageDesc desc,
      90                 :                           const NaClSrpcMessageHeader* header,
      91               3 :                           int flags) {
      92               3 :   return NACL_VTBL(NaClDesc, desc)->SendMsg(desc, header, flags);
      93               3 : }
      94                 : 
      95                 : static ssize_t ImcRecvmsg(NaClSrpcMessageDesc desc,
      96                 :                           NaClSrpcMessageHeader* header,
      97               3 :                           int flags) {
      98                 :   /* Quota management is not supported in trusted SRPC. */
      99                 :   return NACL_VTBL(NaClDesc, desc)->RecvMsg(
     100               3 :       desc, header, flags, (struct NaClDescQuotaInterface *) NULL);
     101               3 : }
     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                 : static int PortableDescCtor(struct PortableDesc* self,
     114               3 :                             NaClSrpcMessageDesc desc) {
     115               3 :   if (kInvalidDesc == desc) {
     116               0 :     return 0;
     117                 :   }
     118                 : #ifdef __native_client__
     119                 :   self->raw_desc = desc;
     120                 : #else
     121               3 :   self->raw_desc = NaClDescRef(desc);
     122                 : #endif  /* __native_client__ */
     123               3 :   return 1;
     124               3 : }
     125                 : 
     126               3 : static void PortableDescDtor(struct PortableDesc* self) {
     127                 : #ifndef __native_client__
     128               3 :   NaClDescSafeUnref(self->raw_desc);
     129                 : #endif  /* __native_client__ */
     130               3 :   self->raw_desc = kInvalidDesc;
     131               3 : }
     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               3 :     NaClSrpcMessageDesc desc) {
     174               3 :   struct NaClSrpcMessageChannel* channel = NULL;
     175                 : 
     176               3 :   channel = (struct NaClSrpcMessageChannel*) malloc(sizeof *channel);
     177               3 :   if (NULL == channel) {
     178               0 :     return NULL;
     179                 :   }
     180               3 :   if (!PortableDescCtor(&channel->desc, desc)) {
     181               0 :     free(channel);
     182               0 :     return NULL;
     183                 :   }
     184               3 :   channel->byte_count = 0;
     185               3 :   channel->desc_count = 0;
     186               3 :   return channel;
     187               3 : }
     188                 : 
     189               3 : void NaClSrpcMessageChannelDelete(struct NaClSrpcMessageChannel* channel) {
     190               3 :   if (NULL != channel) {
     191               3 :     PortableDescDtor(&channel->desc);
     192               3 :     free(channel);
     193                 :   }
     194               3 : }
     195                 : 
     196                 : /*
     197                 :  * Read the next fragment of a message into channel's buffer.
     198                 :  */
     199                 : static uint32_t MessageChannelBufferFirstFragment(
     200               3 :     struct NaClSrpcMessageChannel* channel) {
     201               3 :   ssize_t imc_ret = -1;
     202                 :   NaClSrpcMessageHeader buffer_header;
     203                 :   struct NaClImcMsgIoVec iovec[1];
     204                 : 
     205                 :   NaClSrpcLog(3,
     206               3 :               "MessageChannelBufferFirstFragment: waiting for message.\n");
     207                 :   /* Read the entire first fragment into channel's buffer. */
     208               3 :   buffer_header.iov = iovec;
     209               3 :   buffer_header.iov_length = NACL_ARRAY_SIZE(iovec);
     210               3 :   buffer_header.NACL_SRPC_MESSAGE_HEADER_DESCV = channel->descs;
     211                 :   buffer_header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH =
     212               3 :       NACL_ARRAY_SIZE(channel->descs);
     213               3 :   buffer_header.iov[0].base = channel->bytes;
     214               3 :   buffer_header.iov[0].length = NACL_ARRAY_SIZE(channel->bytes);
     215               3 :   buffer_header.flags = 0;
     216                 :   /*
     217                 :    * The message receive should return at least
     218                 :    * kFragmentOverhead[FIRST_FRAGMENT] bytes.
     219                 :    */
     220               3 :   imc_ret = ImcRecvmsg(channel->desc.raw_desc, &buffer_header, 0);
     221                 :   if ((imc_ret < (ssize_t) kFragmentOverhead[FIRST_FRAGMENT]) ||
     222               3 :       (buffer_header.flags != 0)) {
     223                 :     NaClSrpcLog(3,
     224                 :                 "MessageChannelBufferFirstFragment: read failed (%"
     225                 :                 NACL_PRIdS").\n",
     226               2 :                 imc_ret);
     227               2 :     return 0;
     228                 :   }
     229                 :   NaClSrpcLog(3,
     230                 :               "MessageChannelBufferFirstFragment: buffered message: "
     231                 :               "bytes %"NACL_PRIdS", descs %"NACL_PRIuS".\n",
     232                 :               imc_ret,
     233               3 :               (size_t) buffer_header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH);
     234               3 :   channel->byte_count = imc_ret;
     235               3 :   channel->desc_count = buffer_header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH;
     236               3 :   return 1;
     237               3 : }
     238                 : 
     239                 : /*
     240                 :  * Read from channel's buffer.
     241                 :  */
     242                 : static ssize_t MessageChannelBufferRead(struct NaClSrpcMessageChannel* channel,
     243                 :                                         NaClSrpcMessageHeader* header,
     244               3 :                                         int peeking) {
     245                 :   size_t i;
     246               3 :   size_t byte_count = 0;
     247                 :   size_t iov_read_size;
     248                 :   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               3 :   if (channel->byte_count == 0 && channel->desc_count == 0) {
     255               3 :     if (!peeking) {
     256                 :       /* A read with an empty buffer just reads. */
     257               1 :       return ImcRecvmsg(channel->desc.raw_desc, header, 0);
     258                 :     }
     259                 :     /* Peeking needs to read the first fragment into the buffer. */
     260               3 :     if (!MessageChannelBufferFirstFragment(channel)) {
     261                 :       NaClSrpcLog(3,
     262               2 :                   "MessageChannelBufferRead: couldn't buffer.\n");
     263               2 :       return -1;
     264                 :     }
     265                 :   }
     266               3 :   header->flags = 0;
     267                 :   NaClSrpcLog(3,
     268                 :               "MessageChannelBufferRead: channel->byte_count=%"NACL_PRIuS".\n",
     269               3 :               channel->byte_count);
     270               3 :   for (i = 0; i < header->iov_length; ++i) {
     271                 :     NaClSrpcLog(3,
     272                 :                 "MessageChannelBufferRead: bytes %"NACL_PRIuS" chan %"
     273                 :                 NACL_PRIuS".\n",
     274                 :                 byte_count,
     275               3 :                 channel->byte_count);
     276               3 :     if (channel->byte_count < byte_count) {
     277                 :       NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     278               0 :                   "MessageChannelBufferRead: overflow.\n");
     279               0 :       return -1;
     280                 :     }
     281                 :     iov_read_size =
     282               3 :         size_min(channel->byte_count - byte_count, header->iov[i].length);
     283               3 :     if (SIZE_T_MAX - byte_count < iov_read_size) {
     284                 :       NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     285               0 :                   "MessageChannelBufferRead: overflow.\n");
     286               0 :       return -1;
     287                 :     }
     288               3 :     memcpy(header->iov[i].base, channel->bytes + byte_count, iov_read_size);
     289               3 :     byte_count += iov_read_size;
     290               3 :     if (byte_count == channel->byte_count) {
     291                 :       /* We have read the entire contents of the buffer. */
     292                 :       NaClSrpcLog(3,
     293               3 :                   "MessageChannelBufferRead: break\n");
     294               3 :       break;
     295                 :     }
     296               3 :   }
     297               3 :   if (byte_count < channel->byte_count) {
     298               3 :     header->flags |= NACL_ABI_RECVMSG_DATA_TRUNCATED;
     299                 :   }
     300                 :   descv_read_count =
     301                 :       size_min(channel->desc_count,
     302               3 :                header->NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH);
     303                 :   /* channel->desc_count <= NACL_ABI_SIZE_T_MAX, so casts are safe. */
     304               3 :   if (SIZE_T_MAX / sizeof(NaClSrpcMessageDesc) < descv_read_count) {
     305                 :     /* Descriptor descv_read_count * sizeof would overflow. */
     306               0 :     return -1;
     307                 :   }
     308                 :   memcpy(header->NACL_SRPC_MESSAGE_HEADER_DESCV,
     309                 :          channel->descs,
     310               3 :          descv_read_count * sizeof(NaClSrpcMessageDesc));
     311                 :   header->NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = (nacl_abi_size_t)
     312               3 :       descv_read_count;
     313               3 :   if (descv_read_count < channel->desc_count) {
     314               0 :     header->flags |= NACL_ABI_RECVMSG_DESC_TRUNCATED;
     315                 :   }
     316                 :   /* Reading clears the fragment from the buffer. */
     317               3 :   if (!peeking) {
     318               3 :     channel->byte_count = 0;
     319               3 :     channel->desc_count = 0;
     320                 :   }
     321               3 :   return (ssize_t) byte_count;
     322               3 : }
     323                 : 
     324                 : static ssize_t IovTotalBytes(const struct NaClImcMsgIoVec* iov,
     325                 :                              size_t iov_length,
     326               3 :                              size_t entries_to_skip) {
     327                 :   size_t i;
     328               3 :   size_t byte_count = 0;
     329               3 :   for (i = entries_to_skip; i < iov_length; ++i) {
     330               3 :     if (SIZE_T_MAX - iov[i].length < byte_count) {
     331               0 :       return -1;
     332                 :     }
     333               3 :     byte_count += iov[i].length;
     334               3 :   }
     335                 :   /* Clamp the result to be representable as a nacl_abi_ssize_t. */
     336               3 :   if (NACL_ABI_SSIZE_T_MAX < byte_count) {
     337               0 :     return -1;
     338                 :   }
     339               3 :   return (ssize_t) byte_count;
     340               3 : }
     341                 : 
     342                 : static ssize_t HeaderTotalBytes(const NaClSrpcMessageHeader* header,
     343               3 :                                 size_t entries_to_skip) {
     344               3 :   return IovTotalBytes(header->iov, header->iov_length, entries_to_skip);
     345               3 : }
     346                 : 
     347                 : static int ComputeFragmentSizes(const NaClSrpcMessageHeader* header,
     348                 :                                 enum FragmentPosition fragment_position,
     349               3 :                                 LengthHeader* fragment_size) {
     350                 :   size_t byte_count;
     351                 :   size_t max_user_bytes;
     352                 : 
     353               3 :   if (0 == NaClSrpcMaxImcSendmsgSize) {
     354                 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     355               0 :                 "ComputeFragmentSizes: NaClSrpcModuleInit not called.\n");
     356               0 :     return 0;
     357                 :   }
     358                 :   /* NaClSrpcMaxImcSendmsgSize is guaranteed to to avoid underflow. */
     359                 :   max_user_bytes =
     360               3 :       NaClSrpcMaxImcSendmsgSize - kFragmentOverhead[fragment_position];
     361                 :   byte_count = (size_t)
     362               3 :       HeaderTotalBytes(header, kFragmentHeaderCount[fragment_position]);
     363               3 :   if (-1 == (ssize_t) byte_count) {
     364                 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     365               0 :                 "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               3 :       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               3 :       size_min(SRPC_DESC_MAX, header->NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH);
     374               3 :   return 1;
     375               3 : }
     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                 : static struct NaClImcMsgIoVec* CopyAndAddIovs(const struct NaClImcMsgIoVec* iov,
     383                 :                                               size_t iov_length,
     384               3 :                                               size_t extra_entries) {
     385                 :   struct NaClImcMsgIoVec* copy;
     386                 : 
     387                 :   /* Check for arithmetic overflows. */
     388                 :   if (SIZE_T_MAX - iov_length < extra_entries ||
     389               3 :       SIZE_T_MAX / sizeof *iov < iov_length + extra_entries) {
     390                 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     391               0 :                 "CopyAndAddIovs: overflows.\n");
     392               0 :     return NULL;
     393                 :   }
     394                 :   /* Check for total bytes exceeding NACL_ABI_SSIZE_T_MAX. */
     395               3 :   if (-1 == IovTotalBytes(iov, iov_length, extra_entries)) {
     396                 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     397               0 :                 "CopyAndAddIovs: total bytes overflows.\n");
     398               0 :     return NULL;
     399                 :   }
     400                 :   /* Copy the iov, adding extra_entries elements. */
     401                 :   copy = (struct NaClImcMsgIoVec*) malloc((iov_length + extra_entries) *
     402               3 :                                           sizeof *iov);
     403               3 :   if (NULL == copy) {
     404                 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     405               0 :                 "CopyAndAddIovs: copy malloc failed.\n");
     406               0 :     return NULL;
     407                 :   }
     408               3 :   memcpy(copy + extra_entries, iov, iov_length * sizeof *iov);
     409               3 :   return copy;
     410               3 : }
     411                 : 
     412                 : static int BuildFragmentHeader(NaClSrpcMessageHeader* header,
     413                 :                                LengthHeader* fragment_size,
     414                 :                                size_t entries_to_skip,
     415               3 :                                NaClSrpcMessageHeader* frag_hdr) {
     416                 :   size_t i;
     417               3 :   size_t total_bytes = 0;
     418               3 :   const size_t kMaxIovEntries = SIZE_T_MAX / sizeof *frag_hdr->iov;
     419                 : 
     420               3 :   if (NACL_ABI_SIZE_T_MAX < header->iov_length) {
     421                 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     422               0 :                 "BuildFragmentHeader: iov_length too large.\n");
     423               0 :     return 0;
     424                 :   }
     425                 :   /* Copy the entire iovec, even though only part may be used. */
     426               3 :   frag_hdr->iov_length = header->iov_length;
     427               3 :   if (kMaxIovEntries < header->iov_length) {
     428                 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     429               0 :                 "BuildFragmentHeader: iov_length > kMaxIovEntries.\n");
     430               0 :     return 0;
     431                 :   }
     432                 :   frag_hdr->iov = (struct NaClImcMsgIoVec*)
     433               3 :       malloc(header->iov_length * sizeof *frag_hdr->iov);
     434               3 :   if (frag_hdr->iov == NULL) {
     435                 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     436               0 :                 "BuildFragmentHeader: iov malloc failed.\n");
     437               0 :     return 0;
     438                 :   }
     439                 :   memcpy(frag_hdr->iov,
     440                 :          header->iov,
     441               3 :          frag_hdr->iov_length * sizeof *frag_hdr->iov);
     442                 :   /* Update the iov[i].length entries. */
     443               3 :   for (i = entries_to_skip; i < header->iov_length; ++i) {
     444                 :     size_t bytes_this_iov =
     445                 :         size_min(fragment_size->byte_count - total_bytes,
     446               3 :                  frag_hdr->iov[i].length);
     447               3 :     if (bytes_this_iov == 0) {
     448                 :       /* header->iov_length was checked at entry to make this safe. */
     449               1 :       frag_hdr->iov_length = (nacl_abi_size_t) i;
     450                 :     }
     451               3 :     frag_hdr->iov[i].length = bytes_this_iov;
     452                 :     /* Ensure that total_bytes increment doesn't overflow. */
     453               3 :     if (SIZE_T_MAX - bytes_this_iov < total_bytes) {
     454                 :       NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     455               0 :                   "BuildFragmentHeader: total bytes overflows.\n");
     456               0 :       return 0;
     457                 :     }
     458               3 :     total_bytes += bytes_this_iov;
     459               3 :   }
     460                 :   frag_hdr->NACL_SRPC_MESSAGE_HEADER_DESCV =
     461               3 :       header->NACL_SRPC_MESSAGE_HEADER_DESCV;
     462               3 :   frag_hdr->NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = fragment_size->desc_count;
     463               3 :   return 1;
     464               3 : }
     465                 : 
     466                 : static void ConsumeFragment(NaClSrpcMessageHeader* header,
     467                 :                             LengthHeader* fragment_size,
     468               3 :                             size_t guaranteed_entries) {
     469                 :   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               3 :   header->iov += (nacl_abi_size_t) guaranteed_entries;
     476               3 :   header->iov_length -= (nacl_abi_size_t) guaranteed_entries;
     477                 :   /* Update to reflect the fragment's descriptors that were consumed. */
     478                 :   descs_read =
     479                 :       size_min(fragment_size->desc_count,
     480               3 :                header->NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH);
     481                 :   /* Post-condition: descs_read <= NACL_ABI_SIZE_T_MAX. */
     482               3 :   header->NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH -= (nacl_abi_size_t) descs_read;
     483               3 :   header->NACL_SRPC_MESSAGE_HEADER_DESCV += (nacl_abi_size_t) descs_read;
     484               3 :   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               3 :   while ((header->iov_length > 0) && (fragment_size->byte_count > 0)) {
     490                 :     size_t bytes_for_this_entry;
     491                 :     bytes_for_this_entry =
     492               3 :         size_min(header->iov[0].length, fragment_size->byte_count);
     493                 :     /* Post-condition: bytes_for_this_entry <= NACL_ABI_SIZE_T_MAX. */
     494               3 :     header->iov[0].length -= (nacl_abi_size_t) bytes_for_this_entry;
     495               3 :     fragment_size->byte_count -= (nacl_abi_size_t) bytes_for_this_entry;
     496               3 :     if (header->iov[0].length > 0) {
     497                 :       /* The fragment was exhausted, but didn't satisfy this iov entry. */
     498               1 :       header->iov[0].base = (char*) header->iov[0].base + bytes_for_this_entry;
     499               1 :       break;
     500                 :     }
     501                 :     /* This iov entry was satisfied. Remove it from the vector. */
     502               3 :     header->iov++;
     503               3 :     header->iov_length--;
     504               3 :   }
     505               3 :   if (fragment_size->byte_count > 0) {
     506               1 :     header->flags |= NACL_ABI_RECVMSG_DATA_TRUNCATED;
     507                 :   }
     508               3 :   if (fragment_size->desc_count > 0) {
     509               1 :     header->flags |= NACL_ABI_RECVMSG_DESC_TRUNCATED;
     510                 :   }
     511               3 : }
     512                 : 
     513                 : static int32_t FragmentLengthIsSane(LengthHeader* fragment_size,
     514                 :                                     size_t bytes_received,
     515               3 :                                     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                 :   if (fragment_size->byte_count < bytes_received - FRAGMENT_OVERHEAD ||
     522               3 :       fragment_size->desc_count < descs_received) {
     523                 :     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               0 :                 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               3 :   if (fragment_size->byte_count == 0 && fragment_size->desc_count == 0) {
     539                 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     540               0 :                 "FragmentLengthIsSane: empty fragment. Terminating.\n");
     541               0 :     return 0;
     542                 :   }
     543               3 :   return 1;
     544               3 : }
     545                 : 
     546                 : static int32_t MessageLengthsAreSane(LengthHeader* total_size,
     547                 :                                      LengthHeader* fragment_size,
     548                 :                                      size_t bytes_received,
     549               3 :                                      size_t descs_received) {
     550                 :   /*
     551                 :    * Empty messages are not allowed.
     552                 :    */
     553               3 :   if (total_size->byte_count == 0 && total_size->desc_count == 0) {
     554                 :     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               0 :                 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                 :   if (fragment_size->byte_count > total_size->byte_count ||
     567               3 :       fragment_size->desc_count > total_size->desc_count) {
     568                 :     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               0 :                 total_size->desc_count);
     576               0 :     return 0;
     577                 :   }
     578                 :   /*
     579                 :    * And the first fragment must be correct.
     580                 :    * Decrement bytes_received to remove the total_size header.
     581                 :    */
     582                 :   return FragmentLengthIsSane(fragment_size,
     583                 :                               bytes_received - FRAGMENT_OVERHEAD,
     584               3 :                               descs_received);
     585               3 : }
     586                 : 
     587               2 : static ssize_t ErrnoFromImcRet(ssize_t imc_ret) {
     588               2 :   if (0 > imc_ret) {
     589               2 :     return imc_ret;
     590                 :   } else {
     591               0 :     return -NACL_ABI_EIO;
     592                 :   }
     593               2 : }
     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                 : ssize_t NaClSrpcMessageChannelPeek(struct NaClSrpcMessageChannel* channel,
     600               3 :                                    NaClSrpcMessageHeader* header) {
     601                 :   /*
     602                 :    * TODO(sehr): Most of this function is common with Receive.
     603                 :    * Find a way to merge them.
     604                 :    */
     605               3 :   struct NaClImcMsgIoVec* iovec = NULL;
     606                 :   NaClSrpcMessageHeader header_copy;
     607                 :   LengthHeader total_size;
     608                 :   LengthHeader fragment_size;
     609                 :   ssize_t imc_ret;
     610               3 :   ssize_t retval = -NACL_ABI_EINVAL;
     611                 : 
     612                 :   /* Append the fragment headers to the iov. */
     613               3 :   iovec = CopyAndAddIovs(header->iov, header->iov_length, 2);
     614               3 :   if (NULL == iovec) {
     615                 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     616               0 :                 "NaClSrpcMessageChannelPeek: CopyAndAddIovs failed.\n");
     617               0 :     return -1;
     618                 :   }
     619               3 :   header_copy.iov = iovec;
     620               3 :   header_copy.iov_length = header->iov_length + 2;
     621                 :   header_copy.NACL_SRPC_MESSAGE_HEADER_DESCV =
     622               3 :       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               3 :       size_min(SRPC_DESC_MAX, header->NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH);
     626               3 :   header_copy.iov[0].base = &total_size;
     627               3 :   header_copy.iov[0].length = sizeof total_size;
     628               3 :   header_copy.iov[1].base = &fragment_size;
     629               3 :   header_copy.iov[1].length = sizeof fragment_size;
     630               3 :   header_copy.flags = 0;
     631               3 :   if (-1 == HeaderTotalBytes(&header_copy, 0)) {
     632                 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     633               0 :                 "NaClSrpcMessageChannelPeek: header size overflow.\n");
     634               0 :     goto done;
     635                 :   }
     636                 :   NaClSrpcLog(3,
     637                 :               "NaClSrpcMessageChannelPeek: read message bytes %"
     638                 :               NACL_PRIuS", descs %"NACL_PRIuS".\n",
     639                 :               channel->byte_count,
     640               3 :               channel->desc_count);
     641               3 :   imc_ret = MessageChannelBufferRead(channel, &header_copy, 1);
     642               3 :   if (imc_ret < (ssize_t) kFragmentOverhead[FIRST_FRAGMENT]) {
     643                 :     NaClSrpcLog(3,
     644                 :                 "NaClSrpcMessageChannelPeek: read failed (%"NACL_PRIdS").\n",
     645               2 :                 imc_ret);
     646               2 :     retval = ErrnoFromImcRet(imc_ret);
     647               2 :     goto done;
     648                 :   }
     649               3 :   header->flags = header_copy.flags;
     650                 :   header->NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH =
     651               3 :       header_copy.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH;
     652                 :   NaClSrpcLog(3,
     653                 :               "NaClSrpcMessageChannelPeek: flags %x.\n",
     654               3 :               header->flags);
     655                 :   if (!MessageLengthsAreSane(
     656                 :            &total_size,
     657                 :            &fragment_size,
     658                 :            (size_t) imc_ret,
     659               3 :            header_copy.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH)) {
     660                 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     661               0 :                 "NaClSrpcMessageChannelPeek: message length mismatch.\n");
     662               0 :     retval = -NACL_ABI_EIO;
     663               0 :     goto done;
     664                 :   }
     665                 :   /* Comparison above guarantees no underflow. */
     666               3 :   retval = imc_ret - kFragmentOverhead[FIRST_FRAGMENT];
     667                 : 
     668                 :  done:
     669               3 :   free(iovec);
     670               3 :   return retval;
     671               3 : }
     672                 : 
     673                 : /*
     674                 :  * Receive a message from channel.  On success it returns the number of
     675                 :  * bytes read; otherwise, returns -1.
     676                 :  */
     677                 : ssize_t NaClSrpcMessageChannelReceive(struct NaClSrpcMessageChannel* channel,
     678               3 :                                       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               3 :   ssize_t imc_ret = -1;
     684                 :   NaClSrpcMessageHeader header_copy;
     685               3 :   struct NaClImcMsgIoVec* iovec = NULL;
     686                 :   LengthHeader total_size;
     687                 :   LengthHeader fragment_size;
     688                 :   LengthHeader processed_size;
     689                 :   size_t bytes_received;
     690                 :   size_t descs_received;
     691               3 :   ssize_t retval = -NACL_ABI_EINVAL;
     692                 : 
     693               3 :   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               3 :   iovec = CopyAndAddIovs(header->iov, header->iov_length, 2);
     699               3 :   if (NULL == iovec) {
     700                 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     701               0 :                 "NaClSrpcMessageChannelReceive: CopyAndAddIovs failed.\n");
     702               0 :     goto done;
     703                 :   }
     704               3 :   header_copy.iov = iovec;
     705               3 :   header_copy.iov_length = header->iov_length + 2;
     706                 :   header_copy.NACL_SRPC_MESSAGE_HEADER_DESCV =
     707               3 :       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               3 :       size_min(SRPC_DESC_MAX, header->NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH);
     711               3 :   header_copy.iov[0].base = &total_size;
     712               3 :   header_copy.iov[0].length = sizeof total_size;
     713               3 :   header_copy.iov[1].base = &fragment_size;
     714               3 :   header_copy.iov[1].length = sizeof fragment_size;
     715               3 :   header_copy.flags = 0;
     716               3 :   if (-1 == HeaderTotalBytes(&header_copy, 0)) {
     717                 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     718               0 :                 "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               3 :   imc_ret = MessageChannelBufferRead(channel, &header_copy, 0);
     726               3 :   if (imc_ret < (ssize_t) kFragmentOverhead[FIRST_FRAGMENT]) {
     727                 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     728                 :                 "NaClSrpcMessageChannelReceive: read failed (%"NACL_PRIdS").\n",
     729               0 :                 imc_ret);
     730               0 :     retval = ErrnoFromImcRet(imc_ret);
     731               0 :     goto done;
     732                 :   }
     733                 :   /* Comparison above guarantees no underflow. */
     734               3 :   bytes_received = imc_ret - kFragmentOverhead[FIRST_FRAGMENT];
     735               3 :   descs_received = header_copy.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH;
     736                 :   if (!MessageLengthsAreSane(
     737                 :           &total_size,
     738                 :           &fragment_size,
     739                 :           (size_t) imc_ret,
     740               3 :           header_copy.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH)) {
     741                 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     742                 :                 "NaClSrpcMessageChannelReceive:"
     743               0 :                 " first fragment descriptor check failed.\n");
     744               0 :     retval = -NACL_ABI_EIO;
     745               0 :     goto done;
     746                 :   }
     747                 :   NaClSrpcLog(3,
     748                 :               "NaClSrpcMessageChannelReceive:"
     749                 :               " new message, bytes %"NACL_PRIdNACL_SIZE
     750                 :               ", descs %"NACL_PRIdNACL_SIZE".\n",
     751                 :               total_size.byte_count,
     752               3 :               total_size.desc_count);
     753                 :   NaClSrpcLog(3,
     754                 :               "NaClSrpcMessageChannelReceive:"
     755                 :               " first fragment, bytes %"NACL_PRIdNACL_SIZE
     756                 :               ", descs %"NACL_PRIdNACL_SIZE".\n",
     757                 :               fragment_size.byte_count,
     758               3 :               fragment_size.desc_count);
     759               3 :   processed_size = fragment_size;
     760               3 :   ConsumeFragment(&header_copy, &fragment_size, 2);
     761                 :   /*
     762                 :    * Get the remaining fragments.
     763                 :    */
     764                 :   while (processed_size.byte_count < total_size.byte_count ||
     765               3 :          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               1 :     header_copy.iov = header_copy.iov - 1;
     774               1 :     header_copy.iov_length = header_copy.iov_length + 1;
     775               1 :     header_copy.iov[0].base = &fragment_size;
     776               1 :     header_copy.iov[0].length = sizeof fragment_size;
     777                 :     header_copy.NACL_SRPC_MESSAGE_HEADER_DESCV =
     778               1 :         header->NACL_SRPC_MESSAGE_HEADER_DESCV + descs_received;
     779                 :     header_copy.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = (nacl_abi_size_t)
     780                 :         size_min(SRPC_DESC_MAX,
     781                 :                  (header->NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH -
     782               1 :                   descs_received));
     783               1 :     if (-1 == HeaderTotalBytes(&header_copy, 0)) {
     784                 :       NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     785               0 :                   "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               1 :     imc_ret = ImcRecvmsg(channel->desc.raw_desc, &header_copy, 0);
     794               1 :     if (imc_ret < (ssize_t) kFragmentOverhead[LATER_FRAGMENT]) {
     795                 :       NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     796                 :                   "NaClSrpcMessageChannelReceive: read failed (%"
     797                 :                   NACL_PRIdS").\n",
     798               0 :                   imc_ret);
     799               0 :       retval = ErrnoFromImcRet(imc_ret);
     800               0 :       goto done;
     801                 :     }
     802                 :     /* Comparison above guarantees no underflow. */
     803               1 :     bytes_received += imc_ret - kFragmentOverhead[LATER_FRAGMENT];
     804               1 :     descs_received += header_copy.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH;
     805                 :     if (!FragmentLengthIsSane(
     806                 :             &fragment_size,
     807                 :             (size_t) imc_ret,
     808               1 :             header_copy.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH)) {
     809                 :       NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     810                 :                   "NaClSrpcMessageChannelReceive:"
     811               0 :                   " other fragment descriptor check failed.\n");
     812               0 :       retval = -NACL_ABI_EIO;
     813               0 :       goto done;
     814                 :     }
     815                 :     NaClSrpcLog(3,
     816                 :                 "NaClSrpcMessageChannelReceive:"
     817                 :                 " next fragment, bytes %"NACL_PRIdNACL_SIZE
     818                 :                 ", descs %"NACL_PRIdNACL_SIZE".\n",
     819                 :                 fragment_size.byte_count,
     820               1 :                 fragment_size.desc_count);
     821               1 :     processed_size.byte_count += fragment_size.byte_count;
     822               1 :     processed_size.desc_count += fragment_size.desc_count;
     823               1 :     ConsumeFragment(&header_copy, &fragment_size, 1);
     824               1 :   }
     825                 :   NaClSrpcLog(3,
     826                 :               "NaClSrpcMessageChannelReceive:"
     827                 :               " succeeded, read %"NACL_PRIuS" bytes and %"
     828                 :               NACL_PRIdNACL_SIZE" descs.\n",
     829                 :               bytes_received,
     830               3 :               processed_size.desc_count);
     831               3 :   retval = (ssize_t) bytes_received;
     832                 :   header->NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH =
     833               3 :       (nacl_abi_size_t) descs_received;
     834               3 :   header->flags = header_copy.flags;
     835                 : 
     836                 :  done:
     837               3 :   free(iovec);
     838               3 :   return retval;
     839               3 : }
     840                 : 
     841                 : /*
     842                 :  * Sends message over the channel. It returns 1 if successful, or 0 otherwise.
     843                 :  */
     844                 : ssize_t NaClSrpcMessageChannelSend(struct NaClSrpcMessageChannel* channel,
     845               3 :                                    const NaClSrpcMessageHeader* header) {
     846                 :   ssize_t imc_ret;
     847               3 :   struct NaClImcMsgIoVec* iovec = NULL;
     848                 :   NaClSrpcMessageHeader remaining;
     849                 :   NaClSrpcMessageHeader frag_hdr;
     850                 :   LengthHeader total_size;
     851                 :   LengthHeader fragment_size;
     852                 :   size_t expected_bytes_sent;
     853               3 :   ssize_t retval = -NACL_ABI_EINVAL;
     854                 : 
     855               3 :   iovec = CopyAndAddIovs(header->iov, header->iov_length, 2);
     856               3 :   if (NULL == iovec) {
     857                 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     858               0 :                 "NaClSrpcMessageChannelSend: CopyAndAddIovs failed.\n");
     859               0 :     goto done;
     860                 :   }
     861               3 :   remaining.iov = iovec;
     862               3 :   remaining.iov_length = header->iov_length + 2;
     863                 :   remaining.NACL_SRPC_MESSAGE_HEADER_DESCV =
     864               3 :       header->NACL_SRPC_MESSAGE_HEADER_DESCV;
     865                 :   remaining.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH =
     866               3 :       header->NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH;
     867               3 :   remaining.iov[0].base = &total_size;
     868               3 :   remaining.iov[0].length = sizeof total_size;
     869               3 :   remaining.iov[1].base = &fragment_size;
     870               3 :   remaining.iov[1].length = sizeof fragment_size;
     871               3 :   if (-1 == HeaderTotalBytes(&remaining, 0)) {
     872                 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     873               0 :                 "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               3 :   total_size.byte_count = (nacl_abi_size_t) HeaderTotalBytes(&remaining, 2);
     882               3 :   if (-1 == (nacl_abi_ssize_t) total_size.byte_count) {
     883                 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     884               0 :                 "NaClSrpcMessageChannelSend: HeaderTotalBytes failed.\n");
     885               0 :     goto done;
     886                 :   }
     887               3 :   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               3 :   if (!ComputeFragmentSizes(&remaining, FIRST_FRAGMENT, &fragment_size)) {
     894                 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     895                 :                 "NaClSrpcMessageChannelSend:"
     896               0 :                 " first ComputeFragmentSize failed.\n");
     897               0 :     goto done;
     898                 :   }
     899                 :   NaClSrpcLog(3,
     900                 :               "NaClSrpcMessageChannelSend: new message, bytes %"
     901                 :               NACL_PRIdNACL_SIZE", descs %"NACL_PRIdNACL_SIZE".\n",
     902                 :               total_size.byte_count,
     903               3 :               total_size.desc_count);
     904                 :   NaClSrpcLog(3,
     905                 :               "NaClSrpcMessageChannelSend: first fragment, bytes %"
     906                 :               NACL_PRIdNACL_SIZE", descs %"NACL_PRIdNACL_SIZE".\n",
     907                 :               fragment_size.byte_count,
     908               3 :               fragment_size.desc_count);
     909                 :   if (NACL_ABI_SSIZE_T_MAX - kFragmentOverhead[FIRST_FRAGMENT] <
     910               3 :       fragment_size.byte_count) {
     911                 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     912                 :                 "NaClSrpcMessageChannelSend:"
     913               0 :                 " fragment size would cause overflow.\n");
     914               0 :     goto done;
     915                 :   }
     916                 :   expected_bytes_sent =
     917               3 :       fragment_size.byte_count + kFragmentOverhead[FIRST_FRAGMENT];
     918               3 :   if (expected_bytes_sent > NaClSrpcMaxImcSendmsgSize) {
     919                 :     NaClSrpcLog(NACL_SRPC_LOG_FATAL,
     920                 :                 "NaClSrpcMessageChannelSend: expected bytes %"
     921                 :                 NACL_PRIuS" exceed maximum allowed %"NACL_PRIdNACL_SIZE"\n",
     922               0 :                 expected_bytes_sent, NaClSrpcMaxImcSendmsgSize);
     923                 :   }
     924               3 :   if (!BuildFragmentHeader(&remaining, &fragment_size, 2, &frag_hdr)) {
     925                 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     926                 :                 "NaClSrpcMessageChannelSend:"
     927               0 :                 " 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               3 :   imc_ret = ImcSendmsg(channel->desc.raw_desc, &frag_hdr, 0);
     936               3 :   free(frag_hdr.iov);
     937               3 :   if ((size_t) imc_ret != expected_bytes_sent) {
     938                 :     NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     939                 :                 "NaClSrpcMessageChannelSend: first send failed, %"
     940                 :                 NACL_PRIuS" != %"NACL_PRIdS".\n",
     941                 :                 expected_bytes_sent,
     942               0 :                 imc_ret);
     943               0 :     retval = ErrnoFromImcRet(imc_ret);
     944               0 :     goto done;
     945                 :   }
     946               3 :   ConsumeFragment(&remaining, &fragment_size, 2);
     947                 :   NaClSrpcLog(3,
     948               3 :               "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                 :   while (remaining.iov_length > 0 ||
     954               3 :          remaining.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH > 0) {
     955                 :     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               1 :     remaining.iov = remaining.iov - 1;
     964               1 :     remaining.iov_length = remaining.iov_length + 1;
     965               1 :     remaining.iov[0].base = &fragment_size;
     966               1 :     remaining.iov[0].length = sizeof fragment_size;
     967               1 :     if (-1 == HeaderTotalBytes(&remaining, 0)) {
     968                 :       NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     969               0 :                   "NaClSrpcMessageChannelSend: header size overflow.\n");
     970               0 :       goto done;
     971                 :     }
     972                 :     /*
     973                 :      * The fragment sizes are again limited.
     974                 :      */
     975               1 :     if (!ComputeFragmentSizes(&remaining, LATER_FRAGMENT, &fragment_size)) {
     976                 :       NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     977                 :                   "NaClSrpcMessageChannelSend:"
     978               0 :                   " other ComputeFragmentSize failed.\n");
     979               0 :       retval = -NACL_ABI_EIO;
     980               0 :       goto done;
     981                 :     }
     982                 :     NaClSrpcLog(3,
     983                 :                 "NaClSrpcMessageChannelSend: next fragment, bytes %"
     984                 :                 NACL_PRIdNACL_SIZE", descs %"NACL_PRIdNACL_SIZE".\n",
     985                 :                 fragment_size.byte_count,
     986               1 :                 fragment_size.desc_count);
     987               1 :     if (!BuildFragmentHeader(&remaining, &fragment_size, 1, &frag_hdr)) {
     988                 :       NaClSrpcLog(NACL_SRPC_LOG_ERROR,
     989                 :                   "NaClSrpcMessageChannelSend:"
     990               0 :                   " could not build fragment header.\n");
     991               0 :       retval = -NACL_ABI_EIO;
     992               0 :       goto done;
     993                 :     }
     994                 :     /*
     995                 :      * Send the fragment.
     996                 :      */
     997                 :     if (NACL_ABI_SSIZE_T_MAX - kFragmentOverhead[LATER_FRAGMENT] <
     998               1 :         fragment_size.byte_count) {
     999                 :       NaClSrpcLog(NACL_SRPC_LOG_ERROR,
    1000                 :                   "NaClSrpcMessageChannelSend:"
    1001               0 :                   " fragment size would cause overflow.\n");
    1002               0 :       goto done;
    1003                 :     }
    1004                 :     expected_bytes_sent =
    1005               1 :         fragment_size.byte_count + kFragmentOverhead[LATER_FRAGMENT];
    1006               1 :     if (expected_bytes_sent > NaClSrpcMaxImcSendmsgSize) {
    1007                 :       NaClSrpcLog(NACL_SRPC_LOG_FATAL,
    1008                 :                   "NaClSrpcMessageChannelSend: expected bytes %"
    1009                 :                   NACL_PRIuS" exceed maximum allowed %"NACL_PRIdNACL_SIZE"\n",
    1010               0 :                   expected_bytes_sent, NaClSrpcMaxImcSendmsgSize);
    1011                 :     }
    1012               1 :     imc_ret = ImcSendmsg(channel->desc.raw_desc, &frag_hdr, 0);
    1013               1 :     free(frag_hdr.iov);
    1014               1 :     if ((size_t) imc_ret != expected_bytes_sent) {
    1015                 :       NaClSrpcLog(NACL_SRPC_LOG_ERROR,
    1016               0 :                   "NaClSrpcMessageChannelSend: send error.\n");
    1017               0 :       retval = ErrnoFromImcRet(imc_ret);
    1018               0 :       goto done;
    1019                 :     }
    1020               1 :     ConsumeFragment(&remaining, &fragment_size, 1);
    1021               1 :   }
    1022                 :   NaClSrpcLog(3,
    1023                 :               "NaClSrpcMessageChannelSend: complete send, sent %"
    1024                 :               NACL_PRIdNACL_SIZE" bytes and %"NACL_PRIdNACL_SIZE" descs.\n",
    1025                 :               total_size.byte_count,
    1026               3 :               total_size.desc_count);
    1027               3 :   retval = (ssize_t) total_size.byte_count;
    1028                 : 
    1029                 :  done:
    1030               3 :   free(iovec);
    1031               3 :   return retval;
    1032               3 : }

Generated by: LCOV version 1.7