1 : /*
2 : * Copyright (c) 2011 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 :
8 : // NaCl inter-module communication primitives.
9 :
10 : #include "native_client/src/shared/imc/nacl_imc.h"
11 : #include <assert.h>
12 : #include <ctype.h>
13 : #include <errno.h>
14 : #include <fcntl.h>
15 : #include <limits.h>
16 : #include <poll.h>
17 : #include <stdio.h>
18 : #include <string.h>
19 : #include <unistd.h>
20 : #include <sys/mman.h>
21 : #include <sys/socket.h>
22 : #include <sys/types.h>
23 : #include <sys/un.h>
24 :
25 : #include "native_client/src/shared/platform/nacl_log.h"
26 :
27 :
28 : /*
29 : * TODO(bsy,bradnelson): remove SIGPIPE_FIX. It is needed for future
30 : * testing because our test framework appears to not see the SIGPIPE
31 : * on OSX when the fix is not in place. We've tracked it down to the
32 : * Python subprocess module, where if we manually run
33 : * subprocess.Popen('...path-to-sigpipe_test...') the SIGPIPE doesn't
34 : * actually occur(!); however, when running the same sigpipe_test
35 : * executable from the shell it's apparent that the SIGPIPE *does*
36 : * occur. Presumably it's some weird code path in subprocess that is
37 : * leaving the signal handler for SIGPIPE as SIG_IGN rather than
38 : * SIG_DFL. Unfortunately, we could not create a simpler test of our
39 : * test infrastructure (writing to a pipe that's closed) -- perhaps
40 : * the multithreaded nature of sigpipe_test is involved.
41 : *
42 : * In production code, SIGPIPE_FIX should be 1. The old behavior is
43 : * only needed to help us track down the problem in python.
44 : */
45 : #define SIGPIPE_FIX 1
46 :
47 : /*
48 : * The code guarded by SIGPIPE_FIX has been found to still raise
49 : * SIGPIPE in certain situations. Until we can boil this down to a
50 : * small test case and, possibly, file a bug against the OS, we need
51 : * to forcibly suppress these signals.
52 : */
53 : #define SIGPIPE_ALT_FIX 1
54 :
55 : #if SIGPIPE_ALT_FIX
56 : # include <signal.h>
57 : #endif // SIGPIPE_ALT_FIX
58 :
59 : #include <algorithm>
60 : #include "native_client/src/trusted/service_runtime/include/sys/nacl_imc_api.h"
61 :
62 : namespace nacl {
63 :
64 : namespace {
65 :
66 : // The number of recvmsg retries to perform to determine --
67 : // heuristically, unfortunately -- if the remote end of the socketpair
68 : // had actually closed. This is a (new) hacky workaround for an OSX
69 : // blemish that replaces the older, buggier workaround.
70 : const int kRecvMsgRetries = 8;
71 :
72 : // The maximum number of IOVec elements sent by SendDatagram(). Plus one for
73 : // NaClInternalHeader with the descriptor data bytes.
74 : const size_t kIovLengthMax = NACL_ABI_IMC_IOVEC_MAX + 1;
75 :
76 : // The IMC datagram header followed by a message_bytes of data sent over the
77 : // a stream-oriented socket. We need to use stream-oriented socket for OS X
78 : // since it doesn't support file descriptor transfer over SOCK_DGRAM socket
79 : // like Linux.
80 : struct Header {
81 : // The total bytes of data in the IMC datagram excluding the size of Header.
82 : size_t message_bytes;
83 : // The total number of handles to be transferred with IMC datagram.
84 : size_t handle_count;
85 : };
86 :
87 :
88 : // Gets an array of file descriptors stored in msg.
89 : // The fdv parameter must be an int array of kHandleCountMax elements.
90 : // GetRights() returns the number of file descriptors copied into fdv.
91 9738 : size_t GetRights(struct msghdr* msg, int* fdv) {
92 9738 : if (msg->msg_controllen == 0) {
93 9521 : return 0;
94 : }
95 217 : size_t count = 0;
96 434 : for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(msg);
97 : cmsg != 0;
98 : cmsg = CMSG_NXTHDR(msg, cmsg)) {
99 217 : if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
100 658 : while (CMSG_LEN((1 + count) * sizeof(int)) <= cmsg->cmsg_len) {
101 224 : *fdv++ = *(reinterpret_cast<int*>(CMSG_DATA(cmsg)) + count);
102 224 : ++count;
103 : }
104 : }
105 : }
106 217 : return count;
107 : }
108 :
109 : // Skips the specified length of octets when reading from a handle. Skipped
110 : // octets are discarded.
111 : // On success, true is returned. On error, false is returned.
112 0 : bool SkipFile(int handle, size_t length) {
113 0 : while (0 < length) {
114 : char scratch[1024];
115 0 : size_t count = std::min(sizeof scratch, length);
116 0 : count = read(handle, scratch, count);
117 0 : if (static_cast<ssize_t>(count) == -1 || count == 0) {
118 0 : return false;
119 : }
120 0 : length -= count;
121 : }
122 0 : return true;
123 : }
124 :
125 : #if SIGPIPE_ALT_FIX
126 : // TODO(kbr): move this to an Init() function so it isn't called all
127 : // the time.
128 500 : bool IgnoreSIGPIPE() {
129 : sigset_t mask;
130 500 : sigemptyset(&mask);
131 : struct sigaction sa;
132 500 : sa.sa_handler = SIG_IGN;
133 500 : sa.sa_mask = mask;
134 500 : sa.sa_flags = 0;
135 500 : return sigaction(SIGPIPE, &sa, NULL) == 0;
136 : }
137 : #endif
138 :
139 : } // namespace
140 :
141 : // We keep these no-op implementations of SocketAddress-based
142 : // functions so that sigpipe_test continues to link.
143 0 : Handle BoundSocket(const SocketAddress* address) {
144 : UNREFERENCED_PARAMETER(address);
145 0 : NaClLog(LOG_FATAL, "BoundSocket(): Not used on OSX\n");
146 0 : return -1;
147 : }
148 :
149 : int SendDatagramTo(const MessageHeader* message, int flags,
150 0 : const SocketAddress* name) {
151 : UNREFERENCED_PARAMETER(message);
152 : UNREFERENCED_PARAMETER(flags);
153 : UNREFERENCED_PARAMETER(name);
154 0 : NaClLog(LOG_FATAL, "SendDatagramTo(): Not used on OSX\n");
155 0 : return -1;
156 : }
157 :
158 500 : int SocketPair(Handle pair[2]) {
159 500 : int result = socketpair(AF_UNIX, SOCK_STREAM, 0, pair);
160 500 : if (result == 0) {
161 : #if SIGPIPE_ALT_FIX
162 500 : if (!IgnoreSIGPIPE()) {
163 0 : close(pair[0]);
164 0 : close(pair[1]);
165 0 : return -1;
166 : }
167 : #endif
168 : #if SIGPIPE_FIX
169 500 : int nosigpipe = 1;
170 500 : if (0 != setsockopt(pair[0], SOL_SOCKET, SO_NOSIGPIPE,
171 : &nosigpipe, sizeof nosigpipe) ||
172 : 0 != setsockopt(pair[1], SOL_SOCKET, SO_NOSIGPIPE,
173 : &nosigpipe, sizeof nosigpipe)) {
174 0 : close(pair[0]);
175 0 : close(pair[1]);
176 0 : return -1;
177 : }
178 : #endif
179 : }
180 500 : return result;
181 : }
182 :
183 1186 : int Close(Handle handle) {
184 1186 : return close(handle);
185 : }
186 :
187 9728 : int SendDatagram(Handle handle, const MessageHeader* message, int flags) {
188 : struct msghdr msg;
189 : struct iovec vec[kIovLengthMax + 1];
190 : unsigned char buf[CMSG_SPACE_KHANDLE_COUNT_MAX_INTS];
191 9728 : Header header = { 0, 0 };
192 :
193 : (void) flags; /* BUG(shiki): unused parameter */
194 :
195 : assert(CMSG_SPACE(kHandleCountMax * sizeof(int))
196 : <= CMSG_SPACE_KHANDLE_COUNT_MAX_INTS);
197 :
198 : /*
199 : * The following assert was an earlier attempt to remember/check the
200 : * assumption that our struct IOVec -- which we must define to be
201 : * cross platform -- is compatible with struct iovec on *x systems.
202 : * The length field of IOVec was switched to be uint32_t at oen point
203 : * to use concrete types, which introduced a problem on 64-bit systems.
204 : *
205 : * Clearly, the assert does not check a strong-enough condition,
206 : * since structure padding would make the two sizes the same.
207 : *
208 : assert(sizeof(struct iovec) == sizeof(IOVec));
209 : *
210 : * Don't do this again!
211 : */
212 :
213 9728 : if (!MessageSizeIsValid(message)) {
214 0 : errno = EMSGSIZE;
215 0 : return -1;
216 : }
217 :
218 9728 : if (kHandleCountMax < message->handle_count ||
219 : kIovLengthMax < message->iov_length) {
220 0 : errno = EMSGSIZE;
221 0 : return -1;
222 : }
223 :
224 9728 : memmove(&vec[1], message->iov, sizeof(IOVec) * message->iov_length);
225 :
226 9728 : msg.msg_name = 0;
227 9728 : msg.msg_namelen = 0;
228 9728 : msg.msg_iov = vec;
229 9728 : msg.msg_iovlen = 1 + message->iov_length;
230 9943 : if (0 < message->handle_count && message->handles != NULL) {
231 215 : int size = message->handle_count * sizeof(int);
232 215 : msg.msg_control = buf;
233 215 : msg.msg_controllen = CMSG_SPACE(size);
234 215 : struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg);
235 215 : cmsg->cmsg_level = SOL_SOCKET;
236 215 : cmsg->cmsg_type = SCM_RIGHTS;
237 215 : cmsg->cmsg_len = CMSG_LEN(size);
238 215 : memcpy(reinterpret_cast<int*>(CMSG_DATA(cmsg)), message->handles, size);
239 215 : msg.msg_controllen = cmsg->cmsg_len;
240 215 : header.handle_count = message->handle_count;
241 : } else {
242 9513 : msg.msg_control = 0;
243 9513 : msg.msg_controllen = 0;
244 : }
245 9728 : msg.msg_flags = 0;
246 :
247 : // Send data with the header atomically. Note to send file descriptors we need
248 : // to send at least one byte of data.
249 39554 : for (size_t i = 0; i < message->iov_length; ++i) {
250 29826 : header.message_bytes += message->iov[i].length;
251 : }
252 9728 : vec[0].iov_base = &header;
253 9728 : vec[0].iov_len = sizeof header;
254 9728 : int result = sendmsg(handle, &msg, 0);
255 9728 : if (result == -1) {
256 1 : return -1;
257 : }
258 9727 : if (static_cast<size_t>(result) < sizeof header) {
259 0 : errno = EMSGSIZE;
260 0 : return -1;
261 : }
262 9727 : return result - sizeof header;
263 : }
264 :
265 9746 : int ReceiveDatagram(Handle handle, MessageHeader* message, int flags) {
266 : struct msghdr msg;
267 : struct iovec vec[kIovLengthMax];
268 : unsigned char buf[CMSG_SPACE_KHANDLE_COUNT_MAX_INTS];
269 :
270 : assert(CMSG_SPACE(kHandleCountMax * sizeof(int))
271 : <= CMSG_SPACE_KHANDLE_COUNT_MAX_INTS);
272 :
273 9746 : if (kHandleCountMax < message->handle_count ||
274 : kIovLengthMax < message->iov_length) {
275 0 : errno = EMSGSIZE;
276 0 : return -1;
277 : }
278 :
279 : /*
280 : * The following assert was an earlier attempt to remember/check the
281 : * assumption that our struct IOVec -- which we must define to be
282 : * cross platform -- is compatible with struct iovec on *x systems.
283 : * The length field of IOVec was switched to be uint32_t at oen point
284 : * to use concrete types, which introduced a problem on 64-bit systems.
285 : *
286 : * Clearly, the assert does not check a strong-enough condition,
287 : * since structure padding would make the two sizes the same.
288 : *
289 : assert(sizeof(struct iovec) == sizeof(IOVec));
290 : *
291 : * Don't do this again!
292 : */
293 :
294 9746 : if (!MessageSizeIsValid(message)) {
295 0 : errno = EMSGSIZE;
296 0 : return -1;
297 : }
298 :
299 9746 : message->flags = 0;
300 : // Receive the header of the message and handles first.
301 : Header header;
302 9746 : struct iovec header_vec = { &header, sizeof header };
303 9746 : msg.msg_iov = &header_vec;
304 9746 : msg.msg_iovlen = 1;
305 9746 : msg.msg_name = 0;
306 9746 : msg.msg_namelen = 0;
307 19492 : if (0 < message->handle_count && message->handles != NULL) {
308 9746 : msg.msg_control = buf;
309 9746 : msg.msg_controllen = CMSG_SPACE(message->handle_count * sizeof(int));
310 : } else {
311 0 : msg.msg_control = 0;
312 0 : msg.msg_controllen = 0;
313 : }
314 9746 : msg.msg_flags = 0;
315 : int count;
316 : int retry_count;
317 9810 : for (retry_count = 0; retry_count < kRecvMsgRetries; ++retry_count) {
318 9802 : if (0 != (count = recvmsg(handle, &msg,
319 : (flags & kDontWait) ? MSG_DONTWAIT : 0))) {
320 9738 : break;
321 : }
322 : }
323 9746 : if (0 != retry_count && kRecvMsgRetries != retry_count) {
324 : printf("OSX_BLEMISH_HEURISTIC: retry_count = %d, count = %d\n",
325 0 : retry_count, count);
326 : }
327 9746 : size_t handle_count = 0;
328 9746 : if (0 < count) {
329 9738 : handle_count = GetRights(&msg, message->handles);
330 : }
331 9746 : if (count != sizeof header) {
332 16 : while (0 < handle_count) {
333 : // Note if the sender has sent one end of a socket pair here,
334 : // ReceiveDatagram() for that socket will result in a zero length read
335 : // return henceforth.
336 0 : close(message->handles[--handle_count]);
337 : }
338 8 : if (count == 0) {
339 8 : message->handle_count = 0;
340 8 : return 0;
341 : }
342 0 : if (count != -1) {
343 : // TODO(shiki): We should call recvmsg() again here since it could get to
344 : // wake up with a partial header since the SOCK_STREAM socket does not
345 : // required to maintain message boundaries.
346 0 : errno = EMSGSIZE;
347 : }
348 0 : return -1;
349 : }
350 :
351 9738 : message->handle_count = handle_count;
352 :
353 : // OS X seems not to set the MSG_CTRUNC flag in msg.msg_flags as we expect,
354 : // and we don't rely on it.
355 9738 : if (message->handle_count < header.handle_count) {
356 0 : message->flags |= kHandlesTruncated;
357 : }
358 :
359 9738 : if (header.message_bytes == 0) {
360 200 : return 0;
361 : }
362 :
363 : // Update message->iov to receive just message_bytes.
364 9538 : memmove(vec, message->iov, sizeof(IOVec) * message->iov_length);
365 9538 : msg.msg_iov = vec;
366 9538 : msg.msg_iovlen = message->iov_length;
367 9538 : size_t buffer_bytes = 0;
368 : size_t i;
369 9538 : for (i = 0; i < message->iov_length; ++i) {
370 9538 : buffer_bytes += vec[i].iov_len;
371 9538 : if (header.message_bytes <= buffer_bytes) {
372 9538 : vec[i].iov_len -= buffer_bytes - header.message_bytes;
373 9538 : buffer_bytes = header.message_bytes;
374 9538 : msg.msg_iovlen = i + 1;
375 9538 : break;
376 : }
377 : }
378 9538 : if (buffer_bytes < header.message_bytes) {
379 0 : message->flags |= kMessageTruncated;
380 : }
381 :
382 : // Receive the sent data.
383 9538 : msg.msg_name = 0;
384 9538 : msg.msg_namelen = 0;
385 :
386 9538 : msg.msg_control = 0;
387 9538 : msg.msg_controllen = 0;
388 9538 : msg.msg_flags = 0;
389 9538 : for (retry_count = 0; retry_count < kRecvMsgRetries; ++retry_count) {
390 : // We have to pass MSG_WAITALL here, because we have already consumed
391 : // the header. If we returned EAGAIN here, subsequent calls would read
392 : // data as a header, and much hilarity would ensue.
393 9538 : if (0 != (count = recvmsg(handle, &msg, MSG_WAITALL))) {
394 9538 : break;
395 : }
396 : }
397 9538 : if (0 != retry_count && kRecvMsgRetries != retry_count) {
398 : printf("OSX_BLEMISH_HEURISTIC (2): retry_count = %d, count = %d\n",
399 0 : retry_count, count);
400 : }
401 9538 : if (0 < count) {
402 : // If the caller requested fewer bytes than the message contained, we need
403 : // to read the remaining bytes, discard them, and report message truncated.
404 9538 : if (static_cast<size_t>(count) < header.message_bytes) {
405 0 : if (!SkipFile(handle, header.message_bytes - count)) {
406 0 : return -1;
407 : }
408 0 : message->flags |= kMessageTruncated;
409 : }
410 : }
411 9538 : return count;
412 : }
413 :
414 : } // namespace nacl
|