2 * Copyright 2008, Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 * NaCl Service Runtime. I/O Descriptor / Handle abstraction. Memory
34 * mapping using descriptors.
36 * Note that we avoid using the thread-specific data / thread local
37 * storage access to the "errno" variable, and instead use the raw
38 * system call return interface of small negative numbers as errors.
42 #include <sys/types.h>
49 #include "native_client/include/nacl_platform.h"
50 #include "native_client/include/portability.h"
52 #include "native_client/service_runtime/nacl_config.h"
53 #include "native_client/service_runtime/nacl_log.h"
54 #include "native_client/service_runtime/nacl_host_desc.h"
55 #include "native_client/service_runtime/sel_util.h"
56 #include "native_client/service_runtime/sel_memory.h"
58 #include "native_client/service_runtime/include/sys/errno.h"
59 #include "native_client/service_runtime/include/sys/fcntl.h"
60 #include "native_client/service_runtime/include/bits/mman.h"
61 #include "native_client/service_runtime/include/sys/stat.h"
64 * Map our ABI to the host OS's ABI. On linux, this should be a big no-op.
66 static INLINE
int NaClMapOpenFlags(int nacl_flags
)
70 nacl_flags
&= (NACL_ABI_O_ACCMODE
| NACL_ABI_O_CREAT
71 | NACL_ABI_O_TRUNC
| NACL_ABI_O_APPEND
);
74 #define C(H) case NACL_ABI_ ## H: \
77 switch (nacl_flags
& NACL_ABI_O_ACCMODE
) {
84 if (0 != (nacl_flags & NACL_ABI_ ## H)) { \
95 static INLINE
int NaClMapOpenPerm(int nacl_perm
)
101 if (0 != (nacl_perm & NACL_ABI_ ## H)) { \
111 static INLINE
int NaClMapFlagMap(int nacl_map_flags
)
117 if (0 != (nacl_map_flags & NACL_ABI_ ## H)) { \
118 host_os_flags |= H; \
127 return host_os_flags
;
130 int NaClHostDescMap(struct NaClHostDesc
*d
,
143 ("NaClHostDescMap(0x%08"PRIxPTR
", 0x%08"PRIxPTR
", 0x%08"PRIxS
","
144 " 0x%x, 0x%x, 0x%08"PRIx64
")\n"),
146 (uintptr_t) start_addr
,
151 if (NULL
== d
&& 0 == (flags
& NACL_ABI_MAP_ANONYMOUS
)) {
152 NaClLog(LOG_FATAL
, "NaClHostDescMap: 'this' is NULL and not anon map\n");
154 prot
&= (NACL_ABI_PROT_READ
| NACL_ABI_PROT_WRITE
);
155 /* may be PROT_NONE too */
156 flags
&= NACL_ABI_MAP_ANONYMOUS
;
157 /* NACL_ABI_MAP_SHARED is ignored */
158 flags
|= NACL_ABI_MAP_FIXED
| NACL_ABI_MAP_PRIVATE
;
159 /* supplied start_addr must be okay, mapping must be private! */
161 if (flags
& NACL_ABI_MAP_ANONYMOUS
) {
167 * Translate flags, prot to host_flags, host_prot.
169 host_flags
= NaClMapFlagMap(flags
);
170 host_prot
= NaClProtMap(prot
);
172 map_addr
= mmap(start_addr
, len
, host_prot
, host_flags
, desc
, offset
);
174 if (MAP_FAILED
== map_addr
) {
177 " mmap(0x%08"PRIxPTR
", 0x%"PRIxS
", 0x%x, 0x%x, 0x%d, 0x%"PRIx64
")"
178 " failed, errno %d.\n"),
179 (uintptr_t) start_addr
, len
, host_prot
, host_flags
, desc
,
182 return -NaClXlateErrno(errno
);
184 if (map_addr
!= start_addr
) {
186 ("NaClHostDescMap: mmap with MAP_FIXED not fixed:"
187 " returned 0x%08"PRIxPTR
" instead of 0x%08"PRIxPTR
"\n"),
188 (uintptr_t) map_addr
,
189 (uintptr_t) start_addr
);
191 NaClLog(4, "NaClHostDescMap: returning 0x%08"PRIxPTR
"\n",
192 (uintptr_t) start_addr
);
193 return (uintptr_t) start_addr
; /* and convert to int */
196 int NaClHostDescUnmapUnsafe(void *start_addr
,
202 addr
= (uintptr_t) start_addr
;
204 return ((-1 == (retval
= munmap(start_addr
, len
)))
205 ? -NaClXlateErrno(errno
)
209 int NaClHostDescUnmap(void *start_addr
,
215 addr
= (uintptr_t) start_addr
;
217 return ((-1 == (retval
= (uintptr_t) mmap(start_addr
,
221 | MAP_ANONYMOUS
| MAP_FIXED
),
224 ? -NaClXlateErrno(errno
) : retval
);
227 int NaClHostDescOpen(struct NaClHostDesc
*d
,
234 NaClLog(3, "NaClHostDescOpen(0x%08"PRIxPTR
", %s, 0x%x, 0x%x)\n",
235 (uintptr_t) d
, path
, flags
, mode
);
237 NaClLog(LOG_FATAL
, "NaClHostDescOpen: 'this' is NULL\n");
240 * Sanitize access flags.
242 if (0 != (flags
& ~(NACL_ABI_O_ACCMODE
| NACL_ABI_O_CREAT
243 | NACL_ABI_O_TRUNC
| NACL_ABI_O_APPEND
))) {
244 return -NACL_ABI_EINVAL
;
247 switch (flags
& NACL_ABI_O_ACCMODE
) {
248 case NACL_ABI_O_RDONLY
:
249 case NACL_ABI_O_WRONLY
:
250 case NACL_ABI_O_RDWR
:
254 "NaClHostDescOpen: bad access flags 0x%x.\n",
256 return -NACL_ABI_EINVAL
;
259 flags
= NaClMapOpenFlags(flags
);
260 mode
= NaClMapOpenPerm(mode
);
262 NaClLog(3, "NaClHostDescOpen: invoking POSIX open(%s,0x%x,0%o)\n",
264 host_desc
= open(path
, flags
, mode
);
265 NaClLog(3, "NaClHostDescOpen: got descriptor %d\n", host_desc
);
266 if (-1 == host_desc
) {
268 "NaClHostDescOpen: open returned -1, errno %d\n", errno
);
269 return -NaClXlateErrno(errno
);
272 NaClLog(3, "NaClHostDescOpen: success.\n");
276 int NaClHostDescPosixDup(struct NaClHostDesc
*d
,
283 NaClLog(LOG_FATAL
, "NaClHostDescPosixDup: 'this' is NULL\n");
286 * Sanitize access modes.
288 if (0 != (mode
& ~O_ACCMODE
)) {
289 return -NACL_ABI_EINVAL
;
292 switch (mode
& O_ACCMODE
) {
299 "NaClHostDescPosixDup: bad access mode 0x%x.\n",
301 return -NACL_ABI_EINVAL
;
304 host_desc
= dup(posix_d
);
305 if (-1 == host_desc
) {
306 return -NACL_ABI_EINVAL
;
312 int NaClHostDescPosixTake(struct NaClHostDesc
*d
,
317 NaClLog(LOG_FATAL
, "NaClHostDescPosixTake: 'this' is NULL\n");
320 * Sanitize access modes.
322 if (0 != (mode
& ~O_ACCMODE
)) {
323 return -NACL_ABI_EINVAL
;
326 switch (mode
& O_ACCMODE
) {
333 "NaClHostDescPosixTake: bad access mode 0x%x.\n",
335 return -NACL_ABI_EINVAL
;
342 ssize_t
NaClHostDescRead(struct NaClHostDesc
*d
,
349 NaClLog(LOG_FATAL
, "NaClHostDescRead: 'this' is NULL\n");
351 return ((-1 == (retval
= read(d
->d
, buf
, len
)))
352 ? -NaClXlateErrno(errno
) : retval
);
355 ssize_t
NaClHostDescWrite(struct NaClHostDesc
*d
,
362 NaClLog(LOG_FATAL
, "NaClHostDescWrite: 'this' is NULL\n");
364 return ((-1 == (retval
= write(d
->d
, buf
, len
)))
365 ? -NaClXlateErrno(errno
) : retval
);
368 int NaClHostDescSeek(struct NaClHostDesc
*d
,
375 NaClLog(LOG_FATAL
, "NaClHostDescSeek: 'this' is NULL\n");
377 return ((-1 == (retval
= lseek(d
->d
, offset
, whence
)))
378 ? -NaClXlateErrno(errno
) : retval
);
381 int NaClHostDescIoctl(struct NaClHostDesc
*d
,
389 NaClLog(LOG_FATAL
, "NaClHostDescIoctl: 'this' is NULL\n");
392 * Validate arg according to request. Arrgh indeed.
394 return ((-1 == (retval
= ioctl(d
->d
, request
, arg
)))
395 ? -NaClXlateErrno(errno
) : retval
);
398 NaClLog(LOG_FATAL
, "NaClHostDescIoctl: 'this' is NULL\n");
400 return -NACL_ABI_ENOSYS
;
404 static int next_inode_number
= 1;
406 void NaClHostDescStatCommon(struct nacl_abi_stat
*nasp
,
411 nasp
->nacl_abi_st_dev
= 0;
412 /* Python uses st_ino to determine whether an extension module is
413 the same as a previously-loaded module. This hack stops st_ino
414 from being the same for different files. */
415 nasp
->nacl_abi_st_ino
= next_inode_number
++;
417 switch (sbp
->st_mode
& S_IFMT
) {
419 m
= NACL_ABI_S_IFREG
;
422 m
= NACL_ABI_S_IFDIR
;
426 /* stdin/out/err can be inherited, so this is okay */
427 m
= NACL_ABI_S_IFCHR
;
432 ("NaClHostDescStatCommon: how did NaCl app open a file"
433 " with st_mode = 0%o?\n"),
435 m
= NACL_ABI_S_UNSUP
;
437 if (0 != (nasp
->nacl_abi_st_mode
& S_IRUSR
)) {
438 m
|= NACL_ABI_S_IRUSR
;
440 if (0 != (nasp
->nacl_abi_st_mode
& S_IWUSR
)) {
441 m
|= NACL_ABI_S_IWUSR
;
443 if (0 != (nasp
->nacl_abi_st_mode
& S_IXUSR
)) {
444 m
|= NACL_ABI_S_IXUSR
;
446 nasp
->nacl_abi_st_mode
= m
;
447 nasp
->nacl_abi_st_nlink
= sbp
->st_nlink
;
448 nasp
->nacl_abi_st_uid
= -1; /* not root */
449 nasp
->nacl_abi_st_gid
= -1; /* not wheel */
450 nasp
->nacl_abi_st_rdev
= 0;
451 nasp
->nacl_abi_st_size
= sbp
->st_size
;
452 nasp
->nacl_abi_st_blksize
= 0;
453 nasp
->nacl_abi_st_blocks
= 0;
454 nasp
->nacl_abi_st_atime
= sbp
->st_atime
;
455 nasp
->nacl_abi_st_mtime
= sbp
->st_mtime
;
456 nasp
->nacl_abi_st_ctime
= sbp
->st_ctime
;
460 * See NaClHostDescStat below.
462 int NaClHostDescFstat(struct NaClHostDesc
*d
,
463 struct nacl_abi_stat
*nasp
)
467 if (fstat(d
->d
, &stbuf
) == -1) {
471 NaClHostDescStatCommon(nasp
, &stbuf
);
476 int NaClHostDescClose(struct NaClHostDesc
*d
)
481 NaClLog(LOG_FATAL
, "NaClHostDescClose: 'this' is NULL\n");
483 retval
= close(d
->d
);
487 return (-1 == retval
) ? -NaClXlateErrno(errno
) : retval
;
491 * This is not a host descriptor function, but is closely related to
492 * fstat and should behave similarly.
494 int NaClHostDescStat(char const *host_os_pathname
,
495 struct nacl_abi_stat
*nasp
)
499 if (stat(host_os_pathname
, &stbuf
) == -1) {
503 NaClHostDescStatCommon(nasp
, &stbuf
);