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