1 : /*
2 : * Copyright 2008 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can
4 : * be found in the LICENSE file.
5 : */
6 :
7 : /*
8 : * NaCl Service Runtime. I/O Descriptor / Handle abstraction.
9 : */
10 :
11 : #include <stdlib.h>
12 : #include <string.h>
13 : #include <errno.h>
14 :
15 : #include "native_client/src/include/portability.h"
16 :
17 : #include "native_client/src/trusted/desc/nacl_desc_base.h"
18 : #include "native_client/src/trusted/desc/nacl_desc_imc.h"
19 :
20 : #include "native_client/src/shared/platform/nacl_log.h"
21 : #include "native_client/src/shared/platform/nacl_sync.h"
22 : #include "native_client/src/shared/platform/nacl_sync_checked.h"
23 :
24 : #if NACL_WINDOWS
25 : # include "native_client/src/shared/platform/win/xlate_system_error.h"
26 : #endif
27 :
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 : * This file contains the implementation of the NaClDescImcDesc
33 : * subclass of NaClDesc.
34 : *
35 : * NaClDescImcDesc is the subclass that wraps IMC socket descriptors.
36 : */
37 :
38 : /* fwd */
39 : static struct NaClDescVtbl const kNaClDescImcConnectedDescVtbl;
40 : static struct NaClDescVtbl const kNaClDescImcDescVtbl;
41 : static struct NaClDescVtbl const kNaClDescXferableDataDescVtbl;
42 :
43 : int NaClDescImcConnectedDescCtor(struct NaClDescImcConnectedDesc *self,
44 84 : NaClHandle h) {
45 84 : struct NaClDesc *basep = (struct NaClDesc *) self;
46 :
47 84 : basep->base.vtbl = (struct NaClRefCountVtbl const *) NULL;
48 :
49 84 : if (!NaClDescCtor(basep)) {
50 0 : return 0;
51 : }
52 84 : self->h = h;
53 84 : basep->base.vtbl = (struct NaClRefCountVtbl const *)
54 : &kNaClDescImcConnectedDescVtbl;
55 :
56 84 : return 1;
57 : }
58 :
59 75 : static void NaClDescImcConnectedDescDtor(struct NaClRefCount *vself) {
60 : struct NaClDescImcConnectedDesc *self = ((struct NaClDescImcConnectedDesc *)
61 75 : vself);
62 75 : (void) NaClClose(self->h);
63 75 : self->h = NACL_INVALID_HANDLE;
64 75 : vself->vtbl = (struct NaClRefCountVtbl const *) &kNaClDescVtbl;
65 75 : (*vself->vtbl->Dtor)(vself);
66 75 : }
67 :
68 : int NaClDescImcDescCtor(struct NaClDescImcDesc *self,
69 84 : NaClHandle h) {
70 : int retval;
71 :
72 84 : retval = NaClDescImcConnectedDescCtor(&self->base, h);
73 84 : if (!retval) {
74 0 : return 0;
75 : }
76 84 : if (!NaClMutexCtor(&self->sendmsg_mu)) {
77 0 : NaClDescUnref((struct NaClDesc *) self);
78 0 : return 0;
79 : }
80 84 : if (!NaClMutexCtor(&self->recvmsg_mu)) {
81 0 : NaClMutexDtor(&self->sendmsg_mu);
82 0 : NaClDescUnref((struct NaClDesc *) self);
83 0 : return 0;
84 : }
85 84 : self->base.base.base.vtbl = (struct NaClRefCountVtbl const *)
86 : &kNaClDescImcDescVtbl;
87 :
88 84 : return retval;
89 : }
90 :
91 75 : static void NaClDescImcDescDtor(struct NaClRefCount *vself) {
92 : struct NaClDescImcDesc *self = ((struct NaClDescImcDesc *)
93 75 : vself);
94 75 : NaClMutexDtor(&self->sendmsg_mu);
95 75 : NaClMutexDtor(&self->recvmsg_mu);
96 :
97 75 : vself->vtbl = (struct NaClRefCountVtbl const *)
98 : &kNaClDescImcConnectedDescVtbl;
99 75 : (*vself->vtbl->Dtor)(vself);
100 75 : }
101 :
102 : int NaClDescXferableDataDescCtor(struct NaClDescXferableDataDesc *self,
103 0 : NaClHandle h) {
104 : int retval;
105 0 : retval = NaClDescImcConnectedDescCtor(&self->base, h);
106 0 : if (!retval) {
107 0 : return 0;
108 : }
109 0 : self->base.base.base.vtbl = (struct NaClRefCountVtbl const *)
110 : &kNaClDescXferableDataDescVtbl;
111 :
112 0 : return retval;
113 : }
114 :
115 0 : static void NaClDescXferableDataDescDtor(struct NaClRefCount *vself) {
116 0 : vself->vtbl = (struct NaClRefCountVtbl const *)
117 : &kNaClDescImcConnectedDescVtbl;
118 0 : (*vself->vtbl->Dtor)(vself);
119 0 : }
120 :
121 : int NaClDescImcDescFstat(struct NaClDesc *vself,
122 0 : struct nacl_abi_stat *statbuf) {
123 : UNREFERENCED_PARAMETER(vself);
124 :
125 0 : memset(statbuf, 0, sizeof *statbuf);
126 0 : statbuf->nacl_abi_st_mode = (NACL_ABI_S_IFSOCK |
127 : NACL_ABI_S_IRUSR |
128 : NACL_ABI_S_IWUSR);
129 0 : return 0;
130 : }
131 :
132 : static int NaClDescXferableDataDescFstat(struct NaClDesc *vself,
133 0 : struct nacl_abi_stat *statbuf) {
134 : UNREFERENCED_PARAMETER(vself);
135 :
136 0 : memset(statbuf, 0, sizeof *statbuf);
137 0 : statbuf->nacl_abi_st_mode = NACL_ABI_S_IFDSOCK;
138 0 : return 0;
139 : }
140 :
141 : static int NaClDescXferableDataDescExternalizeSize(struct NaClDesc *vself,
142 : size_t *nbytes,
143 0 : size_t *nhandles) {
144 : UNREFERENCED_PARAMETER(vself);
145 0 : NaClLog(4, "Entered NaClDescXferableDataDescExternalizeSize\n");
146 0 : *nbytes = 0;
147 0 : *nhandles = 1;
148 :
149 0 : return 0;
150 : }
151 :
152 : static int NaClDescXferableDataDescExternalize(struct NaClDesc *vself,
153 0 : struct NaClDescXferState *xfer) {
154 : struct NaClDescXferableDataDesc *self = ((struct NaClDescXferableDataDesc *)
155 0 : vself);
156 :
157 0 : NaClLog(4, "Entered NaClDescXferableDataDescExternalize\n");
158 0 : *xfer->next_handle++ = self->base.h;
159 0 : return 0;
160 : }
161 :
162 :
163 : /*
164 : * In the level of NaClDescImcDescSendMsg, we do not know what
165 : * protocol is implemented by NaClSendDatagram (and indeed, in the
166 : * Windows implementation, the access rights transfer involves a more
167 : * complex protocol to get the peer process id). Because the
168 : * underlying low-level IMC implementation does not provide thread
169 : * safety, this is the source of race conditions: two simultaneous
170 : * imc_sendmsg syscalls to the same descriptor could get their various
171 : * protcol bits interleaved, so the receiver will get garbled data
172 : * that cause the wrong underlying host OS descriptor to be made
173 : * available to the NaCl module.
174 : *
175 : * In order to address this issue, we (1) make descriptors that can
176 : * transfer other descriptors non-transferable, and (2) we use locking
177 : * so that only one thread can be performing (the low level bits of)
178 : * imc_msgsend at a time. The non-transferability of such descriptors
179 : * addresses the multi-module scenario, as opposed to the
180 : * multi-threaded scenario, where a sender race cause receiver
181 : * confusion.
182 : */
183 : static ssize_t NaClDescImcDescSendMsg(struct NaClDesc *vself,
184 : struct NaClMessageHeader const *dgram,
185 9327 : int flags) {
186 : struct NaClDescImcDesc *self = ((struct NaClDescImcDesc *)
187 9327 : vself);
188 : int result;
189 :
190 9327 : NaClXMutexLock(&self->sendmsg_mu);
191 9327 : result = NaClSendDatagram(self->base.h, dgram, flags);
192 9327 : NaClXMutexUnlock(&self->sendmsg_mu);
193 :
194 9327 : if (-1 == result) {
195 : #if NACL_WINDOWS
196 : return -NaClXlateSystemError(GetLastError());
197 : #elif NACL_LINUX || NACL_OSX
198 0 : return -NaClXlateErrno(errno);
199 : #else
200 : # error "Unknown target platform: cannot translate error code(s) from SendMsg"
201 : #endif
202 : }
203 9327 : return result;
204 : }
205 :
206 :
207 : /*
208 : * NaClDescXferableDataDescSendMsg implements imc_sendmsg For
209 : * data-only descriptors. We assume that whatever protocol exists at
210 : * the NaClSendDatagram level is still not thread safe, but that the
211 : * lack of thread safety will not have a significant impact on
212 : * security. This is still somewhat brittle: the low-level Windows
213 : * IMC code can be convinced to do the wrong thing still via sender
214 : * races, but the receiver, because it expects zero handles, will have
215 : * called ReceiveDatagram in such a way that any "received handles"
216 : * are closed. This implies that arbitrary Windows handles can be
217 : * made to be closed, including those not accessible by NaCl modules,
218 : * but fortunately this should only result in a denial of service as
219 : * the error caused by the use of an invalid handle is detected by the
220 : * service runtime and cause an abort.
221 : *
222 : * Note that it is still an application error to send or receive data
223 : * with a transferable data-only descriptor from two threads (or two
224 : * modules) simultaneously.
225 : */
226 : static ssize_t
227 : NaClDescXferableDataDescSendMsg(struct NaClDesc *vself,
228 : struct NaClMessageHeader const *dgram,
229 0 : int flags) {
230 : struct NaClDescXferableDataDesc *self = ((struct NaClDescXferableDataDesc *)
231 0 : vself);
232 : int result;
233 :
234 0 : if (0 != dgram->handle_count) {
235 : /*
236 : * A transferable descriptor cannot be used to transfer other
237 : * descriptors.
238 : */
239 0 : NaClLog(2,
240 : ("NaClDescXferableDataDescSendMsg: tranferable and"
241 : " non-zero handle_count\n"));
242 0 : return -NACL_ABI_EINVAL;
243 : }
244 :
245 0 : result = NaClSendDatagram(self->base.h, dgram, flags);
246 :
247 0 : if (-1 == result) {
248 : #if NACL_WINDOWS
249 : return -NaClXlateSystemError(GetLastError());
250 : #elif NACL_LINUX || NACL_OSX
251 0 : return -NaClXlateErrno(errno);
252 : #else
253 : # error "Unknown target platform: cannot translate error code(s) from SendMsg"
254 : #endif
255 : }
256 0 : return result;
257 : }
258 :
259 :
260 : /*
261 : * See discussion at NaClDescImcDescSendMsg for details. An
262 : * imc_recvmsg race is not substantively different from an imc_sendmsg
263 : * race.
264 : */
265 : static ssize_t NaClDescImcDescRecvMsg(struct NaClDesc *vself,
266 : struct NaClMessageHeader *dgram,
267 9346 : int flags) {
268 : struct NaClDescImcDesc *self = ((struct NaClDescImcDesc *)
269 9346 : vself);
270 : int result;
271 :
272 9346 : NaClLog(4, "Entered NaClDescImcDescRecvMsg, h=%d\n", self->base.h);
273 9346 : NaClXMutexLock(&self->recvmsg_mu);
274 9346 : result = NaClReceiveDatagram(self->base.h, dgram, flags);
275 9346 : NaClXMutexUnlock(&self->recvmsg_mu);
276 :
277 9346 : if (-1 == result) {
278 : #if NACL_WINDOWS
279 : return -NaClXlateSystemError(GetLastError());
280 : #elif NACL_LINUX || NACL_OSX
281 0 : return -errno;
282 : #else
283 : # error "Unknown target platform: cannot translate error code(s) from RecvMsg"
284 : #endif
285 : }
286 9346 : return result;
287 : }
288 :
289 :
290 : /*
291 : * See discussion at NaClDescXferableDataDescSendMsg for details. An
292 : * imc_recvmsg race is not substantively different from an imc_sendmsg
293 : * race.
294 : */
295 : static ssize_t NaClDescXferableDataDescRecvMsg(struct NaClDesc *vself,
296 : struct NaClMessageHeader *dgram,
297 0 : int flags) {
298 : struct NaClDescXferableDataDesc *self = ((struct NaClDescXferableDataDesc *)
299 0 : vself);
300 : int result;
301 :
302 0 : NaClLog(4, "Entered NaClDescXferableDataDescRecvMsg, h = %d\n", self->base.h);
303 0 : if (0 != dgram->handle_count) {
304 : /*
305 : * A transferable descriptor is data-only, and it is an error to
306 : * try to receive any I/O descriptors with it.
307 : */
308 0 : NaClLog(2,
309 : "NaClDescXferableDataDescRecvMsg:"
310 : " tranferable and non-zero handle_count\n");
311 0 : return -NACL_ABI_EINVAL;
312 : }
313 :
314 0 : result = NaClReceiveDatagram(self->base.h, dgram, flags);
315 :
316 0 : if (-1 == result) {
317 : #if NACL_WINDOWS
318 : return -NaClXlateSystemError(GetLastError());
319 : #elif NACL_LINUX || NACL_OSX
320 0 : return -errno;
321 : #else
322 : # error "Unknown target platform: cannot translate error code(s) from RecvMsg"
323 : #endif
324 : }
325 0 : return result;
326 : }
327 :
328 :
329 : static struct NaClDescVtbl const kNaClDescImcConnectedDescVtbl = {
330 : {
331 : NaClDescImcConnectedDescDtor,
332 : },
333 : NaClDescMapNotImplemented,
334 : NaClDescUnmapUnsafeNotImplemented,
335 : NaClDescUnmapNotImplemented,
336 : NaClDescReadNotImplemented,
337 : NaClDescWriteNotImplemented,
338 : NaClDescSeekNotImplemented,
339 : NaClDescIoctlNotImplemented,
340 : NaClDescFstatNotImplemented,
341 : NaClDescGetdentsNotImplemented,
342 : NACL_DESC_CONNECTED_SOCKET,
343 : NaClDescExternalizeSizeNotImplemented,
344 : NaClDescExternalizeNotImplemented,
345 : NaClDescLockNotImplemented,
346 : NaClDescTryLockNotImplemented,
347 : NaClDescUnlockNotImplemented,
348 : NaClDescWaitNotImplemented,
349 : NaClDescTimedWaitAbsNotImplemented,
350 : NaClDescSignalNotImplemented,
351 : NaClDescBroadcastNotImplemented,
352 : NaClDescSendMsgNotImplemented,
353 : NaClDescRecvMsgNotImplemented,
354 : NaClDescConnectAddrNotImplemented,
355 : NaClDescAcceptConnNotImplemented,
356 : NaClDescPostNotImplemented,
357 : NaClDescSemWaitNotImplemented,
358 : NaClDescGetValueNotImplemented,
359 : };
360 :
361 :
362 : static struct NaClDescVtbl const kNaClDescImcDescVtbl = {
363 : {
364 : NaClDescImcDescDtor, /* diff */
365 : },
366 : NaClDescMapNotImplemented,
367 : NaClDescUnmapUnsafeNotImplemented,
368 : NaClDescUnmapNotImplemented,
369 : NaClDescReadNotImplemented,
370 : NaClDescWriteNotImplemented,
371 : NaClDescSeekNotImplemented,
372 : NaClDescIoctlNotImplemented,
373 : NaClDescImcDescFstat, /* diff */
374 : NaClDescGetdentsNotImplemented,
375 : NACL_DESC_IMC_SOCKET, /* diff */
376 : NaClDescExternalizeSizeNotImplemented,
377 : NaClDescExternalizeNotImplemented,
378 : NaClDescLockNotImplemented,
379 : NaClDescTryLockNotImplemented,
380 : NaClDescUnlockNotImplemented,
381 : NaClDescWaitNotImplemented,
382 : NaClDescTimedWaitAbsNotImplemented,
383 : NaClDescSignalNotImplemented,
384 : NaClDescBroadcastNotImplemented,
385 : NaClDescImcDescSendMsg, /* diff */
386 : NaClDescImcDescRecvMsg, /* diff */
387 : NaClDescConnectAddrNotImplemented,
388 : NaClDescAcceptConnNotImplemented,
389 : NaClDescPostNotImplemented,
390 : NaClDescSemWaitNotImplemented,
391 : NaClDescGetValueNotImplemented,
392 : };
393 :
394 :
395 : static struct NaClDescVtbl const kNaClDescXferableDataDescVtbl = {
396 : {
397 : NaClDescXferableDataDescDtor, /* diff */
398 : },
399 : NaClDescMapNotImplemented,
400 : NaClDescUnmapUnsafeNotImplemented,
401 : NaClDescUnmapNotImplemented,
402 : NaClDescReadNotImplemented,
403 : NaClDescWriteNotImplemented,
404 : NaClDescSeekNotImplemented,
405 : NaClDescIoctlNotImplemented,
406 : NaClDescXferableDataDescFstat, /* diff */
407 : NaClDescGetdentsNotImplemented,
408 : NACL_DESC_TRANSFERABLE_DATA_SOCKET, /* diff */
409 : NaClDescXferableDataDescExternalizeSize, /* diff */
410 : NaClDescXferableDataDescExternalize, /* diff */
411 : NaClDescLockNotImplemented,
412 : NaClDescTryLockNotImplemented,
413 : NaClDescUnlockNotImplemented,
414 : NaClDescWaitNotImplemented,
415 : NaClDescTimedWaitAbsNotImplemented,
416 : NaClDescSignalNotImplemented,
417 : NaClDescBroadcastNotImplemented,
418 : NaClDescXferableDataDescSendMsg, /* diff */
419 : NaClDescXferableDataDescRecvMsg, /* diff */
420 : NaClDescConnectAddrNotImplemented,
421 : NaClDescAcceptConnNotImplemented,
422 : NaClDescPostNotImplemented,
423 : NaClDescSemWaitNotImplemented,
424 : NaClDescGetValueNotImplemented,
425 : };
426 :
427 :
428 : int NaClDescXferableDataDescInternalize(
429 : struct NaClDesc **baseptr,
430 : struct NaClDescXferState *xfer,
431 0 : struct NaClDescQuotaInterface *quota_interface) {
432 : int rv;
433 : struct NaClDescXferableDataDesc *ndxdp;
434 :
435 : UNREFERENCED_PARAMETER(quota_interface);
436 0 : NaClLog(4, "Entered NaClDescXferableDataDescInternalize\n");
437 0 : rv = -NACL_ABI_EIO;
438 0 : ndxdp = NULL;
439 :
440 0 : if (xfer->next_handle == xfer->handle_buffer_end) {
441 0 : NaClLog(LOG_ERROR,
442 : ("NaClXferableDataDescInternalize: no descriptor"
443 : " left in xfer state\n"));
444 0 : rv = -NACL_ABI_EIO;
445 0 : goto cleanup;
446 : }
447 0 : ndxdp = malloc(sizeof *ndxdp);
448 0 : if (NULL == ndxdp) {
449 0 : NaClLog(LOG_ERROR,
450 : "NaClXferableDataDescInternalize: no memory\n");
451 0 : rv = -NACL_ABI_ENOMEM;
452 0 : goto cleanup;
453 : }
454 0 : if (!NaClDescXferableDataDescCtor(ndxdp,
455 : *xfer->next_handle)) {
456 0 : NaClLog(LOG_ERROR,
457 : "NaClXferableDataDescInternalize: descriptor ctor error\n");
458 0 : rv = -NACL_ABI_EIO;
459 0 : goto cleanup;
460 : }
461 0 : *xfer->next_handle++ = NACL_INVALID_HANDLE;
462 0 : *baseptr = (struct NaClDesc *) ndxdp;
463 0 : rv = 0;
464 :
465 0 : cleanup:
466 0 : if (rv < 0) {
467 0 : free(ndxdp);
468 : }
469 0 : return rv;
470 : }
|