2 * Copyright (c) 2013 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.
7 #include "native_client/src/nonsfi/irt/irt_interfaces.h"
21 #if defined(__linux__)
22 # include <linux/futex.h>
23 # include <sys/syscall.h>
26 #include "native_client/src/include/elf32.h"
27 #include "native_client/src/include/elf_auxv.h"
28 #include "native_client/src/include/nacl/nacl_exception.h"
29 #include "native_client/src/include/nacl_macros.h"
30 #include "native_client/src/nonsfi/linux/irt_exception_handling.h"
31 #include "native_client/src/public/irt_core.h"
32 #include "native_client/src/trusted/service_runtime/include/machine/_types.h"
33 #include "native_client/src/trusted/service_runtime/include/sys/mman.h"
34 #include "native_client/src/trusted/service_runtime/include/sys/stat.h"
35 #include "native_client/src/trusted/service_runtime/include/sys/time.h"
36 #include "native_client/src/trusted/service_runtime/include/sys/unistd.h"
37 #include "native_client/src/untrusted/irt/irt.h"
38 #include "native_client/src/untrusted/irt/irt_dev.h"
39 #include "native_client/src/untrusted/irt/irt_interfaces.h"
42 * This is an implementation of NaCl's IRT interfaces that runs
43 * outside of the NaCl sandbox.
45 * This allows PNaCl to be used as a portability layer without the
46 * SFI-based sandboxing. PNaCl pexes can be translated to
47 * non-SFI-sandboxed native code and linked against this IRT
52 #if defined(__ANDROID__) && !defined(FUTEX_PRIVATE_FLAG)
53 /* Android's Linux headers currently don't define this flag. */
54 # define FUTEX_PRIVATE_FLAG 128
57 #if defined(__GLIBC__)
59 * glibc's headers will define st_atimensec etc. fields, but only if
60 * _POSIX_SOURCE is defined, which disables many other declarations,
61 * such as nanosleep(), getpagesize(), MAP_ANON and clock_gettime().
63 # define st_atimensec st_atim.tv_nsec
64 # define st_mtimensec st_mtim.tv_nsec
65 # define st_ctimensec st_ctim.tv_nsec
66 #elif defined(__APPLE__)
68 * Similarly, Mac OS X's headers will define st_atimensec etc. fields,
69 * but only if _POSIX_SOURCE is defined, which disables declarations
70 * such as _SC_NPROCESSORS_ONLN.
72 # define st_atimensec st_atimespec.tv_nsec
73 # define st_mtimensec st_mtimespec.tv_nsec
74 # define st_ctimensec st_ctimespec.tv_nsec
77 void _user_start(void *info);
78 void _start(void *info);
80 /* TODO(mseaborn): Make threads work on Mac OS X. */
81 #if defined(__APPLE__)
82 # define __thread /* nothing */
84 static __thread void *g_tls_value;
87 * The IRT functions in irt.h are declared as taking "struct timespec"
88 * and "struct timeval" pointers, but these are really "struct
89 * nacl_abi_timespec" and "struct nacl_abi_timeval" pointers in this
90 * unsandboxed context.
92 * To avoid changing irt.h for now and also avoid casting function
93 * pointers, we use the same type signatures as in irt.h and do the
96 static void convert_from_nacl_timespec(struct timespec *dest,
97 const struct timespec *src_nacl) {
98 const struct nacl_abi_timespec *src =
99 (const struct nacl_abi_timespec *) src_nacl;
100 dest->tv_sec = src->tv_sec;
101 dest->tv_nsec = src->tv_nsec;
104 static void convert_to_nacl_timespec(struct timespec *dest_nacl,
105 const struct timespec *src) {
106 struct nacl_abi_timespec *dest = (struct nacl_abi_timespec *) dest_nacl;
107 dest->tv_sec = src->tv_sec;
108 dest->tv_nsec = src->tv_nsec;
111 static void convert_to_nacl_timeval(struct timeval *dest_nacl,
112 const struct timeval *src) {
113 struct nacl_abi_timeval *dest = (struct nacl_abi_timeval *) dest_nacl;
114 dest->nacl_abi_tv_sec = src->tv_sec;
115 dest->nacl_abi_tv_usec = src->tv_usec;
118 static void convert_to_nacl_stat(struct stat *dest_nacl,
119 const struct stat *src) {
120 struct nacl_abi_stat *dest = (struct nacl_abi_stat *) dest_nacl;
121 dest->nacl_abi_st_dev = src->st_dev;
122 dest->nacl_abi_st_ino = src->st_ino;
123 dest->nacl_abi_st_mode = src->st_mode;
124 dest->nacl_abi_st_nlink = src->st_nlink;
125 dest->nacl_abi_st_uid = src->st_uid;
126 dest->nacl_abi_st_gid = src->st_gid;
127 dest->nacl_abi_st_rdev = src->st_rdev;
128 dest->nacl_abi_st_size = src->st_size;
129 dest->nacl_abi_st_blksize = src->st_blksize;
130 dest->nacl_abi_st_blocks = src->st_blocks;
131 dest->nacl_abi_st_atime = src->st_atime;
132 dest->nacl_abi_st_atimensec = src->st_atimensec;
133 dest->nacl_abi_st_mtime = src->st_mtime;
134 dest->nacl_abi_st_mtimensec = src->st_mtimensec;
135 dest->nacl_abi_st_ctime = src->st_ctime;
136 dest->nacl_abi_st_ctimensec = src->st_ctimensec;
139 static void copy_flag(int *dest, int src, int new_flag, int old_flag) {
140 if ((src & old_flag) != 0)
144 /* Returns whether the conversion was successful. */
145 static int convert_from_nacl_mmap_prot(int *prot, int prot_nacl) {
146 if ((prot_nacl & ~NACL_ABI_PROT_MASK) != 0)
149 copy_flag(prot, prot_nacl, PROT_READ, NACL_ABI_PROT_READ);
150 copy_flag(prot, prot_nacl, PROT_WRITE, NACL_ABI_PROT_WRITE);
151 copy_flag(prot, prot_nacl, PROT_EXEC, NACL_ABI_PROT_EXEC);
155 /* Returns whether the conversion was successful. */
156 static int convert_from_nacl_mmap_flags(int *flags, int flags_nacl) {
157 int allowed = NACL_ABI_MAP_SHARED |
158 NACL_ABI_MAP_PRIVATE |
161 if ((flags_nacl & ~allowed) != 0)
164 copy_flag(flags, flags_nacl, MAP_SHARED, NACL_ABI_MAP_SHARED);
165 copy_flag(flags, flags_nacl, MAP_PRIVATE, NACL_ABI_MAP_PRIVATE);
166 copy_flag(flags, flags_nacl, MAP_FIXED, NACL_ABI_MAP_FIXED);
167 copy_flag(flags, flags_nacl, MAP_ANON, NACL_ABI_MAP_ANON);
171 static int check_error(int result) {
174 * Check that we really have an error and don't indicate success
183 static int irt_close(int fd) {
184 return check_error(close(fd));
187 static int irt_dup(int fd, int *new_fd) {
188 int result = dup(fd);
195 static int irt_dup2(int fd, int new_fd) {
196 int result = dup2(fd, new_fd);
199 assert(result == new_fd);
203 static int irt_read(int fd, void *buf, size_t count, size_t *nread) {
204 int result = read(fd, buf, count);
211 static int irt_write(int fd, const void *buf, size_t count, size_t *nwrote) {
212 int result = write(fd, buf, count);
219 static int irt_seek(int fd, nacl_abi_off_t offset, int whence,
220 nacl_abi_off_t *new_offset) {
221 off_t result = lseek(fd, offset, whence);
224 *new_offset = result;
228 static int irt_fstat(int fd, struct stat *st_nacl) {
230 if (fstat(fd, &st) != 0)
232 convert_to_nacl_stat(st_nacl, &st);
236 static void irt_exit(int status) {
240 static int irt_clock_func(clock_t *ticks) {
241 clock_t result = clock();
242 if (result == (clock_t) -1)
248 static int irt_gettod(struct timeval *time_nacl) {
250 int result = check_error(gettimeofday(&time, NULL));
251 convert_to_nacl_timeval(time_nacl, &time);
255 static int irt_sched_yield(void) {
256 return check_error(sched_yield());
259 static int irt_nanosleep(const struct timespec *requested_nacl,
260 struct timespec *remaining_nacl) {
261 struct timespec requested;
262 struct timespec remaining;
263 convert_from_nacl_timespec(&requested, requested_nacl);
264 int result = check_error(nanosleep(&requested, &remaining));
265 if (remaining_nacl != NULL)
266 convert_to_nacl_timespec(remaining_nacl, &remaining);
270 static int irt_sysconf(int name, int *value) {
272 case NACL_ABI__SC_PAGESIZE:
274 * For now, return the host's page size (typically 4k) rather
275 * than 64k (NaCl's usual page size), which pexes will usually
276 * be tested with. We could change this to 64k, but then the
277 * mmap() we define here should round up requested sizes to
280 *value = getpagesize();
282 case NACL_ABI__SC_NPROCESSORS_ONLN: {
283 int result = sysconf(_SC_NPROCESSORS_ONLN);
294 static int irt_mmap(void **addr, size_t len, int prot, int flags,
295 int fd, nacl_irt_off_t off) {
298 if (!convert_from_nacl_mmap_prot(&host_prot, prot) ||
299 !convert_from_nacl_mmap_flags(&host_flags, flags)) {
302 void *result = mmap(*addr, len, host_prot, host_flags, fd, off);
303 if (result == MAP_FAILED)
309 static int irt_munmap(void *addr, size_t len) {
310 return check_error(munmap(addr, len));
313 static int irt_mprotect(void *addr, size_t len, int prot) {
315 if (!convert_from_nacl_mmap_prot(&host_prot, prot)) {
318 return check_error(mprotect(addr, len, host_prot));
321 static int tls_init(void *ptr) {
326 static void *tls_get(void) {
330 /* For newlib based nonsfi_loader, we use the one defined in pnacl_irt.c. */
331 #if !defined(__native_client__)
332 void *__nacl_read_tp(void) {
338 void (*start_func)(void);
342 static void *start_thread(void *arg) {
343 struct thread_args args = *(struct thread_args *) arg;
345 g_tls_value = args.thread_ptr;
350 static int thread_create(void (*start_func)(void), void *stack,
353 * For now, we ignore the stack that user code provides and just use
354 * the stack that the host libpthread allocates.
357 int error = pthread_attr_init(&attr);
360 error = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
363 struct thread_args *args = malloc(sizeof(struct thread_args));
368 args->start_func = start_func;
369 args->thread_ptr = thread_ptr;
371 error = pthread_create(&tid, &attr, start_thread, args);
375 pthread_attr_destroy(&attr);
379 static void thread_exit(int32_t *stack_flag) {
380 *stack_flag = 0; /* Indicate that the user code's stack can be freed. */
384 static int thread_nice(const int nice) {
389 * Mac OS X does not provide futexes or clock_gettime()/getres() natively.
390 * TODO(mseaborn): Make threads and clock_gettime() work on Mac OS X.
392 #if defined(__linux__)
393 static int futex_wait_abs(volatile int *addr, int value,
394 const struct timespec *abstime_nacl) {
395 struct timespec reltime;
396 struct timespec *reltime_ptr = NULL;
397 if (abstime_nacl != NULL) {
398 struct timespec time_now;
399 if (clock_gettime(CLOCK_REALTIME, &time_now) != 0)
402 /* Convert the absolute time to a relative time. */
403 const struct nacl_abi_timespec *abstime =
404 (const struct nacl_abi_timespec *) abstime_nacl;
405 reltime.tv_sec = abstime->tv_sec - time_now.tv_sec;
406 reltime.tv_nsec = abstime->tv_nsec - time_now.tv_nsec;
407 if (reltime.tv_nsec < 0) {
409 reltime.tv_nsec += 1000000000;
412 * Linux's FUTEX_WAIT returns EINVAL if given a negative relative
413 * time. But an absolute time that's in the past is a valid
414 * argument, for which we need to return ETIMEDOUT instead.
416 if (reltime.tv_sec < 0)
418 reltime_ptr = &reltime;
420 return check_error(syscall(__NR_futex, addr, FUTEX_WAIT | FUTEX_PRIVATE_FLAG,
421 value, reltime_ptr, 0, 0));
424 static int futex_wake(volatile int *addr, int nwake, int *count) {
425 int result = syscall(__NR_futex, addr, FUTEX_WAKE | FUTEX_PRIVATE_FLAG,
434 #if defined(__linux__) || defined(__native_client__)
435 static int irt_clock_getres(nacl_irt_clockid_t clk_id,
436 struct timespec *time_nacl) {
437 struct timespec time;
438 int result = check_error(clock_getres(clk_id, &time));
440 * The timespec pointer is allowed to be NULL for clock_getres() though
441 * not for clock_gettime().
443 if (time_nacl != NULL)
444 convert_to_nacl_timespec(time_nacl, &time);
448 static int irt_clock_gettime(nacl_irt_clockid_t clk_id,
449 struct timespec *time_nacl) {
450 struct timespec time;
451 int result = check_error(clock_gettime(clk_id, &time));
452 convert_to_nacl_timespec(time_nacl, &time);
457 static int irt_open(const char *pathname, int flags, mode_t mode, int *new_fd) {
458 int fd = open(pathname, flags, mode);
465 static int irt_stat(const char *pathname, struct stat *stat_info_nacl) {
466 struct stat stat_info;
467 if (stat(pathname, &stat_info) != 0)
469 convert_to_nacl_stat(stat_info_nacl, &stat_info);
473 static int irt_lstat(const char *pathname, struct stat *stat_info_nacl) {
474 struct stat stat_info;
475 if (lstat(pathname, &stat_info) != 0)
477 convert_to_nacl_stat(stat_info_nacl, &stat_info);
481 static int irt_mkdir(const char *pathname, mode_t mode) {
482 return check_error(mkdir(pathname, mode));
485 static int irt_rmdir(const char *pathname) {
486 return check_error(rmdir(pathname));
489 static int irt_chdir(const char *pathname) {
490 return check_error(chdir(pathname));
493 static int irt_getcwd(char *pathname, size_t len) {
494 if (getcwd(pathname, len) == NULL)
499 static int irt_unlink(const char *pathname) {
500 return check_error(unlink(pathname));
503 static int irt_truncate(const char *pathname, nacl_irt_off_t length) {
504 return check_error(truncate(pathname, length));
507 static int irt_link(const char *oldpath, const char *newpath) {
508 return check_error(link(oldpath, newpath));
511 static int irt_rename(const char *oldpath, const char *newpath) {
512 return check_error(rename(oldpath, newpath));
515 static int irt_symlink(const char *oldpath, const char *newpath) {
516 return check_error(symlink(oldpath, newpath));
519 static int irt_chmod(const char *pathname, mode_t mode) {
520 return check_error(chmod(pathname, mode));
523 static int irt_access(const char *pathname, int mode) {
524 return check_error(access(pathname, mode));
527 static int irt_readlink(const char *path, char *buf, size_t count,
529 ssize_t result = readlink(path, buf, count);
536 static int irt_getpid(int *pid) {
541 static void irt_stub_func(const char *name) {
542 fprintf(stderr, "Error: Unimplemented IRT function: %s\n", name);
546 #define DEFINE_STUB(name) \
547 static void irt_stub_##name() { irt_stub_func(#name); }
548 #define USE_STUB(s, name) (__typeof__(s.name)) irt_stub_##name
550 const struct nacl_irt_basic nacl_irt_basic = {
559 DEFINE_STUB(getdents)
560 const struct nacl_irt_fdio nacl_irt_fdio = {
568 USE_STUB(nacl_irt_fdio, getdents),
571 const struct nacl_irt_memory nacl_irt_memory = {
577 const struct nacl_irt_tls nacl_irt_tls = {
582 const struct nacl_irt_thread nacl_irt_thread = {
588 #if defined(__linux__)
589 const struct nacl_irt_futex nacl_irt_futex = {
593 #elif !defined(__native_client__)
594 DEFINE_STUB(futex_wait_abs)
595 DEFINE_STUB(futex_wake)
596 const struct nacl_irt_futex nacl_irt_futex = {
597 USE_STUB(nacl_irt_futex, futex_wait_abs),
598 USE_STUB(nacl_irt_futex, futex_wake),
602 #if defined(__linux__) || defined(__native_client__)
603 const struct nacl_irt_clock nacl_irt_clock = {
610 const struct nacl_irt_dev_filename nacl_irt_dev_filename = {
626 USE_STUB(nacl_irt_dev_filename, utimes),
629 const struct nacl_irt_dev_getpid nacl_irt_dev_getpid = {
634 * The following condition is true when building for Non-SFI Mode,
635 * when we're calling Linux syscalls directly. (Counter-intuitively,
636 * "__linux__" is not #defined in this case.)
638 #if defined(__native_client__)
639 const struct nacl_irt_exception_handling nacl_irt_exception_handling = {
640 nacl_exception_get_and_set_handler,
641 nacl_exception_set_stack,
642 nacl_exception_clear_flag,
646 static const struct nacl_irt_interface irt_interfaces[] = {
647 { NACL_IRT_BASIC_v0_1, &nacl_irt_basic, sizeof(nacl_irt_basic), NULL },
648 { NACL_IRT_FDIO_v0_1, &nacl_irt_fdio, sizeof(nacl_irt_fdio), NULL },
649 { NACL_IRT_MEMORY_v0_3, &nacl_irt_memory, sizeof(nacl_irt_memory), NULL },
650 { NACL_IRT_TLS_v0_1, &nacl_irt_tls, sizeof(nacl_irt_tls), NULL },
651 { NACL_IRT_THREAD_v0_1, &nacl_irt_thread, sizeof(nacl_irt_thread), NULL },
652 { NACL_IRT_FUTEX_v0_1, &nacl_irt_futex, sizeof(nacl_irt_futex), NULL },
653 #if defined(__linux__) || defined(__native_client__)
654 { NACL_IRT_CLOCK_v0_1, &nacl_irt_clock, sizeof(nacl_irt_clock), NULL },
656 { NACL_IRT_DEV_FILENAME_v0_3, &nacl_irt_dev_filename,
657 sizeof(nacl_irt_dev_filename), NULL },
658 { NACL_IRT_DEV_GETPID_v0_1, &nacl_irt_dev_getpid,
659 sizeof(nacl_irt_dev_getpid), NULL },
660 #if defined(__native_client__)
661 { NACL_IRT_EXCEPTION_HANDLING_v0_1, &nacl_irt_exception_handling,
662 sizeof(nacl_irt_exception_handling), NULL},
666 size_t nacl_irt_query_core(const char *interface_ident,
667 void *table, size_t tablesize) {
668 return nacl_irt_query_list(interface_ident, table, tablesize,
669 irt_interfaces, sizeof(irt_interfaces));
672 int nacl_irt_nonsfi_entry(int argc, char **argv, char **environ,
673 nacl_entry_func_t entry_func) {
674 /* Find size of environ array. */
675 size_t env_count = 0;
676 while (environ[env_count] != NULL)
680 1 /* cleanup_func pointer */
681 + 2 /* envc and argc counts */
682 + argc + 1 /* argv array, with terminator */
683 + env_count + 1 /* environ array, with terminator */
684 + 4; /* auxv: 2 entries, one of them the terminator */
685 uintptr_t *data = malloc(count * sizeof(uintptr_t));
687 fprintf(stderr, "Failed to allocate argv/env/auxv array\n");
691 data[pos++] = 0; /* cleanup_func pointer */
692 data[pos++] = env_count;
694 /* Copy arrays, with terminators. */
696 for (i = 0; i < (size_t) argc; i++)
697 data[pos++] = (uintptr_t) argv[i];
699 for (i = 0; i < env_count; i++)
700 data[pos++] = (uintptr_t) environ[i];
703 data[pos++] = AT_SYSINFO;
704 data[pos++] = (uintptr_t) nacl_irt_query_core;
708 assert(pos == count);
714 #if defined(DEFINE_MAIN)
715 int main(int argc, char **argv, char **environ) {
717 * On Linux, we rename _start() to _user_start() to avoid a clash
718 * with the "_start" routine in the host toolchain. On Mac OS X,
719 * lacking objcopy, doing the symbol renaming is trickier, but also
720 * unnecessary, because the host toolchain doesn't have a "_start"
723 nacl_entry_func_t entry_func =
724 #if defined(__APPLE__)
730 return nacl_irt_nonsfi_entry(argc, argv, environ, entry_func);