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 1388 : static int NaClDescIoDescSubclassCtor(struct NaClDescIoDesc *self,
50 1388 : struct NaClHostDesc *hd) {
51 1388 : struct NaClDesc *basep = (struct NaClDesc *) self;
52 :
53 1388 : self->hd = hd;
54 1388 : basep->base.vtbl = (struct NaClRefCountVtbl const *) &kNaClDescIoDescVtbl;
55 1388 : return 1;
56 : }
57 :
58 : /*
59 : * Takes ownership of hd, will close in Dtor.
60 : */
61 1351 : int NaClDescIoDescCtor(struct NaClDescIoDesc *self,
62 1351 : struct NaClHostDesc *hd) {
63 1351 : struct NaClDesc *basep = (struct NaClDesc *) self;
64 1351 : int rv;
65 :
66 1351 : basep->base.vtbl = (struct NaClRefCountVtbl const *) NULL;
67 1351 : if (!NaClDescCtor(basep)) {
68 0 : return 0;
69 : }
70 1351 : rv = NaClDescIoDescSubclassCtor(self, hd);
71 1351 : if (!rv) {
72 0 : (*NACL_VTBL(NaClRefCount, basep)->Dtor)((struct NaClRefCount *) basep);
73 0 : }
74 1351 : (*NACL_VTBL(NaClDesc, basep)->
75 : SetFlags)(basep, hd->flags & NACL_ABI_O_ACCMODE);
76 1351 : return rv;
77 1351 : }
78 :
79 975 : static void NaClDescIoDescDtor(struct NaClRefCount *vself) {
80 975 : struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
81 :
82 975 : NaClLog(4, "NaClDescIoDescDtor(0x%08"NACL_PRIxPTR").\n",
83 : (uintptr_t) vself);
84 975 : if (0 != NaClHostDescClose(self->hd)) {
85 0 : NaClLog(LOG_FATAL, "NaClDescIoDescDtor: NaClHostDescClose failed\n");
86 0 : }
87 975 : free(self->hd);
88 975 : self->hd = NULL;
89 975 : vself->vtbl = (struct NaClRefCountVtbl const *) &kNaClDescVtbl;
90 975 : (*vself->vtbl->Dtor)(vself);
91 975 : }
92 :
93 1349 : struct NaClDescIoDesc *NaClDescIoDescMake(struct NaClHostDesc *nhdp) {
94 1349 : struct NaClDescIoDesc *ndp;
95 :
96 1349 : ndp = malloc(sizeof *ndp);
97 1349 : if (NULL == ndp) {
98 0 : NaClLog(LOG_FATAL,
99 : "NaClDescIoDescMake: no memory for 0x%08"NACL_PRIxPTR"\n",
100 : (uintptr_t) nhdp);
101 0 : }
102 1349 : if (!NaClDescIoDescCtor(ndp, nhdp)) {
103 0 : NaClLog(LOG_FATAL,
104 : ("NaClDescIoDescMake:"
105 : " NaClDescIoDescCtor(0x%08"NACL_PRIxPTR",0x%08"NACL_PRIxPTR
106 : ") failed\n"),
107 : (uintptr_t) ndp,
108 : (uintptr_t) nhdp);
109 0 : }
110 1349 : return ndp;
111 : }
112 :
113 14 : struct NaClDesc *NaClDescIoDescFromHandleAllocCtor(NaClHandle handle,
114 14 : int flags) {
115 14 : 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 14 : posix_d = handle;
140 : #endif
141 14 : return NaClDescIoDescFromDescAllocCtor(posix_d, flags);
142 : }
143 :
144 22 : struct NaClDesc *NaClDescIoDescFromDescAllocCtor(int desc,
145 22 : int flags) {
146 22 : struct NaClHostDesc *nhdp;
147 :
148 22 : nhdp = NaClHostDescPosixMake(desc, flags);
149 22 : 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 22 : return (struct NaClDesc *) NaClDescIoDescMake(nhdp);
159 22 : }
160 :
161 294 : struct NaClDescIoDesc *NaClDescIoDescOpen(char const *path,
162 294 : int mode,
163 294 : int perms) {
164 294 : struct NaClHostDesc *nhdp;
165 :
166 294 : nhdp = malloc(sizeof *nhdp);
167 294 : if (NULL == nhdp) {
168 0 : NaClLog(LOG_FATAL, "NaClDescIoDescOpen: no memory for %s\n", path);
169 0 : }
170 294 : if (0 != NaClHostDescOpen(nhdp, path, mode, perms)) {
171 1 : NaClLog(4,
172 : "NaClDescIoDescOpen: NaClHostDescOpen failed for %s\n",
173 : path);
174 1 : return NULL;
175 : }
176 293 : return NaClDescIoDescMake(nhdp);
177 294 : }
178 :
179 71487 : static uintptr_t NaClDescIoDescMap(struct NaClDesc *vself,
180 71487 : struct NaClDescEffector *effp,
181 71487 : void *start_addr,
182 71487 : size_t len,
183 71487 : int prot,
184 71487 : int flags,
185 71487 : nacl_off64_t offset) {
186 71487 : struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
187 71487 : uintptr_t status;
188 71487 : uintptr_t addr;
189 :
190 : /*
191 : * prot must only contain NACL_ABI_PROT_* flags.
192 : */
193 71487 : if (0 != (~(NACL_ABI_PROT_MASK) & prot)) {
194 0 : NaClLog(LOG_INFO,
195 : ("NaClDescIoDescMap: prot has other bits"
196 : " than NACL_ABI_PROT_{READ|WRITE|EXEC}\n"));
197 0 : return -NACL_ABI_EINVAL;
198 : }
199 :
200 71487 : if (0 == (NACL_ABI_MAP_FIXED & flags)) {
201 19 : if (!NaClFindAddressSpace(&addr, len)) {
202 0 : NaClLog(1, "NaClDescIoDescMap: no address space?\n");
203 0 : return -NACL_ABI_ENOMEM;
204 : }
205 19 : NaClLog(4,
206 : "NaClDescIoDescMap: NaClFindAddressSpace"
207 : " returned 0x%"NACL_PRIxPTR"\n",
208 : addr);
209 19 : start_addr = (void *) addr;
210 19 : }
211 71487 : flags |= NACL_ABI_MAP_FIXED;
212 :
213 214461 : status = NaClHostDescMap((NULL == self) ? NULL : self->hd,
214 : effp,
215 : (void *) start_addr,
216 : len,
217 : prot,
218 : flags,
219 : offset);
220 71487 : NaClLog(4, "NaClDescIoDescMap returning %"NACL_PRIxPTR"\n", status);
221 71487 : return status;
222 71487 : }
223 :
224 71420 : uintptr_t NaClDescIoDescMapAnon(struct NaClDescEffector *effp,
225 71420 : void *start_addr,
226 71420 : size_t len,
227 71420 : int prot,
228 71420 : int flags,
229 71420 : nacl_off64_t offset) {
230 71420 : return NaClDescIoDescMap((struct NaClDesc *) NULL, effp, start_addr, len,
231 : prot, flags, offset);
232 : }
233 :
234 : #if NACL_WINDOWS
235 : static int NaClDescIoDescUnmapUnsafe(struct NaClDesc *vself,
236 : void *start_addr,
237 : size_t len) {
238 : UNREFERENCED_PARAMETER(vself);
239 : return NaClHostDescUnmapUnsafe(start_addr, len);
240 : }
241 : #endif
242 :
243 155 : static ssize_t NaClDescIoDescRead(struct NaClDesc *vself,
244 155 : void *buf,
245 155 : size_t len) {
246 155 : struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
247 :
248 155 : return NaClHostDescRead(self->hd, buf, len);
249 : }
250 :
251 58568 : static ssize_t NaClDescIoDescWrite(struct NaClDesc *vself,
252 58568 : void const *buf,
253 58568 : size_t len) {
254 58568 : struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
255 :
256 58568 : return NaClHostDescWrite(self->hd, buf, len);
257 : }
258 :
259 6752 : static nacl_off64_t NaClDescIoDescSeek(struct NaClDesc *vself,
260 6752 : nacl_off64_t offset,
261 6752 : int whence) {
262 6752 : struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
263 :
264 6752 : return NaClHostDescSeek(self->hd, offset, whence);
265 : }
266 :
267 1480 : static ssize_t NaClDescIoDescPRead(struct NaClDesc *vself,
268 1480 : void *buf,
269 1480 : size_t len,
270 1480 : nacl_off64_t offset) {
271 1480 : struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
272 :
273 1480 : return NaClHostDescPRead(self->hd, buf, len, offset);
274 : }
275 :
276 10 : static ssize_t NaClDescIoDescPWrite(struct NaClDesc *vself,
277 10 : void const *buf,
278 10 : size_t len,
279 10 : nacl_off64_t offset) {
280 10 : struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
281 :
282 10 : return NaClHostDescPWrite(self->hd, buf, len, offset);
283 : }
284 :
285 237 : static int NaClDescIoDescFstat(struct NaClDesc *vself,
286 237 : struct nacl_abi_stat *statbuf) {
287 237 : struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
288 237 : int rv;
289 237 : nacl_host_stat_t hstatbuf;
290 :
291 237 : rv = NaClHostDescFstat(self->hd, &hstatbuf);
292 237 : if (0 != rv) {
293 0 : return rv;
294 : }
295 237 : return NaClAbiStatHostDescStatXlateCtor(statbuf, &hstatbuf);
296 237 : }
297 :
298 2 : static int32_t NaClDescIoIsatty(struct NaClDesc *vself) {
299 2 : struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
300 :
301 2 : return NaClHostDescIsatty(self->hd);
302 : }
303 :
304 49 : static int NaClDescIoDescExternalizeSize(struct NaClDesc *vself,
305 49 : size_t *nbytes,
306 49 : size_t *nhandles) {
307 49 : struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
308 49 : int rv;
309 :
310 49 : rv = NaClDescExternalizeSize(vself, nbytes, nhandles);
311 49 : if (0 != rv) {
312 0 : return rv;
313 : }
314 49 : *nhandles += 1;
315 49 : *nbytes += sizeof self->hd->flags;
316 : /* For Windows, we do not need to send flProtect since it is a cache */
317 49 : return 0;
318 49 : }
319 :
320 49 : static int NaClDescIoDescExternalize(struct NaClDesc *vself,
321 49 : struct NaClDescXferState *xfer) {
322 49 : struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
323 49 : int rv;
324 : #if NACL_WINDOWS
325 : HANDLE h;
326 : #endif
327 :
328 49 : rv = NaClDescExternalize(vself, xfer);
329 49 : if (0 != rv) {
330 0 : return rv;
331 : }
332 :
333 147 : memcpy(xfer->next_byte, &self->hd->flags, sizeof self->hd->flags);
334 49 : xfer->next_byte += sizeof self->hd->flags;
335 : #if NACL_WINDOWS
336 : h = (HANDLE) _get_osfhandle(self->hd->d);
337 : *xfer->next_handle++ = (NaClHandle) h;
338 : #else
339 49 : *xfer->next_handle++ = self->hd->d;
340 : #endif
341 49 : return 0;
342 49 : }
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 38 : int NaClDescIoInternalize(struct NaClDesc **out_desc,
389 38 : struct NaClDescXferState *xfer,
390 38 : struct NaClDescQuotaInterface *quota_interface) {
391 38 : int rv;
392 38 : NaClHandle h;
393 38 : int d;
394 38 : int flags;
395 38 : struct NaClHostDesc *nhdp;
396 38 : struct NaClDescIoDesc *ndidp;
397 :
398 76 : UNREFERENCED_PARAMETER(quota_interface);
399 38 : rv = -NACL_ABI_EIO; /* catch-all */
400 38 : h = NACL_INVALID_HANDLE;
401 38 : nhdp = NULL;
402 38 : ndidp = NULL;
403 :
404 38 : nhdp = malloc(sizeof *nhdp);
405 38 : if (NULL == nhdp) {
406 0 : rv = -NACL_ABI_ENOMEM;
407 0 : goto cleanup;
408 : }
409 38 : ndidp = malloc(sizeof *ndidp);
410 38 : if (!ndidp) {
411 0 : rv = -NACL_ABI_ENOMEM;
412 0 : goto cleanup;
413 : }
414 38 : if (!NaClDescInternalizeCtor((struct NaClDesc *) ndidp, xfer)) {
415 0 : rv = -NACL_ABI_ENOMEM;
416 0 : goto cleanup;
417 : }
418 76 : if (xfer->next_handle == xfer->handle_buffer_end ||
419 : 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 76 : NACL_COMPILE_TIME_ASSERT(sizeof flags == sizeof(ndidp->hd->flags));
425 38 : memcpy(&flags, xfer->next_byte, sizeof flags);
426 38 : xfer->next_byte += sizeof flags;
427 :
428 38 : h = *xfer->next_handle;
429 38 : *xfer->next_handle++ = NACL_INVALID_HANDLE;
430 : #if NACL_WINDOWS
431 : if (-1 == (d = _open_osfhandle((intptr_t) h, _O_RDWR | _O_BINARY))) {
432 : rv = -NACL_ABI_EIO;
433 : goto cleanup_ndidp_dtor;
434 : }
435 : #else
436 38 : 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 38 : if ((rv = NaClHostDescPosixTake(nhdp, d, flags)) < 0) {
443 0 : goto cleanup_ndidp_dtor;
444 : }
445 38 : h = NACL_INVALID_HANDLE; /* nhdp took ownership of h */
446 :
447 38 : 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 38 : *out_desc = (struct NaClDesc *) ndidp;
455 38 : rv = 0;
456 : cleanup_nhdp_dtor:
457 38 : if (rv < 0) {
458 0 : if (0 != NaClHostDescClose(nhdp)) {
459 0 : NaClLog(LOG_FATAL, "NaClDescIoInternalize: NaClHostDescClose failed\n");
460 0 : }
461 38 : }
462 : cleanup_ndidp_dtor:
463 38 : if (rv < 0) {
464 0 : NaClDescSafeUnref((struct NaClDesc *) ndidp);
465 0 : ndidp = NULL;
466 38 : }
467 : cleanup:
468 38 : if (rv < 0) {
469 0 : free(nhdp);
470 0 : free(ndidp);
471 0 : if (NACL_INVALID_HANDLE != h) {
472 0 : (void) NaClClose(h);
473 0 : }
474 0 : }
475 38 : return rv;
476 : }
|