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. Memory
9 * mapping using descriptors.
10 */
11
12 #include "native_client/src/include/build_config.h"
13 #include "native_client/src/include/portability.h"
14
15 #if NACL_WINDOWS
16 # include "io.h"
17 # include "fcntl.h"
18 #endif
19
20 #include <string.h>
21
22 #include "native_client/src/include/nacl_macros.h"
23 #include "native_client/src/shared/imc/nacl_imc_c.h"
24 #include "native_client/src/trusted/desc/nacl_desc_base.h"
25 #include "native_client/src/trusted/desc/nacl_desc_effector.h"
26 #include "native_client/src/trusted/desc/nacl_desc_io.h"
27
28 #include "native_client/src/shared/platform/nacl_find_addrsp.h"
29 #include "native_client/src/shared/platform/nacl_host_desc.h"
30 #include "native_client/src/shared/platform/nacl_log.h"
31
32 #include "native_client/src/trusted/service_runtime/include/bits/mman.h"
33 #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
34 #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
35 #include "native_client/src/trusted/service_runtime/internal_errno.h"
36 #include "native_client/src/trusted/service_runtime/nacl_config.h"
37
38
39 /*
40 * This file contains the implementation for the NaClIoDesc subclass
41 * of NaClDesc.
42 *
43 * NaClDescIoDesc is the subclass that wraps host-OS descriptors
44 * provided by NaClHostDesc (which gives an OS-independent abstraction
45 * for host-OS descriptors).
46 */
47
48 static struct NaClDescVtbl const kNaClDescIoDescVtbl; /* fwd */
49
NaClDescIoDescSubclassCtor(struct NaClDescIoDesc * self,struct NaClHostDesc * hd)50 static int NaClDescIoDescSubclassCtor(struct NaClDescIoDesc *self,
51 struct NaClHostDesc *hd) {
52 struct NaClDesc *basep = (struct NaClDesc *) self;
53
54 self->hd = hd;
55 basep->base.vtbl = (struct NaClRefCountVtbl const *) &kNaClDescIoDescVtbl;
56 return 1;
57 }
58
59 /*
60 * Takes ownership of hd, will close in Dtor.
61 */
NaClDescIoDescCtor(struct NaClDescIoDesc * self,struct NaClHostDesc * hd)62 int NaClDescIoDescCtor(struct NaClDescIoDesc *self,
63 struct NaClHostDesc *hd) {
64 struct NaClDesc *basep = (struct NaClDesc *) self;
65 int rv;
66
67 basep->base.vtbl = (struct NaClRefCountVtbl const *) NULL;
68 if (!NaClDescCtor(basep)) {
69 return 0;
70 }
71 rv = NaClDescIoDescSubclassCtor(self, hd);
72 if (!rv) {
73 (*NACL_VTBL(NaClRefCount, basep)->Dtor)((struct NaClRefCount *) basep);
74 }
75 (*NACL_VTBL(NaClDesc, basep)->
76 SetFlags)(basep, hd->flags & NACL_ABI_O_ACCMODE);
77 return rv;
78 }
79
NaClDescIoDescDtor(struct NaClRefCount * vself)80 static void NaClDescIoDescDtor(struct NaClRefCount *vself) {
81 struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
82
83 NaClLog(4, "NaClDescIoDescDtor(0x%08"NACL_PRIxPTR").\n",
84 (uintptr_t) vself);
85 if (0 != NaClHostDescClose(self->hd)) {
86 NaClLog(LOG_FATAL, "NaClDescIoDescDtor: NaClHostDescClose failed\n");
87 }
88 free(self->hd);
89 self->hd = NULL;
90 vself->vtbl = (struct NaClRefCountVtbl const *) &kNaClDescVtbl;
91 (*vself->vtbl->Dtor)(vself);
92 }
93
NaClDescIoDescMake(struct NaClHostDesc * nhdp)94 struct NaClDescIoDesc *NaClDescIoDescMake(struct NaClHostDesc *nhdp) {
95 struct NaClDescIoDesc *ndp;
96
97 ndp = malloc(sizeof *ndp);
98 if (NULL == ndp) {
99 NaClLog(LOG_FATAL,
100 "NaClDescIoDescMake: no memory for 0x%08"NACL_PRIxPTR"\n",
101 (uintptr_t) nhdp);
102 }
103 if (!NaClDescIoDescCtor(ndp, nhdp)) {
104 NaClLog(LOG_FATAL,
105 ("NaClDescIoDescMake:"
106 " NaClDescIoDescCtor(0x%08"NACL_PRIxPTR",0x%08"NACL_PRIxPTR
107 ") failed\n"),
108 (uintptr_t) ndp,
109 (uintptr_t) nhdp);
110 }
111 return ndp;
112 }
113
NaClDescIoMakeFromHandle(NaClHandle handle,int flags)114 struct NaClDesc *NaClDescIoMakeFromHandle(NaClHandle handle, int flags) {
115 int posix_d;
116
117 #if NACL_WINDOWS
118 int win_flags = 0;
119
120 switch (flags & NACL_ABI_O_ACCMODE) {
121 case NACL_ABI_O_RDONLY:
122 win_flags = _O_RDONLY | _O_BINARY;
123 break;
124 case NACL_ABI_O_WRONLY:
125 win_flags = _O_WRONLY | _O_BINARY;
126 break;
127 case NACL_ABI_O_RDWR:
128 win_flags = _O_RDWR | _O_BINARY;
129 break;
130 }
131 if (0 == win_flags) {
132 return NULL;
133 }
134 posix_d = _open_osfhandle((intptr_t) handle, win_flags);
135 if (-1 == posix_d) {
136 return NULL;
137 }
138 #else
139 posix_d = handle;
140 #endif
141 return NaClDescIoDescFromDescAllocCtor(posix_d, flags);
142 }
143
NaClDescIoDescFromDescAllocCtor(int desc,int flags)144 struct NaClDesc *NaClDescIoDescFromDescAllocCtor(int desc,
145 int flags) {
146 struct NaClHostDesc *nhdp;
147
148 nhdp = NaClHostDescPosixMake(desc, flags);
149 if (NULL == nhdp) {
150 /*
151 * BUG: In Windows, we leak posix_d representation in the POSIX
152 * layer, since caller will continue to own |handle| on a failure
153 * return, but we cannot close |posix_d| without implicitly
154 * invoking CloseHandle on |handle|.
155 */
156 return NULL;
157 }
158 return (struct NaClDesc *) NaClDescIoDescMake(nhdp);
159 }
160
NaClDescIoDescOpen(char const * path,int mode,int perms)161 struct NaClDescIoDesc *NaClDescIoDescOpen(char const *path,
162 int mode,
163 int perms) {
164 struct NaClHostDesc *nhdp;
165
166 nhdp = malloc(sizeof *nhdp);
167 if (NULL == nhdp) {
168 NaClLog(LOG_FATAL, "NaClDescIoDescOpen: no memory for %s\n", path);
169 }
170 if (0 != NaClHostDescOpen(nhdp, path, mode, perms)) {
171 NaClLog(4,
172 "NaClDescIoDescOpen: NaClHostDescOpen failed for %s\n",
173 path);
174 return NULL;
175 }
176 return NaClDescIoDescMake(nhdp);
177 }
178
NaClDescIoDescMap(struct NaClDesc * vself,struct NaClDescEffector * effp,void * start_addr,size_t len,int prot,int flags,nacl_off64_t offset)179 static uintptr_t NaClDescIoDescMap(struct NaClDesc *vself,
180 struct NaClDescEffector *effp,
181 void *start_addr,
182 size_t len,
183 int prot,
184 int flags,
185 nacl_off64_t offset) {
186 struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
187 uintptr_t status;
188 uintptr_t addr;
189
190 /*
191 * prot must only contain NACL_ABI_PROT_* flags.
192 */
193 if (0 != (~(NACL_ABI_PROT_MASK) & prot)) {
194 NaClLog(LOG_INFO,
195 ("NaClDescIoDescMap: prot has other bits"
196 " than NACL_ABI_PROT_{READ|WRITE|EXEC}\n"));
197 return (uintptr_t) -NACL_ABI_EINVAL;
198 }
199
200 if (0 == (NACL_ABI_MAP_FIXED & flags)) {
201 if (!NaClFindAddressSpace(&addr, len)) {
202 NaClLog(1, "NaClDescIoDescMap: no address space?\n");
203 return (uintptr_t) -NACL_ABI_ENOMEM;
204 }
205 NaClLog(4,
206 "NaClDescIoDescMap: NaClFindAddressSpace"
207 " returned 0x%"NACL_PRIxPTR"\n",
208 addr);
209 start_addr = (void *) addr;
210 }
211 flags |= NACL_ABI_MAP_FIXED;
212
213 status = NaClHostDescMap((NULL == self) ? NULL : self->hd,
214 effp,
215 (void *) start_addr,
216 len,
217 prot,
218 flags,
219 offset);
220 NaClLog(4, "NaClDescIoDescMap returning %"NACL_PRIxPTR"\n", status);
221 return status;
222 }
223
NaClDescIoDescMapAnon(struct NaClDescEffector * effp,void * start_addr,size_t len,int prot,int flags,nacl_off64_t offset)224 uintptr_t NaClDescIoDescMapAnon(struct NaClDescEffector *effp,
225 void *start_addr,
226 size_t len,
227 int prot,
228 int flags,
229 nacl_off64_t offset) {
230 return NaClDescIoDescMap((struct NaClDesc *) NULL, effp, start_addr, len,
231 prot, flags, offset);
232 }
233
NaClDescIoDescRead(struct NaClDesc * vself,void * buf,size_t len)234 static ssize_t NaClDescIoDescRead(struct NaClDesc *vself,
235 void *buf,
236 size_t len) {
237 struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
238
239 return NaClHostDescRead(self->hd, buf, len);
240 }
241
NaClDescIoDescWrite(struct NaClDesc * vself,void const * buf,size_t len)242 static ssize_t NaClDescIoDescWrite(struct NaClDesc *vself,
243 void const *buf,
244 size_t len) {
245 struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
246
247 return NaClHostDescWrite(self->hd, buf, len);
248 }
249
NaClDescIoDescSeek(struct NaClDesc * vself,nacl_off64_t offset,int whence)250 static nacl_off64_t NaClDescIoDescSeek(struct NaClDesc *vself,
251 nacl_off64_t offset,
252 int whence) {
253 struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
254
255 return NaClHostDescSeek(self->hd, offset, whence);
256 }
257
NaClDescIoDescPRead(struct NaClDesc * vself,void * buf,size_t len,nacl_off64_t offset)258 static ssize_t NaClDescIoDescPRead(struct NaClDesc *vself,
259 void *buf,
260 size_t len,
261 nacl_off64_t offset) {
262 struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
263
264 return NaClHostDescPRead(self->hd, buf, len, offset);
265 }
266
NaClDescIoDescPWrite(struct NaClDesc * vself,void const * buf,size_t len,nacl_off64_t offset)267 static ssize_t NaClDescIoDescPWrite(struct NaClDesc *vself,
268 void const *buf,
269 size_t len,
270 nacl_off64_t offset) {
271 struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
272
273 return NaClHostDescPWrite(self->hd, buf, len, offset);
274 }
275
NaClDescIoDescFstat(struct NaClDesc * vself,struct nacl_abi_stat * statbuf)276 static int NaClDescIoDescFstat(struct NaClDesc *vself,
277 struct nacl_abi_stat *statbuf) {
278 struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
279 int rv;
280 nacl_host_stat_t hstatbuf;
281
282 rv = NaClHostDescFstat(self->hd, &hstatbuf);
283 if (0 != rv) {
284 return rv;
285 }
286 return NaClAbiStatHostDescStatXlateCtor(statbuf, &hstatbuf);
287 }
288
NaClDescIoDescFchmod(struct NaClDesc * vself,int mode)289 static int NaClDescIoDescFchmod(struct NaClDesc *vself,
290 int mode) {
291 struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
292
293 return NaClHostDescFchmod(self->hd, mode);
294 }
295
NaClDescIoDescFsync(struct NaClDesc * vself)296 static int NaClDescIoDescFsync(struct NaClDesc *vself) {
297 struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
298
299 return NaClHostDescFsync(self->hd);
300 }
301
NaClDescIoDescFdatasync(struct NaClDesc * vself)302 static int NaClDescIoDescFdatasync(struct NaClDesc *vself) {
303 struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
304
305 return NaClHostDescFdatasync(self->hd);
306 }
307
NaClDescIoDescFtruncate(struct NaClDesc * vself,nacl_abi_off_t length)308 static int NaClDescIoDescFtruncate(struct NaClDesc *vself,
309 nacl_abi_off_t length) {
310 struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
311
312 return NaClHostDescFtruncate(self->hd, length);
313 }
314
NaClDescIoIsatty(struct NaClDesc * vself)315 static int32_t NaClDescIoIsatty(struct NaClDesc *vself) {
316 struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
317
318 return NaClHostDescIsatty(self->hd);
319 }
320
NaClDescIoDescExternalizeSize(struct NaClDesc * vself,size_t * nbytes,size_t * nhandles)321 static int NaClDescIoDescExternalizeSize(struct NaClDesc *vself,
322 size_t *nbytes,
323 size_t *nhandles) {
324 struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
325 int rv;
326
327 rv = NaClDescExternalizeSize(vself, nbytes, nhandles);
328 if (0 != rv) {
329 return rv;
330 }
331 *nhandles += 1;
332 *nbytes += sizeof self->hd->flags;
333 /* For Windows, we do not need to send flProtect since it is a cache */
334 return 0;
335 }
336
NaClDescIoDescExternalize(struct NaClDesc * vself,struct NaClDescXferState * xfer)337 static int NaClDescIoDescExternalize(struct NaClDesc *vself,
338 struct NaClDescXferState *xfer) {
339 struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
340 int rv;
341 #if NACL_WINDOWS
342 HANDLE h;
343 #endif
344
345 rv = NaClDescExternalize(vself, xfer);
346 if (0 != rv) {
347 return rv;
348 }
349
350 memcpy(xfer->next_byte, &self->hd->flags, sizeof self->hd->flags);
351 xfer->next_byte += sizeof self->hd->flags;
352 #if NACL_WINDOWS
353 h = (HANDLE) _get_osfhandle(self->hd->d);
354 *xfer->next_handle++ = (NaClHandle) h;
355 #else
356 *xfer->next_handle++ = self->hd->d;
357 #endif
358 return 0;
359 }
360
361 static struct NaClDescVtbl const kNaClDescIoDescVtbl = {
362 {
363 NaClDescIoDescDtor,
364 },
365 NaClDescIoDescMap,
366 NaClDescIoDescRead,
367 NaClDescIoDescWrite,
368 NaClDescIoDescSeek,
369 NaClDescIoDescPRead,
370 NaClDescIoDescPWrite,
371 NaClDescIoDescFstat,
372 NaClDescFchdirNotImplemented,
373 NaClDescIoDescFchmod,
374 NaClDescIoDescFsync,
375 NaClDescIoDescFdatasync,
376 NaClDescIoDescFtruncate,
377 NaClDescGetdentsNotImplemented,
378 NaClDescIoDescExternalizeSize,
379 NaClDescIoDescExternalize,
380 NaClDescLockNotImplemented,
381 NaClDescTryLockNotImplemented,
382 NaClDescUnlockNotImplemented,
383 NaClDescWaitNotImplemented,
384 NaClDescTimedWaitAbsNotImplemented,
385 NaClDescSignalNotImplemented,
386 NaClDescBroadcastNotImplemented,
387 NaClDescSendMsgNotImplemented,
388 NaClDescRecvMsgNotImplemented,
389 NaClDescLowLevelSendMsgNotImplemented,
390 NaClDescLowLevelRecvMsgNotImplemented,
391 NaClDescConnectAddrNotImplemented,
392 NaClDescAcceptConnNotImplemented,
393 NaClDescPostNotImplemented,
394 NaClDescSemWaitNotImplemented,
395 NaClDescGetValueNotImplemented,
396 NaClDescSetMetadata,
397 NaClDescGetMetadata,
398 NaClDescSetFlags,
399 NaClDescGetFlags,
400 NaClDescIoIsatty,
401 NACL_DESC_HOST_IO,
402 };
403
404 /* set *out_desc to struct NaClDescIo * output */
NaClDescIoInternalize(struct NaClDesc ** out_desc,struct NaClDescXferState * xfer)405 int NaClDescIoInternalize(struct NaClDesc **out_desc,
406 struct NaClDescXferState *xfer) {
407 int rv;
408 NaClHandle h;
409 int d;
410 int flags;
411 struct NaClHostDesc *nhdp;
412 struct NaClDescIoDesc *ndidp;
413
414 rv = -NACL_ABI_EIO; /* catch-all */
415 h = NACL_INVALID_HANDLE;
416 nhdp = NULL;
417 ndidp = NULL;
418
419 nhdp = malloc(sizeof *nhdp);
420 if (NULL == nhdp) {
421 rv = -NACL_ABI_ENOMEM;
422 goto cleanup;
423 }
424 ndidp = malloc(sizeof *ndidp);
425 if (!ndidp) {
426 rv = -NACL_ABI_ENOMEM;
427 goto cleanup;
428 }
429 if (!NaClDescInternalizeCtor((struct NaClDesc *) ndidp, xfer)) {
430 rv = -NACL_ABI_ENOMEM;
431 goto cleanup;
432 }
433 if (xfer->next_handle == xfer->handle_buffer_end ||
434 xfer->next_byte + sizeof ndidp->hd->flags > xfer->byte_buffer_end) {
435 rv = -NACL_ABI_EIO;
436 goto cleanup_ndidp_dtor;
437 }
438
439 NACL_COMPILE_TIME_ASSERT(sizeof flags == sizeof(ndidp->hd->flags));
440 memcpy(&flags, xfer->next_byte, sizeof flags);
441 xfer->next_byte += sizeof flags;
442
443 h = *xfer->next_handle;
444 *xfer->next_handle++ = NACL_INVALID_HANDLE;
445 #if NACL_WINDOWS
446 if (-1 == (d = _open_osfhandle((intptr_t) h, _O_RDWR | _O_BINARY))) {
447 rv = -NACL_ABI_EIO;
448 goto cleanup_ndidp_dtor;
449 }
450 #else
451 d = h;
452 #endif
453 /*
454 * We mark it as read/write, but don't really know for sure until we
455 * try to make those syscalls (in which case we'd get EBADF).
456 */
457 if ((rv = NaClHostDescPosixTake(nhdp, d, flags)) < 0) {
458 goto cleanup_ndidp_dtor;
459 }
460 h = NACL_INVALID_HANDLE; /* nhdp took ownership of h */
461
462 if (!NaClDescIoDescSubclassCtor(ndidp, nhdp)) {
463 rv = -NACL_ABI_ENOMEM;
464 goto cleanup_nhdp_dtor;
465 }
466 /*
467 * ndidp took ownership of nhdp, now give ownership of ndidp to caller.
468 */
469 *out_desc = (struct NaClDesc *) ndidp;
470 rv = 0;
471 cleanup_nhdp_dtor:
472 if (rv < 0) {
473 if (0 != NaClHostDescClose(nhdp)) {
474 NaClLog(LOG_FATAL, "NaClDescIoInternalize: NaClHostDescClose failed\n");
475 }
476 }
477 cleanup_ndidp_dtor:
478 if (rv < 0) {
479 NaClDescSafeUnref((struct NaClDesc *) ndidp);
480 ndidp = NULL;
481 }
482 cleanup:
483 if (rv < 0) {
484 free(nhdp);
485 free(ndidp);
486 if (NACL_INVALID_HANDLE != h) {
487 (void) NaClClose(h);
488 }
489 }
490 return rv;
491 }
492