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. 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 "native_client/src/shared/imc/nacl_imc_c.h"
20 : #include "native_client/src/trusted/desc/nacl_desc_base.h"
21 : #include "native_client/src/trusted/desc/nacl_desc_effector.h"
22 : #include "native_client/src/trusted/desc/nacl_desc_io.h"
23 :
24 : #include "native_client/src/shared/platform/nacl_find_addrsp.h"
25 : #include "native_client/src/shared/platform/nacl_host_desc.h"
26 : #include "native_client/src/shared/platform/nacl_log.h"
27 :
28 : #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
29 : #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
30 : #include "native_client/src/trusted/service_runtime/include/sys/mman.h"
31 : #include "native_client/src/trusted/service_runtime/internal_errno.h"
32 : #include "native_client/src/trusted/service_runtime/nacl_config.h"
33 :
34 :
35 : /*
36 : * This file contains the implementation for the NaClIoDesc subclass
37 : * of NaClDesc.
38 : *
39 : * NaClDescIoDesc is the subclass that wraps host-OS descriptors
40 : * provided by NaClHostDesc (which gives an OS-independent abstraction
41 : * for host-OS descriptors).
42 : */
43 :
44 : static struct NaClDescVtbl const kNaClDescIoDescVtbl; /* fwd */
45 : /*
46 : * Takes ownership of hd, will close in Dtor.
47 : */
48 : int NaClDescIoDescCtor(struct NaClDescIoDesc *self,
49 94 : struct NaClHostDesc *hd) {
50 94 : struct NaClDesc *basep = (struct NaClDesc *) self;
51 :
52 94 : basep->base.vtbl = (struct NaClRefCountVtbl const *) NULL;
53 94 : if (!NaClDescCtor(basep)) {
54 0 : return 0;
55 : }
56 94 : self->hd = hd;
57 94 : basep->base.vtbl = (struct NaClRefCountVtbl const *) &kNaClDescIoDescVtbl;
58 94 : return 1;
59 : }
60 :
61 33 : static void NaClDescIoDescDtor(struct NaClRefCount *vself) {
62 33 : struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
63 :
64 33 : NaClLog(4, "NaClDescIoDescDtor(0x%08"NACL_PRIxPTR").\n",
65 : (uintptr_t) vself);
66 33 : NaClHostDescClose(self->hd);
67 33 : free(self->hd);
68 33 : self->hd = NULL;
69 33 : vself->vtbl = (struct NaClRefCountVtbl const *) &kNaClDescVtbl;
70 33 : (*vself->vtbl->Dtor)(vself);
71 33 : }
72 :
73 93 : struct NaClDescIoDesc *NaClDescIoDescMake(struct NaClHostDesc *nhdp) {
74 : struct NaClDescIoDesc *ndp;
75 :
76 93 : ndp = malloc(sizeof *ndp);
77 93 : if (NULL == ndp) {
78 0 : NaClLog(LOG_FATAL,
79 : "NaClDescIoDescMake: no memory for 0x%08"NACL_PRIxPTR"\n",
80 : (uintptr_t) nhdp);
81 : }
82 93 : if (!NaClDescIoDescCtor(ndp, nhdp)) {
83 0 : NaClLog(LOG_FATAL,
84 : ("NaClDescIoDescMake:"
85 : " NaClDescIoDescCtor(0x%08"NACL_PRIxPTR",0x%08"NACL_PRIxPTR
86 : ") failed\n"),
87 : (uintptr_t) ndp,
88 : (uintptr_t) nhdp);
89 : }
90 93 : return ndp;
91 : }
92 :
93 : struct NaClDescIoDesc *NaClDescIoDescOpen(char *path,
94 : int mode,
95 4 : int perms) {
96 : struct NaClHostDesc *nhdp;
97 :
98 4 : nhdp = malloc(sizeof *nhdp);
99 4 : if (NULL == nhdp) {
100 0 : NaClLog(LOG_FATAL, "NaClDescIoDescOpen: no memory for %s\n", path);
101 : }
102 4 : if (0 != NaClHostDescOpen(nhdp, path, mode, perms)) {
103 0 : NaClLog(LOG_FATAL, "NaClDescIoDescOpen: NaClHostDescOpen failed for %s\n",
104 : path);
105 : }
106 4 : return NaClDescIoDescMake(nhdp);
107 : }
108 :
109 : static uintptr_t NaClDescIoDescMap(struct NaClDesc *vself,
110 : struct NaClDescEffector *effp,
111 : void *start_addr,
112 : size_t len,
113 : int prot,
114 : int flags,
115 3 : nacl_off64_t offset) {
116 3 : struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
117 : int rv;
118 : uintptr_t status;
119 : uintptr_t addr;
120 : uintptr_t end_addr;
121 : nacl_off64_t tmp_off;
122 :
123 : /*
124 : * prot must be PROT_NONE or a combination of PROT_{READ|WRITE}
125 : */
126 3 : if (0 != (~(NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE) & prot)) {
127 0 : NaClLog(LOG_INFO,
128 : ("NaClDescIoDescMap: prot has other bits"
129 : " than PROT_{READ|WRITE}\n"));
130 0 : return -NACL_ABI_EINVAL;
131 : }
132 :
133 3 : if (0 == (NACL_ABI_MAP_FIXED & flags) && NULL == start_addr) {
134 0 : NaClLog(LOG_INFO,
135 : ("NaClDescIoDescMap: Mapping not NACL_ABI_MAP_FIXED"
136 : " but start_addr is NULL\n"));
137 : }
138 :
139 3 : if (0 == (NACL_ABI_MAP_FIXED & flags)) {
140 0 : if (!NaClFindAddressSpace(&addr, len)) {
141 0 : NaClLog(1, "NaClDescIoDescMap: no address space?\n");
142 0 : return -NACL_ABI_ENOMEM;
143 : }
144 0 : start_addr = (void *) addr;
145 : }
146 3 : flags |= NACL_ABI_MAP_FIXED;
147 :
148 : for (addr = (uintptr_t) start_addr,
149 : end_addr = addr + len,
150 3 : tmp_off = offset;
151 9 : addr < end_addr;
152 : addr += NACL_MAP_PAGESIZE,
153 3 : tmp_off += NACL_MAP_PAGESIZE) {
154 : size_t map_size;
155 :
156 3 : if (0 != (rv = (*effp->vtbl->UnmapMemory)(effp,
157 : addr,
158 : NACL_MAP_PAGESIZE))) {
159 0 : NaClLog(LOG_FATAL,
160 : ("NaClDescIoDescMap: error %d --"
161 : " could not unmap 0x%08"NACL_PRIxPTR
162 : ", length 0x%"NACL_PRIxS"\n"),
163 : rv,
164 : addr,
165 : (size_t) NACL_MAP_PAGESIZE);
166 : }
167 :
168 3 : map_size = end_addr - addr;
169 3 : if (map_size > NACL_MAP_PAGESIZE) {
170 0 : map_size = NACL_MAP_PAGESIZE;
171 : }
172 3 : status = NaClHostDescMap((NULL == self) ? NULL : self->hd,
173 : (void *) addr,
174 : map_size,
175 : prot,
176 : flags,
177 : tmp_off);
178 3 : if (NACL_MAP_FAILED == (void *) status) {
179 0 : return -NACL_ABI_E_MOVE_ADDRESS_SPACE;
180 : }
181 : }
182 3 : return (uintptr_t) start_addr;
183 : }
184 :
185 : uintptr_t NaClDescIoDescMapAnon(struct NaClDescEffector *effp,
186 : void *start_addr,
187 : size_t len,
188 : int prot,
189 : int flags,
190 2 : nacl_off64_t offset) {
191 2 : return NaClDescIoDescMap((struct NaClDesc *) NULL, effp, start_addr, len,
192 : prot, flags, offset);
193 : }
194 :
195 : static int NaClDescIoDescUnmapCommon(struct NaClDesc *vself,
196 : struct NaClDescEffector *effp,
197 : void *start_addr,
198 : size_t len,
199 0 : int safe_mode) {
200 : int status;
201 :
202 : UNREFERENCED_PARAMETER(vself);
203 : UNREFERENCED_PARAMETER(effp);
204 :
205 0 : if (safe_mode) {
206 0 : status = NaClHostDescUnmap(start_addr, len);
207 : } else {
208 0 : status = NaClHostDescUnmapUnsafe(start_addr, len);
209 : }
210 :
211 0 : return status;
212 : }
213 :
214 : /*
215 : * NB: User code should never be able to invoke the Unsafe method.
216 : */
217 : static int NaClDescIoDescUnmapUnsafe(struct NaClDesc *vself,
218 : struct NaClDescEffector *effp,
219 : void *start_addr,
220 0 : size_t len) {
221 0 : return NaClDescIoDescUnmapCommon(vself, effp, start_addr, len, 0);
222 : }
223 :
224 : static int NaClDescIoDescUnmap(struct NaClDesc *vself,
225 : struct NaClDescEffector *effp,
226 : void *start_addr,
227 0 : size_t len) {
228 0 : return NaClDescIoDescUnmapCommon(vself, effp, start_addr, len, 1);
229 : }
230 :
231 : static ssize_t NaClDescIoDescRead(struct NaClDesc *vself,
232 : void *buf,
233 116 : size_t len) {
234 116 : struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
235 :
236 116 : return NaClHostDescRead(self->hd, buf, len);
237 : }
238 :
239 : static ssize_t NaClDescIoDescWrite(struct NaClDesc *vself,
240 : void const *buf,
241 6805 : size_t len) {
242 6805 : struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
243 :
244 6805 : return NaClHostDescWrite(self->hd, buf, len);
245 : }
246 :
247 : static nacl_off64_t NaClDescIoDescSeek(struct NaClDesc *vself,
248 : nacl_off64_t offset,
249 6700 : int whence) {
250 6700 : struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
251 :
252 6700 : return NaClHostDescSeek(self->hd, offset, whence);
253 : }
254 :
255 : static int NaClDescIoDescIoctl(struct NaClDesc *vself,
256 : int request,
257 0 : void *arg) {
258 0 : struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
259 :
260 0 : return NaClHostDescIoctl(self->hd, request, arg);
261 : }
262 :
263 : static int NaClDescIoDescFstat(struct NaClDesc *vself,
264 6 : struct nacl_abi_stat *statbuf) {
265 6 : struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
266 : int rv;
267 : nacl_host_stat_t hstatbuf;
268 :
269 6 : rv = NaClHostDescFstat(self->hd, &hstatbuf);
270 6 : if (0 != rv) {
271 0 : return rv;
272 : }
273 6 : return NaClAbiStatHostDescStatXlateCtor(statbuf, &hstatbuf);
274 : }
275 :
276 : static int NaClDescIoDescExternalizeSize(struct NaClDesc *vself,
277 : size_t *nbytes,
278 13 : size_t *nhandles) {
279 : UNREFERENCED_PARAMETER(vself);
280 :
281 13 : *nbytes = 0;
282 13 : *nhandles = 1;
283 13 : return 0;
284 : }
285 :
286 : static int NaClDescIoDescExternalize(struct NaClDesc *vself,
287 13 : struct NaClDescXferState *xfer) {
288 13 : struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
289 :
290 : #if NACL_WINDOWS
291 : HANDLE h = (HANDLE) _get_osfhandle(self->hd->d);
292 :
293 : NaClLog(LOG_WARNING, "NaClDescIoDescExternalize is EXPERIMENTAL\n");
294 : NaClLog(LOG_WARNING, "handle 0x%x\n", (uintptr_t) h);
295 :
296 : *xfer->next_handle++ = (NaClHandle) h;
297 : #else
298 13 : *xfer->next_handle++ = self->hd->d;
299 : #endif
300 13 : return 0;
301 : }
302 :
303 : static struct NaClDescVtbl const kNaClDescIoDescVtbl = {
304 : {
305 : NaClDescIoDescDtor,
306 : },
307 : NaClDescIoDescMap,
308 : NaClDescIoDescUnmapUnsafe,
309 : NaClDescIoDescUnmap,
310 : NaClDescIoDescRead,
311 : NaClDescIoDescWrite,
312 : NaClDescIoDescSeek,
313 : NaClDescIoDescIoctl,
314 : NaClDescIoDescFstat,
315 : NaClDescGetdentsNotImplemented,
316 : NACL_DESC_HOST_IO,
317 : NaClDescIoDescExternalizeSize,
318 : NaClDescIoDescExternalize,
319 : NaClDescLockNotImplemented,
320 : NaClDescTryLockNotImplemented,
321 : NaClDescUnlockNotImplemented,
322 : NaClDescWaitNotImplemented,
323 : NaClDescTimedWaitAbsNotImplemented,
324 : NaClDescSignalNotImplemented,
325 : NaClDescBroadcastNotImplemented,
326 : NaClDescSendMsgNotImplemented,
327 : NaClDescRecvMsgNotImplemented,
328 : NaClDescConnectAddrNotImplemented,
329 : NaClDescAcceptConnNotImplemented,
330 : NaClDescPostNotImplemented,
331 : NaClDescSemWaitNotImplemented,
332 : NaClDescGetValueNotImplemented,
333 : };
334 :
335 : /* set *out_desc to struct NaClDescIo * output */
336 : int NaClDescIoInternalize(struct NaClDesc **out_desc,
337 : struct NaClDescXferState *xfer,
338 1 : struct NaClDescQuotaInterface *quota_interface) {
339 : int rv;
340 : NaClHandle h;
341 : int d;
342 : struct NaClHostDesc *nhdp;
343 : struct NaClDescIoDesc *ndidp;
344 :
345 : UNREFERENCED_PARAMETER(quota_interface);
346 1 : rv = -NACL_ABI_EIO; /* catch-all */
347 1 : h = NACL_INVALID_HANDLE;
348 1 : nhdp = NULL;
349 1 : ndidp = NULL;
350 :
351 1 : if (xfer->next_handle == xfer->handle_buffer_end) {
352 0 : rv = -NACL_ABI_EIO;
353 0 : goto cleanup;
354 : }
355 1 : nhdp = malloc(sizeof *nhdp);
356 1 : if (NULL == nhdp) {
357 0 : rv = -NACL_ABI_ENOMEM;
358 0 : goto cleanup;
359 : }
360 1 : ndidp = malloc(sizeof *ndidp);
361 1 : if (!ndidp) {
362 0 : rv = -NACL_ABI_ENOMEM;
363 0 : goto cleanup;
364 : }
365 1 : h = *xfer->next_handle;
366 1 : *xfer->next_handle++ = NACL_INVALID_HANDLE;
367 : #if NACL_WINDOWS
368 : if (-1 == (d = _open_osfhandle((intptr_t) h, _O_RDWR | _O_BINARY))) {
369 : rv = -NACL_ABI_EIO;
370 : goto cleanup;
371 : }
372 : #else
373 1 : d = h;
374 : #endif
375 : /*
376 : * We mark it as read/write, but don't really know for sure until we
377 : * try to make those syscalls (in which case we'd get EBADF).
378 : */
379 1 : if ((rv = NaClHostDescPosixTake(nhdp, d, NACL_ABI_O_RDWR)) < 0) {
380 0 : goto cleanup;
381 : }
382 1 : h = NACL_INVALID_HANDLE; /* nhdp took ownership of h */
383 :
384 1 : if (!NaClDescIoDescCtor(ndidp, nhdp)) {
385 0 : rv = -NACL_ABI_ENOMEM;
386 0 : goto cleanup_hd_dtor;
387 : }
388 : /*
389 : * ndidp took ownership of nhdp, now give ownership of ndidp to caller.
390 : */
391 1 : *out_desc = (struct NaClDesc *) ndidp;
392 1 : rv = 0;
393 1 : cleanup_hd_dtor:
394 1 : if (rv < 0) {
395 0 : (void) NaClHostDescClose(nhdp);
396 : }
397 1 : cleanup:
398 1 : if (rv < 0) {
399 0 : free(nhdp);
400 0 : free(ndidp);
401 0 : if (NACL_INVALID_HANDLE != h) {
402 0 : (void) NaClClose(h);
403 : }
404 : }
405 1 : return rv;
406 : }
|