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 : /*
8 : * NaCl Service Runtime. I/O Descriptor / Handle abstraction.
9 : * Bound IMC descriptors.
10 : */
11 :
12 : #include <assert.h>
13 : #include <errno.h>
14 : #include <stdlib.h>
15 : #include <string.h>
16 : #include <sys/socket.h>
17 :
18 : #include "native_client/src/include/portability.h"
19 : #include "native_client/src/shared/imc/nacl_imc_c.h"
20 : #include "native_client/src/shared/platform/nacl_check.h"
21 : #include "native_client/src/shared/platform/nacl_log.h"
22 :
23 : #include "native_client/src/trusted/desc/nacl_desc_base.h"
24 : #include "native_client/src/trusted/desc/nacl_desc_imc.h"
25 : #include "native_client/src/trusted/desc/nacl_desc_imc_bound_desc.h"
26 :
27 : #include "native_client/src/trusted/service_runtime/nacl_config.h"
28 : #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
29 : #include "native_client/src/trusted/service_runtime/include/sys/stat.h"
30 :
31 :
32 : static struct NaClDescVtbl const kNaClDescImcBoundDescVtbl; /* fwd */
33 :
34 586 : int NaClDescImcBoundDescCtor(struct NaClDescImcBoundDesc *self,
35 586 : NaClHandle h) {
36 586 : struct NaClDesc *basep = (struct NaClDesc *) self;
37 :
38 586 : basep->base.vtbl = (struct NaClRefCountVtbl const *) NULL;
39 586 : if (!NaClDescCtor(basep)) {
40 0 : return 0;
41 : }
42 586 : self->h = h;
43 586 : basep->base.vtbl =
44 : (struct NaClRefCountVtbl const *) &kNaClDescImcBoundDescVtbl;
45 586 : return 1;
46 586 : }
47 :
48 8 : void NaClDescImcBoundDescDtor(struct NaClRefCount *vself) {
49 8 : struct NaClDescImcBoundDesc *self = (struct NaClDescImcBoundDesc *) vself;
50 :
51 8 : NaClClose(self->h);
52 8 : self->h = NACL_INVALID_HANDLE;
53 8 : vself->vtbl = (struct NaClRefCountVtbl const *) &kNaClDescVtbl;
54 8 : (*vself->vtbl->Dtor)(vself);
55 8 : }
56 :
57 0 : int NaClDescImcBoundDescFstat(struct NaClDesc *vself,
58 0 : struct nacl_abi_stat *statbuf) {
59 0 : UNREFERENCED_PARAMETER(vself);
60 :
61 0 : memset(statbuf, 0, sizeof *statbuf);
62 0 : statbuf->nacl_abi_st_mode = NACL_ABI_S_IFBOUNDSOCK;
63 0 : return 0;
64 : }
65 :
66 559 : int NaClDescImcBoundDescAcceptConn(struct NaClDesc *vself,
67 559 : struct NaClDesc **result) {
68 : /*
69 : * See NaClDescConnCapConnectAddr code in nacl_desc_conn_cap.c
70 : */
71 559 : struct NaClDescImcBoundDesc *self = (struct NaClDescImcBoundDesc *) vself;
72 559 : int retval;
73 559 : NaClHandle received_fd;
74 559 : struct NaClDescImcDesc *peer;
75 559 : struct iovec iovec;
76 559 : struct msghdr accept_msg;
77 559 : struct cmsghdr *cmsg;
78 559 : char data_buf[1];
79 559 : char control_buf[CMSG_SPACE_KHANDLE_COUNT_MAX_INTS];
80 559 : int received;
81 :
82 : assert(CMSG_SPACE(sizeof(int)) <= CMSG_SPACE_KHANDLE_COUNT_MAX_INTS);
83 :
84 559 : peer = malloc(sizeof(*peer));
85 559 : if (peer == NULL) {
86 0 : return -NACL_ABI_ENOMEM;
87 : }
88 :
89 33 : iovec.iov_base = data_buf;
90 33 : iovec.iov_len = sizeof(data_buf);
91 33 : accept_msg.msg_iov = &iovec;
92 33 : accept_msg.msg_iovlen = 1;
93 33 : accept_msg.msg_name = NULL;
94 33 : accept_msg.msg_namelen = 0;
95 33 : accept_msg.msg_control = control_buf;
96 33 : accept_msg.msg_controllen = sizeof(control_buf);
97 :
98 33 : NaClLog(3,
99 : ("NaClDescImcBoundDescAcceptConn(0x%08"NACL_PRIxPTR", "
100 : " h = %d\n"),
101 : (uintptr_t) vself,
102 : self->h);
103 :
104 33 : received_fd = NACL_INVALID_HANDLE;
105 :
106 33 : received = recvmsg(self->h, &accept_msg, 0);
107 65 : if (received != 1 || data_buf[0] != 'c') {
108 1 : NaClLog(LOG_ERROR,
109 : ("NaClDescImcBoundDescAcceptConn:"
110 : " could not receive connection message, errno %d\n"),
111 1 : errno);
112 1 : retval = -NACL_ABI_EIO;
113 1 : goto cleanup;
114 : }
115 :
116 32 : retval = 0;
117 : /*
118 : * If we got more than one fd in the message, we must clean up by
119 : * closing those extra descriptors. Given that control_buf is
120 : * CMSG_SPACE(sizeof(int)) in size, this shouldn't actualy happen.
121 : *
122 : * We follow the principle of being strict in what we send and
123 : * tolerant in what we accept, and simply discard the extra
124 : * descriptors without signaling an error (other than a log
125 : * message). This makes it easier to rev the protocol w/o
126 : * necessarily requiring a protocol version number bump.
127 : */
128 160 : for (cmsg = CMSG_FIRSTHDR(&accept_msg);
129 : cmsg != NULL;
130 160 : cmsg = CMSG_NXTHDR(&accept_msg, cmsg)) {
131 96 : if (cmsg->cmsg_level == SOL_SOCKET &&
132 : cmsg->cmsg_type == SCM_RIGHTS &&
133 : cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
134 32 : if (NACL_INVALID_HANDLE != received_fd) {
135 0 : int bad_fd;
136 :
137 : /* can only be true on 2nd time through */
138 0 : NaClLog(LOG_ERROR, ("NaClDescImcBoundDescAcceptConn: connection"
139 : " message contains more than 1 descriptors?!?\n"));
140 0 : memcpy(&bad_fd, CMSG_DATA(cmsg), sizeof bad_fd);
141 0 : (void) close(bad_fd);
142 : /*
143 : * If we want to NOT be tolerant about what we receive, we could
144 : * uncomment this:
145 : *
146 : * retval = -NACL_ABI_EIO;
147 : */
148 0 : continue;
149 : }
150 : /*
151 : * We use memcpy() rather than assignment through a cast to avoid
152 : * strict-aliasing warnings
153 : */
154 32 : memcpy(&received_fd, CMSG_DATA(cmsg), sizeof received_fd);
155 32 : }
156 32 : }
157 32 : if (0 != retval) {
158 0 : goto cleanup;
159 : }
160 32 : if (NACL_INVALID_HANDLE == received_fd) {
161 0 : NaClLog(LOG_ERROR, ("NaClDescImcBoundDescAcceptConn: connection"
162 : " message contains NO descriptors?!?\n"));
163 0 : retval = -NACL_ABI_EIO;
164 0 : goto cleanup;
165 : }
166 :
167 : if (NACL_OSX) {
168 : /*
169 : * Send a message to acknowledge that we received the socket FD
170 : * successfully. This is part of a workaround for a Mac OS X
171 : * kernel bug.
172 : * See http://code.google.com/p/nativeclient/issues/detail?id=1796
173 : */
174 32 : ssize_t sent = send(received_fd, "a", 1, 0);
175 32 : if (sent != 1) {
176 0 : retval = -NACL_ABI_EIO;
177 0 : goto cleanup;
178 : }
179 : }
180 :
181 32 : if (!NaClDescImcDescCtor(peer, received_fd)) {
182 0 : retval = -NACL_ABI_EMFILE;
183 0 : goto cleanup;
184 : }
185 32 : received_fd = NACL_INVALID_HANDLE;
186 :
187 32 : *result = (struct NaClDesc *) peer;
188 32 : retval = 0;
189 :
190 : cleanup:
191 33 : if (retval < 0) {
192 1 : if (received_fd != NACL_INVALID_HANDLE) {
193 0 : (void) close(received_fd);
194 0 : }
195 1 : free(peer);
196 1 : }
197 33 : return retval;
198 33 : }
199 :
200 : static struct NaClDescVtbl const kNaClDescImcBoundDescVtbl = {
201 : {
202 : NaClDescImcBoundDescDtor,
203 : },
204 : NaClDescMapNotImplemented,
205 : NACL_DESC_UNMAP_NOT_IMPLEMENTED
206 : NaClDescReadNotImplemented,
207 : NaClDescWriteNotImplemented,
208 : NaClDescSeekNotImplemented,
209 : NaClDescPReadNotImplemented,
210 : NaClDescPWriteNotImplemented,
211 : NaClDescImcBoundDescFstat,
212 : NaClDescGetdentsNotImplemented,
213 : NaClDescExternalizeSizeNotImplemented,
214 : NaClDescExternalizeNotImplemented,
215 : NaClDescLockNotImplemented,
216 : NaClDescTryLockNotImplemented,
217 : NaClDescUnlockNotImplemented,
218 : NaClDescWaitNotImplemented,
219 : NaClDescTimedWaitAbsNotImplemented,
220 : NaClDescSignalNotImplemented,
221 : NaClDescBroadcastNotImplemented,
222 : NaClDescSendMsgNotImplemented,
223 : NaClDescRecvMsgNotImplemented,
224 : NaClDescLowLevelSendMsgNotImplemented,
225 : NaClDescLowLevelRecvMsgNotImplemented,
226 : NaClDescConnectAddrNotImplemented,
227 : NaClDescImcBoundDescAcceptConn,
228 : NaClDescPostNotImplemented,
229 : NaClDescSemWaitNotImplemented,
230 : NaClDescGetValueNotImplemented,
231 : NaClDescSetMetadata,
232 : NaClDescGetMetadata,
233 : NaClDescSetFlags,
234 : NaClDescGetFlags,
235 : NaClDescIsattyNotImplemented,
236 : NACL_DESC_BOUND_SOCKET,
237 : };
|