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