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. Memory
9 : * mapping using descriptors.
10 : *
11 : * Note that we avoid using the thread-specific data / thread local
12 : * storage access to the "errno" variable, and instead use the raw
13 : * system call return interface of small negative numbers as errors.
14 : */
15 :
16 : #include <stdint.h>
17 : #include <sys/types.h>
18 : #include <sys/stat.h>
19 : #include <fcntl.h>
20 : #include <errno.h>
21 : #include <sys/mman.h>
22 : #include <unistd.h>
23 :
24 : #include "native_client/src/include/nacl_platform.h"
25 : #include "native_client/src/include/portability.h"
26 :
27 : #include "native_client/src/shared/platform/nacl_host_desc.h"
28 : #include "native_client/src/shared/platform/nacl_log.h"
29 :
30 : #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
31 : #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
32 : #include "native_client/src/trusted/service_runtime/include/bits/mman.h"
33 : #include "native_client/src/trusted/service_runtime/include/sys/stat.h"
34 :
35 :
36 : /*
37 : * Map our ABI to the host OS's ABI. On linux, this should be a big no-op.
38 : */
39 29 : static INLINE int NaClMapOpenFlags(int nacl_flags) {
40 : int host_os_flags;
41 :
42 29 : nacl_flags &= (NACL_ABI_O_ACCMODE | NACL_ABI_O_CREAT
43 : | NACL_ABI_O_TRUNC | NACL_ABI_O_APPEND);
44 :
45 29 : host_os_flags = 0;
46 : #define C(H) case NACL_ABI_ ## H: \
47 : host_os_flags |= H; \
48 : break;
49 29 : switch (nacl_flags & NACL_ABI_O_ACCMODE) {
50 18 : C(O_RDONLY);
51 5 : C(O_WRONLY);
52 6 : C(O_RDWR);
53 : }
54 : #undef C
55 : #define M(H) do { \
56 : if (0 != (nacl_flags & NACL_ABI_ ## H)) { \
57 : host_os_flags |= H; \
58 : } \
59 : } while (0)
60 29 : M(O_CREAT);
61 29 : M(O_TRUNC);
62 29 : M(O_APPEND);
63 : #undef M
64 29 : return host_os_flags;
65 : }
66 :
67 29 : static INLINE int NaClMapOpenPerm(int nacl_perm) {
68 : int host_os_perm;
69 :
70 29 : host_os_perm = 0;
71 : #define M(H) do { \
72 : if (0 != (nacl_perm & NACL_ABI_ ## H)) { \
73 : host_os_perm |= H; \
74 : } \
75 : } while (0)
76 29 : M(S_IRUSR);
77 29 : M(S_IWUSR);
78 : #undef M
79 29 : return host_os_perm;
80 : }
81 :
82 4 : static INLINE int NaClMapFlagMap(int nacl_map_flags) {
83 : int host_os_flags;
84 :
85 4 : host_os_flags = 0;
86 : #define M(H) do { \
87 : if (0 != (nacl_map_flags & NACL_ABI_ ## H)) { \
88 : host_os_flags |= H; \
89 : } \
90 : } while (0)
91 4 : M(MAP_SHARED);
92 4 : M(MAP_PRIVATE);
93 4 : M(MAP_FIXED);
94 4 : M(MAP_ANONYMOUS);
95 : #undef M
96 :
97 4 : return host_os_flags;
98 : }
99 :
100 : /*
101 : * TODO(bsy): handle the !NACL_ABI_MAP_FIXED case.
102 : */
103 : uintptr_t NaClHostDescMap(struct NaClHostDesc *d,
104 : void *start_addr,
105 : size_t len,
106 : int prot,
107 : int flags,
108 4 : nacl_off64_t offset) {
109 : int desc;
110 : void *map_addr;
111 : int host_prot;
112 : int host_flags;
113 :
114 4 : NaClLog(4,
115 : ("NaClHostDescMap(0x%08"NACL_PRIxPTR", "
116 : "0x%08"NACL_PRIxPTR", 0x%08"NACL_PRIxS", "
117 : "0x%x, 0x%x, 0x%08"NACL_PRIx64")\n"),
118 : (uintptr_t) d,
119 : (uintptr_t) start_addr,
120 : len,
121 : prot,
122 : flags,
123 : (int64_t) offset);
124 4 : if (NULL == d && 0 == (flags & NACL_ABI_MAP_ANONYMOUS)) {
125 0 : NaClLog(LOG_FATAL, "NaClHostDescMap: 'this' is NULL and not anon map\n");
126 : }
127 4 : prot &= (NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE);
128 : /* may be PROT_NONE too, just not PROT_EXEC */
129 :
130 :
131 4 : if (flags & NACL_ABI_MAP_ANONYMOUS) {
132 3 : desc = -1;
133 : } else {
134 1 : desc = d->d;
135 : }
136 : /*
137 : * Translate flags, prot to host_flags, host_prot.
138 : */
139 4 : host_flags = NaClMapFlagMap(flags);
140 4 : host_prot = NaClProtMap(prot);
141 :
142 4 : NaClLog(4, "NaClHostDescMap: host_flags 0x%x, host_prot 0x%x\n",
143 : host_flags, host_prot);
144 :
145 4 : map_addr = mmap(start_addr, len, host_prot, host_flags, desc, offset);
146 :
147 4 : if (MAP_FAILED == map_addr) {
148 0 : NaClLog(LOG_INFO,
149 : ("NaClHostDescMap: "
150 : "mmap(0x%08"NACL_PRIxPTR", 0x%"NACL_PRIxS", "
151 : "0x%x, 0x%x, 0x%d, 0x%"NACL_PRIx64")"
152 : " failed, errno %d.\n"),
153 : (uintptr_t) start_addr, len, host_prot, host_flags, desc,
154 : (int64_t) offset,
155 : errno);
156 0 : return -NaClXlateErrno(errno);
157 : }
158 4 : if (0 != (flags & NACL_ABI_MAP_FIXED) && map_addr != start_addr) {
159 0 : NaClLog(LOG_FATAL,
160 : ("NaClHostDescMap: mmap with MAP_FIXED not fixed:"
161 : " returned 0x%08"NACL_PRIxPTR" instead of 0x%08"NACL_PRIxPTR"\n"),
162 : (uintptr_t) map_addr,
163 : (uintptr_t) start_addr);
164 : }
165 4 : NaClLog(4, "NaClHostDescMap: returning 0x%08"NACL_PRIxPTR"\n",
166 : (uintptr_t) start_addr);
167 :
168 4 : return (uintptr_t) start_addr;
169 : }
170 :
171 : int NaClHostDescUnmapUnsafe(void *start_addr,
172 0 : size_t len) {
173 : int retval;
174 0 : return ((-1 == (retval = munmap(start_addr, len)))
175 : ? -NaClXlateErrno(errno)
176 : : retval);
177 : }
178 :
179 : int NaClHostDescUnmap(void *start_addr,
180 0 : size_t len) {
181 : int retval;
182 0 : return ((-1 == (retval = (uintptr_t) mmap(start_addr,
183 : len,
184 : PROT_NONE,
185 : (MAP_PRIVATE
186 : | MAP_ANONYMOUS | MAP_FIXED),
187 : -1,
188 : (nacl_off64_t) 0)))
189 : ? -NaClXlateErrno(errno) : retval);
190 : }
191 :
192 : int NaClHostDescCtor(struct NaClHostDesc *d,
193 25 : int fd) {
194 25 : d->d = fd;
195 25 : NaClLog(3, "NaClHostDescCtor: success.\n");
196 25 : return 0;
197 : }
198 :
199 : int NaClHostDescOpen(struct NaClHostDesc *d,
200 : char const *path,
201 : int flags,
202 29 : int mode) {
203 : int host_desc;
204 : struct stat stbuf;
205 :
206 29 : NaClLog(3, "NaClHostDescOpen(0x%08"NACL_PRIxPTR", %s, 0x%x, 0x%x)\n",
207 : (uintptr_t) d, path, flags, mode);
208 29 : if (NULL == d) {
209 0 : NaClLog(LOG_FATAL, "NaClHostDescOpen: 'this' is NULL\n");
210 : }
211 : /*
212 : * Sanitize access flags.
213 : */
214 29 : if (0 != (flags & ~NACL_ALLOWED_OPEN_FLAGS)) {
215 0 : return -NACL_ABI_EINVAL;
216 : }
217 :
218 29 : switch (flags & NACL_ABI_O_ACCMODE) {
219 : case NACL_ABI_O_RDONLY:
220 : case NACL_ABI_O_WRONLY:
221 : case NACL_ABI_O_RDWR:
222 : break;
223 : default:
224 0 : NaClLog(LOG_ERROR,
225 : "NaClHostDescOpen: bad access flags 0x%x.\n",
226 : flags);
227 0 : return -NACL_ABI_EINVAL;
228 : }
229 :
230 29 : flags = NaClMapOpenFlags(flags);
231 29 : mode = NaClMapOpenPerm(mode);
232 :
233 29 : NaClLog(3, "NaClHostDescOpen: invoking POSIX open(%s,0x%x,0%o)\n",
234 : path, flags, mode);
235 29 : host_desc = open(path, flags, mode);
236 29 : NaClLog(3, "NaClHostDescOpen: got descriptor %d\n", host_desc);
237 29 : if (-1 == host_desc) {
238 4 : NaClLog(LOG_ERROR,
239 : "NaClHostDescOpen: open returned -1, errno %d\n", errno);
240 4 : return -NaClXlateErrno(errno);
241 : }
242 25 : if (-1 == fstat(host_desc, &stbuf)) {
243 0 : NaClLog(LOG_ERROR,
244 : "NaClHostDescOpen: fstat failed?!? errno %d\n", errno);
245 0 : (void) close(host_desc);
246 0 : return -NaClXlateErrno(errno);
247 : }
248 25 : if (!S_ISREG(stbuf.st_mode)) {
249 0 : NaClLog(LOG_INFO,
250 : "NaClHostDescOpen: file type 0x%x, not regular\n", stbuf.st_mode);
251 0 : (void) close(host_desc);
252 : /* cannot access anything other than a real file */
253 0 : return -NACL_ABI_EPERM;
254 : }
255 25 : return NaClHostDescCtor(d, host_desc);
256 : }
257 :
258 : int NaClHostDescPosixDup(struct NaClHostDesc *d,
259 : int posix_d,
260 0 : int flags) {
261 : int host_desc;
262 :
263 0 : if (NULL == d) {
264 0 : NaClLog(LOG_FATAL, "NaClHostDescPosixDup: 'this' is NULL\n");
265 : }
266 : /*
267 : * Sanitize access flags.
268 : */
269 0 : if (0 != (flags & ~NACL_ALLOWED_OPEN_FLAGS)) {
270 0 : return -NACL_ABI_EINVAL;
271 : }
272 :
273 0 : switch (flags & NACL_ABI_O_ACCMODE) {
274 : case NACL_ABI_O_RDONLY:
275 : case NACL_ABI_O_WRONLY:
276 : case NACL_ABI_O_RDWR:
277 : break;
278 : default:
279 0 : NaClLog(LOG_ERROR,
280 : "NaClHostDescPosixDup: bad access flags 0x%x.\n",
281 : flags);
282 0 : return -NACL_ABI_EINVAL;
283 : }
284 :
285 0 : host_desc = dup(posix_d);
286 0 : if (-1 == host_desc) {
287 0 : return -NACL_ABI_EINVAL;
288 : }
289 0 : d->d = host_desc;
290 0 : return 0;
291 : }
292 :
293 : int NaClHostDescPosixTake(struct NaClHostDesc *d,
294 : int posix_d,
295 68 : int flags) {
296 68 : if (NULL == d) {
297 0 : NaClLog(LOG_FATAL, "NaClHostDescPosixTake: 'this' is NULL\n");
298 : }
299 : /*
300 : * Sanitize access flags.
301 : */
302 68 : if (0 != (flags & ~NACL_ALLOWED_OPEN_FLAGS)) {
303 0 : return -NACL_ABI_EINVAL;
304 : }
305 :
306 68 : switch (flags & NACL_ABI_O_ACCMODE) {
307 : case NACL_ABI_O_RDONLY:
308 : case NACL_ABI_O_WRONLY:
309 : case NACL_ABI_O_RDWR:
310 : break;
311 : default:
312 0 : NaClLog(LOG_ERROR,
313 : "NaClHostDescPosixTake: bad access flags 0x%x.\n",
314 : flags);
315 0 : return -NACL_ABI_EINVAL;
316 : }
317 :
318 68 : d->d = posix_d;
319 68 : return 0;
320 : }
321 :
322 : ssize_t NaClHostDescRead(struct NaClHostDesc *d,
323 : void *buf,
324 116 : size_t len) {
325 : ssize_t retval;
326 :
327 116 : if (NULL == d) {
328 0 : NaClLog(LOG_FATAL, "NaClHostDescRead: 'this' is NULL\n");
329 : }
330 116 : return ((-1 == (retval = read(d->d, buf, len)))
331 : ? -NaClXlateErrno(errno) : retval);
332 : }
333 :
334 : ssize_t NaClHostDescWrite(struct NaClHostDesc *d,
335 : void const *buf,
336 6805 : size_t len) {
337 : ssize_t retval;
338 :
339 6805 : if (NULL == d) {
340 0 : NaClLog(LOG_FATAL, "NaClHostDescWrite: 'this' is NULL\n");
341 : }
342 6805 : return ((-1 == (retval = write(d->d, buf, len)))
343 : ? -NaClXlateErrno(errno) : retval);
344 : }
345 :
346 : nacl_off64_t NaClHostDescSeek(struct NaClHostDesc *d,
347 : nacl_off64_t offset,
348 6700 : int whence) {
349 : nacl_off64_t retval;
350 :
351 6700 : if (NULL == d) {
352 0 : NaClLog(LOG_FATAL, "NaClHostDescSeek: 'this' is NULL\n");
353 : }
354 : #if NACL_LINUX
355 : return ((-1 == (retval = lseek64(d->d, offset, whence)))
356 : ? -NaClXlateErrno(errno) : retval);
357 : #elif NACL_OSX
358 6700 : return ((-1 == (retval = lseek(d->d, offset, whence)))
359 : ? -NaClXlateErrno(errno) : retval);
360 : #else
361 : # error "What Unix-like OS is this?"
362 : #endif
363 : }
364 :
365 : int NaClHostDescIoctl(struct NaClHostDesc *d,
366 : int request,
367 0 : void *arg) {
368 : #if 0
369 : int retval;
370 :
371 : if (NULL == d) {
372 : NaClLog(LOG_FATAL, "NaClHostDescIoctl: 'this' is NULL\n");
373 : }
374 : /*
375 : * Validate arg according to request. Arrgh indeed.
376 : */
377 : return ((-1 == (retval = ioctl(d->d, request, arg)))
378 : ? -NaClXlateErrno(errno) : retval);
379 : #else
380 : UNREFERENCED_PARAMETER(request);
381 : UNREFERENCED_PARAMETER(arg);
382 :
383 0 : if (NULL == d) {
384 0 : NaClLog(LOG_FATAL, "NaClHostDescIoctl: 'this' is NULL\n");
385 : }
386 0 : return -NACL_ABI_ENOSYS;
387 : #endif
388 : }
389 :
390 : /*
391 : * See NaClHostDescStat below.
392 : */
393 : int NaClHostDescFstat(struct NaClHostDesc *d,
394 6 : nacl_host_stat_t *nhsp) {
395 : #if NACL_LINUX
396 : if (fstat64(d->d, nhsp) == -1) {
397 : return -errno;
398 : }
399 : #elif NACL_OSX
400 6 : if (fstat(d->d, nhsp) == -1) {
401 0 : return -errno;
402 : }
403 : #else
404 : # error "What OS?"
405 : #endif
406 :
407 6 : return 0;
408 : }
409 :
410 33 : int NaClHostDescClose(struct NaClHostDesc *d) {
411 : int retval;
412 :
413 33 : if (NULL == d) {
414 0 : NaClLog(LOG_FATAL, "NaClHostDescClose: 'this' is NULL\n");
415 : }
416 33 : retval = close(d->d);
417 33 : if (-1 != retval) {
418 33 : d->d = -1;
419 : }
420 33 : return (-1 == retval) ? -NaClXlateErrno(errno) : retval;
421 : }
422 :
423 : /*
424 : * This is not a host descriptor function, but is closely related to
425 : * fstat and should behave similarly.
426 : */
427 : int NaClHostDescStat(char const *host_os_pathname,
428 25 : nacl_host_stat_t *nhsp) {
429 :
430 : #if NACL_LINUX
431 : if (stat64(host_os_pathname, nhsp) == -1) {
432 : return -errno;
433 : }
434 : #elif NACL_OSX
435 25 : if (stat(host_os_pathname, nhsp) == -1) {
436 4 : return -errno;
437 : }
438 : #else
439 : # error "What OS?"
440 : #endif
441 :
442 21 : return 0;
443 : }
|