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