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 : }
|