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_c.h"
11 : #include <assert.h>
12 : #include <ctype.h>
13 : #include <errno.h>
14 : #include <fcntl.h>
15 : #include <stdio.h>
16 : #include <string.h>
17 : #include <unistd.h>
18 : #include <sys/mman.h>
19 : #include <sys/socket.h>
20 : #include <sys/types.h>
21 : #include <sys/un.h>
22 :
23 : #include "native_client/src/shared/platform/nacl_log.h"
24 :
25 : /*
26 : * Gets an array of file descriptors stored in msg.
27 : * The fdv parameter must be an int array of kHandleCountMax elements.
28 : * GetRights() returns the number of file descriptors copied into fdv.
29 : */
30 19105 : static size_t GetRights(struct msghdr* msg, int* fdv) {
31 : struct cmsghdr* cmsg;
32 19105 : size_t count = 0;
33 19371 : for (cmsg = CMSG_FIRSTHDR(msg);
34 : cmsg != 0;
35 : cmsg = CMSG_NXTHDR(msg, cmsg)) {
36 266 : if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
37 839 : while (CMSG_LEN((1 + count) * sizeof(int)) <= cmsg->cmsg_len) {
38 307 : *fdv++ = ((int *) CMSG_DATA(cmsg))[count];
39 307 : ++count;
40 : }
41 : }
42 : }
43 19105 : return count;
44 : }
45 :
46 : /*
47 : * We keep these no-op implementations of SocketAddress-based
48 : * functions so that sigpipe_test continues to link.
49 : */
50 0 : NaClHandle NaClBoundSocket(const NaClSocketAddress* address) {
51 : UNREFERENCED_PARAMETER(address);
52 0 : NaClLog(LOG_FATAL, "BoundSocket(): Not used on Linux\n");
53 0 : return -1;
54 : }
55 :
56 0 : int NaClSendDatagramTo(const NaClMessageHeader* message, int flags,
57 : const NaClSocketAddress* name) {
58 : UNREFERENCED_PARAMETER(message);
59 : UNREFERENCED_PARAMETER(flags);
60 : UNREFERENCED_PARAMETER(name);
61 0 : NaClLog(LOG_FATAL, "SendDatagramTo(): Not used on Linux\n");
62 0 : return -1;
63 : }
64 :
65 1110 : int NaClSocketPair(NaClHandle pair[2]) {
66 : /*
67 : * The read operation for a SOCK_SEQPACKET socket returns zero when the
68 : * remote peer closed the connection unlike a SOCK_DGRAM socket. Note
69 : * SOCK_SEQPACKET was introduced with Linux 2.6.4.
70 : */
71 1110 : int rv = socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair);
72 1110 : if (rv != 0) {
73 0 : NaClLog(LOG_ERROR, "SocketPair: socketpair failed, errno %d\n", errno);
74 : }
75 1110 : return rv;
76 : }
77 :
78 1239 : int NaClClose(NaClHandle handle) {
79 1239 : return close(handle);
80 : }
81 :
82 19076 : int NaClSendDatagram(NaClHandle handle, const NaClMessageHeader* message,
83 : int flags) {
84 : struct msghdr msg;
85 : unsigned char buf[CMSG_SPACE(NACL_HANDLE_COUNT_MAX * sizeof(int))];
86 :
87 19076 : if (NACL_HANDLE_COUNT_MAX < message->handle_count) {
88 0 : errno = EMSGSIZE;
89 0 : return -1;
90 : }
91 : /*
92 : * The following assert was an earlier attempt to remember/check the
93 : * assumption that our struct IOVec -- which we must define to be
94 : * cross platform -- is compatible with struct iovec on *x systems.
95 : * The length field of IOVec was switched to be uint32_t at one point
96 : * to use concrete types, which introduced a problem on 64-bit systems.
97 : *
98 : * Clearly, the assert does not check a strong-enough condition,
99 : * since structure padding would make the two sizes the same.
100 : *
101 : assert(sizeof(struct iovec) == sizeof(NaClIOVec));
102 : *
103 : * Don't do this again!
104 : */
105 :
106 19076 : if (!NaClMessageSizeIsValid(message)) {
107 0 : errno = EMSGSIZE;
108 0 : return -1;
109 : }
110 :
111 19076 : msg.msg_iov = (struct iovec *) message->iov;
112 19076 : msg.msg_iovlen = message->iov_length;
113 19076 : msg.msg_name = 0;
114 19076 : msg.msg_namelen = 0;
115 :
116 19076 : if (0 < message->handle_count && message->handles != NULL) {
117 : struct cmsghdr* cmsg;
118 249 : int size = message->handle_count * sizeof(int);
119 249 : msg.msg_control = buf;
120 249 : msg.msg_controllen = CMSG_SPACE(size);
121 249 : cmsg = CMSG_FIRSTHDR(&msg);
122 249 : cmsg->cmsg_level = SOL_SOCKET;
123 249 : cmsg->cmsg_type = SCM_RIGHTS;
124 249 : cmsg->cmsg_len = CMSG_LEN(size);
125 249 : memcpy(CMSG_DATA(cmsg), message->handles, size);
126 249 : msg.msg_controllen = cmsg->cmsg_len;
127 : } else {
128 18827 : msg.msg_control = 0;
129 18827 : msg.msg_controllen = 0;
130 : }
131 19076 : msg.msg_flags = 0;
132 : return sendmsg(handle, &msg,
133 19076 : MSG_NOSIGNAL | ((flags & NACL_DONT_WAIT) ? MSG_DONTWAIT : 0));
134 : }
135 :
136 19119 : int NaClReceiveDatagram(NaClHandle handle, NaClMessageHeader* message,
137 : int flags) {
138 : struct msghdr msg;
139 : unsigned char buf[CMSG_SPACE(NACL_HANDLE_COUNT_MAX * sizeof(int))];
140 : int count;
141 :
142 19119 : if (NACL_HANDLE_COUNT_MAX < message->handle_count) {
143 0 : errno = EMSGSIZE;
144 0 : return -1;
145 : }
146 19119 : msg.msg_name = 0;
147 19119 : msg.msg_namelen = 0;
148 :
149 : /*
150 : * Make sure we cannot receive more than 2**32-1 bytes.
151 : */
152 19119 : if (!NaClMessageSizeIsValid(message)) {
153 0 : errno = EMSGSIZE;
154 0 : return -1;
155 : }
156 :
157 19119 : msg.msg_iov = (struct iovec *) message->iov;
158 19119 : msg.msg_iovlen = message->iov_length;
159 19119 : if (0 < message->handle_count && message->handles != NULL) {
160 19108 : msg.msg_control = buf;
161 19108 : msg.msg_controllen = CMSG_SPACE(message->handle_count * sizeof(int));
162 : } else {
163 11 : msg.msg_control = 0;
164 11 : msg.msg_controllen = 0;
165 : }
166 19119 : msg.msg_flags = 0;
167 19119 : message->flags = 0;
168 19119 : count = recvmsg(handle, &msg, (flags & NACL_DONT_WAIT) ? MSG_DONTWAIT : 0);
169 19105 : if (0 <= count) {
170 19105 : message->handle_count = GetRights(&msg, message->handles);
171 19105 : if (msg.msg_flags & MSG_TRUNC) {
172 0 : message->flags |= NACL_MESSAGE_TRUNCATED;
173 : }
174 19105 : if (msg.msg_flags & MSG_CTRUNC) {
175 0 : message->flags |= NACL_HANDLES_TRUNCATED;
176 : }
177 : }
178 19105 : return count;
179 : }
|