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"
19 #include <sys/syscall.h>
22 #if defined(__linux__)
23 # include <linux/futex.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_macros.h"
29 #include "native_client/src/trusted/service_runtime/include/machine/_types.h"
30 #include "native_client/src/trusted/service_runtime/include/sys/mman.h"
31 #include "native_client/src/trusted/service_runtime/include/sys/stat.h"
32 #include "native_client/src/trusted/service_runtime/include/sys/time.h"
33 #include "native_client/src/trusted/service_runtime/include/sys/unistd.h"
34 #include "native_client/src/untrusted/irt/irt.h"
35 #include "native_client/src/untrusted/irt/irt_dev.h"
38 * This is an implementation of NaCl's IRT interfaces that runs
39 * outside of the NaCl sandbox.
41 * This allows PNaCl to be used as a portability layer without the
42 * SFI-based sandboxing. PNaCl pexes can be translated to
43 * non-SFI-sandboxed native code and linked against this IRT
48 #if defined(__ANDROID__) && !defined(FUTEX_PRIVATE_FLAG)
49 /* Android's Linux headers currently don't define this flag. */
50 # define FUTEX_PRIVATE_FLAG 128
53 #if defined(__GLIBC__)
55 * glibc's headers will define st_atimensec etc. fields, but only if
56 * _POSIX_SOURCE is defined, which disables many other declarations,
57 * such as nanosleep(), getpagesize(), MAP_ANON and clock_gettime().
59 # define st_atimensec st_atim.tv_nsec
60 # define st_mtimensec st_mtim.tv_nsec
61 # define st_ctimensec st_ctim.tv_nsec
62 #elif defined(__APPLE__)
64 * Similarly, Mac OS X's headers will define st_atimensec etc. fields,
65 * but only if _POSIX_SOURCE is defined, which disables declarations
66 * such as _SC_NPROCESSORS_ONLN.
68 # define st_atimensec st_atimespec.tv_nsec
69 # define st_mtimensec st_mtimespec.tv_nsec
70 # define st_ctimensec st_ctimespec.tv_nsec
73 void _user_start(void *info);
74 void _start(void *info);
76 /* TODO(mseaborn): Make threads work on Mac OS X. */
77 #if defined(__APPLE__)
78 # define __thread /* nothing */
80 static __thread void *g_tls_value;
84 * The IRT functions in irt.h are declared as taking "struct timespec"
85 * and "struct timeval" pointers, but these are really "struct
86 * nacl_abi_timespec" and "struct nacl_abi_timeval" pointers in this
87 * unsandboxed context.
89 * To avoid changing irt.h for now and also avoid casting function
90 * pointers, we use the same type signatures as in irt.h and do the
93 static void convert_from_nacl_timespec(struct timespec *dest,
94 const struct timespec *src_nacl) {
95 const struct nacl_abi_timespec *src =
96 (const struct nacl_abi_timespec *) src_nacl;
97 dest->tv_sec = src->tv_sec;
98 dest->tv_nsec = src->tv_nsec;
101 static void convert_to_nacl_timespec(struct timespec *dest_nacl,
102 const struct timespec *src) {
103 struct nacl_abi_timespec *dest = (struct nacl_abi_timespec *) dest_nacl;
104 dest->tv_sec = src->tv_sec;
105 dest->tv_nsec = src->tv_nsec;
108 static void convert_to_nacl_timeval(struct timeval *dest_nacl,
109 const struct timeval *src) {
110 struct nacl_abi_timeval *dest = (struct nacl_abi_timeval *) dest_nacl;
111 dest->nacl_abi_tv_sec = src->tv_sec;
112 dest->nacl_abi_tv_usec = src->tv_usec;
115 static void convert_to_nacl_stat(struct stat *dest_nacl,
116 const struct stat *src) {
117 struct nacl_abi_stat *dest = (struct nacl_abi_stat *) dest_nacl;
118 dest->nacl_abi_st_dev = src->st_dev;
119 dest->nacl_abi_st_ino = src->st_ino;
120 dest->nacl_abi_st_mode = src->st_mode;
121 dest->nacl_abi_st_nlink = src->st_nlink;
122 dest->nacl_abi_st_uid = src->st_uid;
123 dest->nacl_abi_st_gid = src->st_gid;
124 dest->nacl_abi_st_rdev = src->st_rdev;
125 dest->nacl_abi_st_size = src->st_size;
126 dest->nacl_abi_st_blksize = src->st_blksize;
127 dest->nacl_abi_st_blocks = src->st_blocks;
128 dest->nacl_abi_st_atime = src->st_atime;
129 dest->nacl_abi_st_atimensec = src->st_atimensec;
130 dest->nacl_abi_st_mtime = src->st_mtime;
131 dest->nacl_abi_st_mtimensec = src->st_mtimensec;
132 dest->nacl_abi_st_ctime = src->st_ctime;
133 dest->nacl_abi_st_ctimensec = src->st_ctimensec;
136 static void copy_flag(int *dest, int src, int new_flag, int old_flag) {
137 if ((src & old_flag) != 0)
141 /* Returns whether the conversion was successful. */
142 static int convert_from_nacl_mmap_prot(int *prot, int prot_nacl) {
143 if ((prot_nacl & ~NACL_ABI_PROT_MASK) != 0)
146 copy_flag(prot, prot_nacl, PROT_READ, NACL_ABI_PROT_READ);
147 copy_flag(prot, prot_nacl, PROT_WRITE, NACL_ABI_PROT_WRITE);
148 copy_flag(prot, prot_nacl, PROT_EXEC, NACL_ABI_PROT_EXEC);
152 /* Returns whether the conversion was successful. */
153 static int convert_from_nacl_mmap_flags(int *flags, int flags_nacl) {
154 int allowed = NACL_ABI_MAP_SHARED |
155 NACL_ABI_MAP_PRIVATE |
158 if ((flags_nacl & ~allowed) != 0)
161 copy_flag(flags, flags_nacl, MAP_SHARED, NACL_ABI_MAP_SHARED);
162 copy_flag(flags, flags_nacl, MAP_PRIVATE, NACL_ABI_MAP_PRIVATE);
163 copy_flag(flags, flags_nacl, MAP_FIXED, NACL_ABI_MAP_FIXED);
164 copy_flag(flags, flags_nacl, MAP_ANON, NACL_ABI_MAP_ANON);
168 static int check_error(int result) {
171 * Check that we really have an error and don't indicate success
180 static int irt_close(int fd) {
181 return check_error(close(fd));
184 static int irt_dup(int fd, int *new_fd) {
185 int result = dup(fd);
192 static int irt_dup2(int fd, int new_fd) {
193 int result = dup2(fd, new_fd);
196 assert(result == new_fd);
200 static int irt_read(int fd, void *buf, size_t count, size_t *nread) {
201 int result = read(fd, buf, count);
208 static int irt_write(int fd, const void *buf, size_t count, size_t *nwrote) {
209 int result = write(fd, buf, count);
216 static int irt_seek(int fd, nacl_abi_off_t offset, int whence,
217 nacl_abi_off_t *new_offset) {
218 off_t result = lseek(fd, offset, whence);
221 *new_offset = result;
225 static int irt_fstat(int fd, struct stat *st) {
226 /* TODO(mseaborn): Implement this and convert "struct stat". */
230 static void irt_exit(int status) {
234 static int irt_clock_func(clock_t *ticks) {
235 clock_t result = clock();
236 if (result == (clock_t) -1)
242 static int irt_gettod(struct timeval *time_nacl) {
244 int result = check_error(gettimeofday(&time, NULL));
245 convert_to_nacl_timeval(time_nacl, &time);
249 static int irt_sched_yield(void) {
250 return check_error(sched_yield());
253 static int irt_nanosleep(const struct timespec *requested_nacl,
254 struct timespec *remaining_nacl) {
255 struct timespec requested;
256 struct timespec remaining;
257 convert_from_nacl_timespec(&requested, requested_nacl);
258 int result = check_error(nanosleep(&requested, &remaining));
259 if (remaining_nacl != NULL)
260 convert_to_nacl_timespec(remaining_nacl, &remaining);
264 static int irt_sysconf(int name, int *value) {
266 case NACL_ABI__SC_PAGESIZE:
268 * For now, return the host's page size (typically 4k) rather
269 * than 64k (NaCl's usual page size), which pexes will usually
270 * be tested with. We could change this to 64k, but then the
271 * mmap() we define here should round up requested sizes to
274 *value = getpagesize();
276 case NACL_ABI__SC_NPROCESSORS_ONLN: {
277 int result = sysconf(_SC_NPROCESSORS_ONLN);
288 static int irt_mmap(void **addr, size_t len, int prot, int flags,
289 int fd, nacl_irt_off_t off) {
292 if (!convert_from_nacl_mmap_prot(&host_prot, prot) ||
293 !convert_from_nacl_mmap_flags(&host_flags, flags)) {
296 void *result = mmap(*addr, len, host_prot, host_flags, fd, off);
297 if (result == MAP_FAILED)
303 static int irt_munmap(void *addr, size_t len) {
304 return check_error(munmap(addr, len));
307 static int tls_init(void *ptr) {
312 static void *tls_get(void) {
316 void *__nacl_read_tp(void) {
321 void (*start_func)(void);
325 static void *start_thread(void *arg) {
326 struct thread_args args = *(struct thread_args *) arg;
328 g_tls_value = args.thread_ptr;
333 static int thread_create(void (*start_func)(void), void *stack,
336 * For now, we ignore the stack that user code provides and just use
337 * the stack that the host libpthread allocates.
340 int error = pthread_attr_init(&attr);
343 error = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
346 struct thread_args *args = malloc(sizeof(struct thread_args));
351 args->start_func = start_func;
352 args->thread_ptr = thread_ptr;
354 error = pthread_create(&tid, &attr, start_thread, args);
358 pthread_attr_destroy(&attr);
362 static void thread_exit(int32_t *stack_flag) {
363 *stack_flag = 0; /* Indicate that the user code's stack can be freed. */
367 static int thread_nice(const int nice) {
372 * Mac OS X does not provide futexes or clock_gettime()/getres() natively.
373 * TODO(mseaborn): Make threads and clock_gettime() work on Mac OS X.
375 #if defined(__linux__)
376 static int futex_wait_abs(volatile int *addr, int value,
377 const struct timespec *abstime_nacl) {
378 struct timespec reltime;
379 struct timespec *reltime_ptr = NULL;
380 if (abstime_nacl != NULL) {
381 struct timespec time_now;
382 if (clock_gettime(CLOCK_REALTIME, &time_now) != 0)
385 /* Convert the absolute time to a relative time. */
386 const struct nacl_abi_timespec *abstime =
387 (const struct nacl_abi_timespec *) abstime_nacl;
388 reltime.tv_sec = abstime->tv_sec - time_now.tv_sec;
389 reltime.tv_nsec = abstime->tv_nsec - time_now.tv_nsec;
390 if (reltime.tv_nsec < 0) {
392 reltime.tv_nsec += 1000000000;
395 * Linux's FUTEX_WAIT returns EINVAL if given a negative relative
396 * time. But an absolute time that's in the past is a valid
397 * argument, for which we need to return ETIMEDOUT instead.
399 if (reltime.tv_sec < 0)
401 reltime_ptr = &reltime;
403 return check_error(syscall(__NR_futex, addr, FUTEX_WAIT | FUTEX_PRIVATE_FLAG,
404 value, reltime_ptr, 0, 0));
407 static int futex_wake(volatile int *addr, int nwake, int *count) {
408 int result = syscall(__NR_futex, addr, FUTEX_WAKE | FUTEX_PRIVATE_FLAG,
416 static int irt_clock_getres(nacl_irt_clockid_t clk_id,
417 struct timespec *time_nacl) {
418 struct timespec time;
419 int result = check_error(clock_getres(clk_id, &time));
420 convert_to_nacl_timespec(time_nacl, &time);
424 static int irt_clock_gettime(nacl_irt_clockid_t clk_id,
425 struct timespec *time_nacl) {
426 struct timespec time;
427 int result = check_error(clock_gettime(clk_id, &time));
428 convert_to_nacl_timespec(time_nacl, &time);
433 static int irt_open(const char *pathname, int flags, mode_t mode, int *new_fd) {
434 int fd = open(pathname, flags, mode);
441 static int irt_stat(const char *pathname, struct stat *stat_info_nacl) {
442 struct stat stat_info;
443 if (stat(pathname, &stat_info) != 0)
445 convert_to_nacl_stat(stat_info_nacl, &stat_info);
449 static int irt_mkdir(const char *pathname, mode_t mode) {
450 return check_error(mkdir(pathname, mode));
453 static int irt_rmdir(const char *pathname) {
454 return check_error(rmdir(pathname));
457 static int irt_chdir(const char *pathname) {
458 return check_error(chdir(pathname));
461 static int irt_getcwd(char *pathname, size_t len) {
462 if (getcwd(pathname, len) == NULL)
467 static int irt_unlink(const char *pathname) {
468 return check_error(unlink(pathname));
471 static int irt_getpid(int *pid) {
476 static void irt_stub_func(const char *name) {
477 fprintf(stderr, "Error: Unimplemented IRT function: %s\n", name);
481 #define DEFINE_STUB(name) \
482 static void irt_stub_##name() { irt_stub_func(#name); }
483 #define USE_STUB(s, name) (__typeof__(s.name)) irt_stub_##name
485 static const struct nacl_irt_basic irt_basic = {
494 DEFINE_STUB(getdents)
495 static const struct nacl_irt_fdio irt_fdio = {
503 USE_STUB(irt_fdio, getdents),
506 DEFINE_STUB(mprotect)
507 static const struct nacl_irt_memory irt_memory = {
510 USE_STUB(irt_memory, mprotect),
513 static const struct nacl_irt_tls irt_tls = {
518 static const struct nacl_irt_thread irt_thread = {
524 #if defined(__linux__)
525 static const struct nacl_irt_futex irt_futex = {
530 static const struct nacl_irt_clock irt_clock = {
535 DEFINE_STUB(futex_wait_abs)
536 DEFINE_STUB(futex_wake)
537 static const struct nacl_irt_futex irt_futex = {
538 USE_STUB(irt_futex, futex_wait_abs),
539 USE_STUB(irt_futex, futex_wake),
543 DEFINE_STUB(truncate)
550 DEFINE_STUB(readlink)
552 static const struct nacl_irt_dev_filename irt_dev_filename = {
560 USE_STUB(irt_dev_filename, truncate),
561 USE_STUB(irt_dev_filename, lstat),
562 USE_STUB(irt_dev_filename, link),
563 USE_STUB(irt_dev_filename, rename),
564 USE_STUB(irt_dev_filename, symlink),
565 USE_STUB(irt_dev_filename, chmod),
566 USE_STUB(irt_dev_filename, access),
567 USE_STUB(irt_dev_filename, readlink),
568 USE_STUB(irt_dev_filename, utimes),
571 static const struct nacl_irt_dev_getpid irt_dev_getpid = {
575 struct nacl_interface_table {
581 static const struct nacl_interface_table irt_interfaces[] = {
582 { NACL_IRT_BASIC_v0_1, &irt_basic, sizeof(irt_basic) },
583 { NACL_IRT_FDIO_v0_1, &irt_fdio, sizeof(irt_fdio) },
584 { NACL_IRT_MEMORY_v0_3, &irt_memory, sizeof(irt_memory) },
585 { NACL_IRT_TLS_v0_1, &irt_tls, sizeof(irt_tls) },
586 { NACL_IRT_THREAD_v0_1, &irt_thread, sizeof(irt_thread) },
587 { NACL_IRT_FUTEX_v0_1, &irt_futex, sizeof(irt_futex) },
588 #if defined(__linux__)
589 { NACL_IRT_CLOCK_v0_1, &irt_clock, sizeof(irt_clock) },
591 { NACL_IRT_DEV_FILENAME_v0_3, &irt_dev_filename, sizeof(irt_dev_filename) },
592 { NACL_IRT_DEV_GETPID_v0_1, &irt_dev_getpid, sizeof(irt_dev_getpid) },
595 static size_t irt_interface_query(const char *interface_ident,
596 void *table, size_t tablesize) {
598 for (i = 0; i < NACL_ARRAY_SIZE(irt_interfaces); ++i) {
599 if (0 == strcmp(interface_ident, irt_interfaces[i].name)) {
600 const size_t size = irt_interfaces[i].size;
601 if (size <= tablesize) {
602 memcpy(table, irt_interfaces[i].table, size);
608 fprintf(stderr, "Warning: unavailable IRT interface queried: %s\n",
613 int nacl_irt_nonsfi_entry(int argc, char **argv, char **environ,
614 nacl_entry_func_t entry_func) {
615 /* Find size of environ array. */
616 size_t env_count = 0;
617 while (environ[env_count] != NULL)
621 1 /* cleanup_func pointer */
622 + 2 /* envc and argc counts */
623 + argc + 1 /* argv array, with terminator */
624 + env_count + 1 /* environ array, with terminator */
625 + 4; /* auxv: 2 entries, one of them the terminator */
626 uintptr_t *data = malloc(count * sizeof(uintptr_t));
628 fprintf(stderr, "Failed to allocate argv/env/auxv array\n");
632 data[pos++] = 0; /* cleanup_func pointer */
633 data[pos++] = env_count;
635 /* Copy arrays, with terminators. */
637 for (i = 0; i < (size_t) argc; i++)
638 data[pos++] = (uintptr_t) argv[i];
640 for (i = 0; i < env_count; i++)
641 data[pos++] = (uintptr_t) environ[i];
644 data[pos++] = AT_SYSINFO;
645 data[pos++] = (uintptr_t) irt_interface_query;
649 assert(pos == count);
655 #if defined(DEFINE_MAIN)
656 int main(int argc, char **argv, char **environ) {
658 * On Linux, we rename _start() to _user_start() to avoid a clash
659 * with the "_start" routine in the host toolchain. On Mac OS X,
660 * lacking objcopy, doing the symbol renaming is trickier, but also
661 * unnecessary, because the host toolchain doesn't have a "_start"
664 nacl_entry_func_t entry_func =
665 #if defined(__APPLE__)
671 return nacl_irt_nonsfi_entry(argc, argv, environ, entry_func);