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

Generated by: LCOV version 1.7