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 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 : int NaClDescImcBoundDescCtor(struct NaClDescImcBoundDesc *self,
35 36 : NaClHandle h) {
36 36 : struct NaClDesc *basep = (struct NaClDesc *) self;
37 :
38 36 : basep->base.vtbl = (struct NaClRefCountVtbl const *) NULL;
39 36 : if (!NaClDescCtor(basep)) {
40 0 : return 0;
41 : }
42 36 : self->h = h;
43 36 : basep->base.vtbl =
44 : (struct NaClRefCountVtbl const *) &kNaClDescImcBoundDescVtbl;
45 36 : return 1;
46 : }
47 :
48 12 : void NaClDescImcBoundDescDtor(struct NaClRefCount *vself) {
49 12 : struct NaClDescImcBoundDesc *self = (struct NaClDescImcBoundDesc *) vself;
50 :
51 12 : NaClClose(self->h);
52 12 : self->h = NACL_INVALID_HANDLE;
53 12 : vself->vtbl = (struct NaClRefCountVtbl const *) &kNaClDescVtbl;
54 12 : (*vself->vtbl->Dtor)(vself);
55 12 : }
56 :
57 : int NaClDescImcBoundDescFstat(struct NaClDesc *vself,
58 0 : struct nacl_abi_stat *statbuf) {
59 : 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 : int NaClDescImcBoundDescAcceptConn(struct NaClDesc *vself,
67 25 : struct NaClDesc **result) {
68 : /*
69 : * See NaClDescConnCapConnectAddr code in nacl_desc_conn_cap.c
70 : */
71 25 : struct NaClDescImcBoundDesc *self = (struct NaClDescImcBoundDesc *) vself;
72 : int retval;
73 : NaClHandle received_fd;
74 : struct NaClDescImcDesc *peer;
75 : struct iovec iovec;
76 : struct msghdr accept_msg;
77 : struct cmsghdr *cmsg;
78 : char data_buf[1];
79 : char control_buf[CMSG_SPACE_KHANDLE_COUNT_MAX_INTS];
80 : int received;
81 :
82 : assert(CMSG_SPACE(sizeof(int)) <= CMSG_SPACE_KHANDLE_COUNT_MAX_INTS);
83 :
84 25 : peer = malloc(sizeof(*peer));
85 25 : if (peer == NULL) {
86 0 : return -NACL_ABI_ENOMEM;
87 : }
88 :
89 25 : iovec.iov_base = data_buf;
90 25 : iovec.iov_len = sizeof(data_buf);
91 25 : accept_msg.msg_iov = &iovec;
92 25 : accept_msg.msg_iovlen = 1;
93 25 : accept_msg.msg_name = NULL;
94 25 : accept_msg.msg_namelen = 0;
95 25 : accept_msg.msg_control = control_buf;
96 25 : accept_msg.msg_controllen = sizeof(control_buf);
97 :
98 25 : NaClLog(3,
99 : ("NaClDescImcBoundDescAcceptConn(0x%08"NACL_PRIxPTR", "
100 : " h = %d\n"),
101 : (uintptr_t) vself,
102 : self->h);
103 :
104 25 : received_fd = NACL_INVALID_HANDLE;
105 :
106 25 : received = recvmsg(self->h, &accept_msg, 0);
107 19 : if (received != 1 || data_buf[0] != 'c') {
108 0 : NaClLog(LOG_ERROR,
109 : ("NaClDescImcBoundDescAcceptConn:"
110 : " could not receive connection message, errno %d\n"),
111 : errno);
112 0 : retval = -NACL_ABI_EIO;
113 0 : goto cleanup;
114 : }
115 :
116 19 : 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 19 : for (cmsg = CMSG_FIRSTHDR(&accept_msg);
129 57 : cmsg != NULL;
130 19 : cmsg = CMSG_NXTHDR(&accept_msg, cmsg)) {
131 19 : if (cmsg->cmsg_level == SOL_SOCKET &&
132 : cmsg->cmsg_type == SCM_RIGHTS &&
133 : cmsg->cmsg_len == CMSG_LEN(sizeof(int))) {
134 19 : if (NACL_INVALID_HANDLE != received_fd) {
135 : 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 19 : memcpy(&received_fd, CMSG_DATA(cmsg), sizeof received_fd);
155 : }
156 : }
157 19 : if (0 != retval) {
158 0 : goto cleanup;
159 : }
160 19 : 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 19 : ssize_t sent = send(received_fd, "a", 1, 0);
175 19 : if (sent != 1) {
176 0 : retval = -NACL_ABI_EIO;
177 0 : goto cleanup;
178 : }
179 : }
180 :
181 19 : if (!NaClDescImcDescCtor(peer, received_fd)) {
182 0 : retval = -NACL_ABI_EMFILE;
183 0 : goto cleanup;
184 : }
185 19 : received_fd = NACL_INVALID_HANDLE;
186 :
187 19 : *result = (struct NaClDesc *) peer;
188 19 : retval = 0;
189 :
190 19 : cleanup:
191 19 : if (retval < 0) {
192 0 : if (received_fd != NACL_INVALID_HANDLE) {
193 0 : (void) close(received_fd);
194 : }
195 0 : free(peer);
196 : }
197 19 : return retval;
198 : }
199 :
200 : static struct NaClDescVtbl const kNaClDescImcBoundDescVtbl = {
201 : {
202 : NaClDescImcBoundDescDtor,
203 : },
204 : NaClDescMapNotImplemented,
205 : NaClDescUnmapUnsafeNotImplemented,
206 : NaClDescUnmapNotImplemented,
207 : NaClDescReadNotImplemented,
208 : NaClDescWriteNotImplemented,
209 : NaClDescSeekNotImplemented,
210 : NaClDescIoctlNotImplemented,
211 : NaClDescImcBoundDescFstat,
212 : NaClDescGetdentsNotImplemented,
213 : NACL_DESC_BOUND_SOCKET,
214 : NaClDescExternalizeSizeNotImplemented,
215 : NaClDescExternalizeNotImplemented,
216 : NaClDescLockNotImplemented,
217 : NaClDescTryLockNotImplemented,
218 : NaClDescUnlockNotImplemented,
219 : NaClDescWaitNotImplemented,
220 : NaClDescTimedWaitAbsNotImplemented,
221 : NaClDescSignalNotImplemented,
222 : NaClDescBroadcastNotImplemented,
223 : NaClDescSendMsgNotImplemented,
224 : NaClDescRecvMsgNotImplemented,
225 : NaClDescConnectAddrNotImplemented,
226 : NaClDescImcBoundDescAcceptConn,
227 : NaClDescPostNotImplemented,
228 : NaClDescSemWaitNotImplemented,
229 : NaClDescGetValueNotImplemented,
230 : };
|