Index: pnacl/support/unsandboxed_irt.c |
diff --git a/pnacl/support/unsandboxed_irt.c b/pnacl/support/unsandboxed_irt.c |
deleted file mode 100644 |
index acc774c4b0e6f8b30c5309dc309ee81ba0b5f928..0000000000000000000000000000000000000000 |
--- a/pnacl/support/unsandboxed_irt.c |
+++ /dev/null |
@@ -1,661 +0,0 @@ |
-/* |
- * Copyright (c) 2013 The Native Client Authors. All rights reserved. |
- * Use of this source code is governed by a BSD-style license that can be |
- * found in the LICENSE file. |
- */ |
- |
-#include <assert.h> |
-#include <errno.h> |
-#include <fcntl.h> |
-#include <limits.h> |
-#include <pthread.h> |
-#include <stdio.h> |
-#include <stdlib.h> |
-#include <string.h> |
-#include <sys/mman.h> |
-#include <sys/stat.h> |
-#include <sys/syscall.h> |
-#include <unistd.h> |
- |
-#if defined(__linux__) |
-# include <linux/futex.h> |
-#endif |
- |
-#include "native_client/src/include/elf32.h" |
-#include "native_client/src/include/elf_auxv.h" |
-#include "native_client/src/include/nacl_macros.h" |
-#include "native_client/src/trusted/service_runtime/include/machine/_types.h" |
-#include "native_client/src/trusted/service_runtime/include/sys/mman.h" |
-#include "native_client/src/trusted/service_runtime/include/sys/stat.h" |
-#include "native_client/src/trusted/service_runtime/include/sys/time.h" |
-#include "native_client/src/trusted/service_runtime/include/sys/unistd.h" |
-#include "native_client/src/untrusted/irt/irt.h" |
-#include "native_client/src/untrusted/irt/irt_dev.h" |
- |
-/* |
- * This is an implementation of NaCl's IRT interfaces that runs |
- * outside of the NaCl sandbox. |
- * |
- * This allows PNaCl to be used as a portability layer without the |
- * SFI-based sandboxing. PNaCl pexes can be translated to |
- * non-SFI-sandboxed native code and linked against this IRT |
- * implementation. |
- */ |
- |
- |
-#if defined(__ANDROID__) && !defined(FUTEX_PRIVATE_FLAG) |
-/* Android's Linux headers currently don't define this flag. */ |
-# define FUTEX_PRIVATE_FLAG 128 |
-#endif |
- |
-#if defined(__GLIBC__) |
-/* |
- * glibc's headers will define st_atimensec etc. fields, but only if |
- * _POSIX_SOURCE is defined, which disables many other declarations, |
- * such as nanosleep(), getpagesize(), MAP_ANON and clock_gettime(). |
- */ |
-# define st_atimensec st_atim.tv_nsec |
-# define st_mtimensec st_mtim.tv_nsec |
-# define st_ctimensec st_ctim.tv_nsec |
-#elif defined(__APPLE__) |
-/* |
- * Similarly, Mac OS X's headers will define st_atimensec etc. fields, |
- * but only if _POSIX_SOURCE is defined, which disables declarations |
- * such as _SC_NPROCESSORS_ONLN. |
- */ |
-# define st_atimensec st_atimespec.tv_nsec |
-# define st_mtimensec st_mtimespec.tv_nsec |
-# define st_ctimensec st_ctimespec.tv_nsec |
-#endif |
- |
-void _user_start(void *info); |
-void _start(void *info); |
- |
-/* TODO(mseaborn): Make threads work on Mac OS X. */ |
-#if defined(__APPLE__) |
-# define __thread /* nothing */ |
-#endif |
-static __thread void *g_tls_value; |
- |
- |
-/* |
- * The IRT functions in irt.h are declared as taking "struct timespec" |
- * and "struct timeval" pointers, but these are really "struct |
- * nacl_abi_timespec" and "struct nacl_abi_timeval" pointers in this |
- * unsandboxed context. |
- * |
- * To avoid changing irt.h for now and also avoid casting function |
- * pointers, we use the same type signatures as in irt.h and do the |
- * casting here. |
- */ |
-static void convert_from_nacl_timespec(struct timespec *dest, |
- const struct timespec *src_nacl) { |
- const struct nacl_abi_timespec *src = |
- (const struct nacl_abi_timespec *) src_nacl; |
- dest->tv_sec = src->tv_sec; |
- dest->tv_nsec = src->tv_nsec; |
-} |
- |
-static void convert_to_nacl_timespec(struct timespec *dest_nacl, |
- const struct timespec *src) { |
- struct nacl_abi_timespec *dest = (struct nacl_abi_timespec *) dest_nacl; |
- dest->tv_sec = src->tv_sec; |
- dest->tv_nsec = src->tv_nsec; |
-} |
- |
-static void convert_to_nacl_timeval(struct timeval *dest_nacl, |
- const struct timeval *src) { |
- struct nacl_abi_timeval *dest = (struct nacl_abi_timeval *) dest_nacl; |
- dest->nacl_abi_tv_sec = src->tv_sec; |
- dest->nacl_abi_tv_usec = src->tv_usec; |
-} |
- |
-static void convert_to_nacl_stat(struct stat *dest_nacl, |
- const struct stat *src) { |
- struct nacl_abi_stat *dest = (struct nacl_abi_stat *) dest_nacl; |
- dest->nacl_abi_st_dev = src->st_dev; |
- dest->nacl_abi_st_ino = src->st_ino; |
- dest->nacl_abi_st_mode = src->st_mode; |
- dest->nacl_abi_st_nlink = src->st_nlink; |
- dest->nacl_abi_st_uid = src->st_uid; |
- dest->nacl_abi_st_gid = src->st_gid; |
- dest->nacl_abi_st_rdev = src->st_rdev; |
- dest->nacl_abi_st_size = src->st_size; |
- dest->nacl_abi_st_blksize = src->st_blksize; |
- dest->nacl_abi_st_blocks = src->st_blocks; |
- dest->nacl_abi_st_atime = src->st_atime; |
- dest->nacl_abi_st_atimensec = src->st_atimensec; |
- dest->nacl_abi_st_mtime = src->st_mtime; |
- dest->nacl_abi_st_mtimensec = src->st_mtimensec; |
- dest->nacl_abi_st_ctime = src->st_ctime; |
- dest->nacl_abi_st_ctimensec = src->st_ctimensec; |
-} |
- |
-static void copy_flag(int *dest, int src, int new_flag, int old_flag) { |
- if ((src & old_flag) != 0) |
- *dest |= new_flag; |
-} |
- |
-/* Returns whether the conversion was successful. */ |
-static int convert_from_nacl_mmap_prot(int *prot, int prot_nacl) { |
- if ((prot_nacl & ~NACL_ABI_PROT_MASK) != 0) |
- return 0; |
- *prot = 0; |
- copy_flag(prot, prot_nacl, PROT_READ, NACL_ABI_PROT_READ); |
- copy_flag(prot, prot_nacl, PROT_WRITE, NACL_ABI_PROT_WRITE); |
- copy_flag(prot, prot_nacl, PROT_EXEC, NACL_ABI_PROT_EXEC); |
- return 1; |
-} |
- |
-/* Returns whether the conversion was successful. */ |
-static int convert_from_nacl_mmap_flags(int *flags, int flags_nacl) { |
- int allowed = NACL_ABI_MAP_SHARED | |
- NACL_ABI_MAP_PRIVATE | |
- NACL_ABI_MAP_FIXED | |
- NACL_ABI_MAP_ANON; |
- if ((flags_nacl & ~allowed) != 0) |
- return 0; |
- *flags = 0; |
- copy_flag(flags, flags_nacl, MAP_SHARED, NACL_ABI_MAP_SHARED); |
- copy_flag(flags, flags_nacl, MAP_PRIVATE, NACL_ABI_MAP_PRIVATE); |
- copy_flag(flags, flags_nacl, MAP_FIXED, NACL_ABI_MAP_FIXED); |
- copy_flag(flags, flags_nacl, MAP_ANON, NACL_ABI_MAP_ANON); |
- return 1; |
-} |
- |
-static int check_error(int result) { |
- if (result != 0) { |
- /* |
- * Check that we really have an error and don't indicate success |
- * mistakenly. |
- */ |
- assert(errno != 0); |
- return errno; |
- } |
- return 0; |
-} |
- |
-static int irt_close(int fd) { |
- return check_error(close(fd)); |
-} |
- |
-static int irt_dup(int fd, int *new_fd) { |
- int result = dup(fd); |
- if (result < 0) |
- return errno; |
- *new_fd = result; |
- return 0; |
-} |
- |
-static int irt_dup2(int fd, int new_fd) { |
- int result = dup2(fd, new_fd); |
- if (result < 0) |
- return errno; |
- assert(result == new_fd); |
- return 0; |
-} |
- |
-static int irt_read(int fd, void *buf, size_t count, size_t *nread) { |
- int result = read(fd, buf, count); |
- if (result < 0) |
- return errno; |
- *nread = result; |
- return 0; |
-} |
- |
-static int irt_write(int fd, const void *buf, size_t count, size_t *nwrote) { |
- int result = write(fd, buf, count); |
- if (result < 0) |
- return errno; |
- *nwrote = result; |
- return 0; |
-} |
- |
-static int irt_seek(int fd, nacl_abi_off_t offset, int whence, |
- nacl_abi_off_t *new_offset) { |
- off_t result = lseek(fd, offset, whence); |
- if (result < 0) |
- return errno; |
- *new_offset = result; |
- return 0; |
-} |
- |
-static int irt_fstat(int fd, struct stat *st) { |
- /* TODO(mseaborn): Implement this and convert "struct stat". */ |
- return ENOSYS; |
-} |
- |
-static void irt_exit(int status) { |
- _exit(status); |
-} |
- |
-static int irt_clock_func(clock_t *ticks) { |
- clock_t result = clock(); |
- if (result == (clock_t) -1) |
- return errno; |
- *ticks = result; |
- return 0; |
-} |
- |
-static int irt_gettod(struct timeval *time_nacl) { |
- struct timeval time; |
- int result = check_error(gettimeofday(&time, NULL)); |
- convert_to_nacl_timeval(time_nacl, &time); |
- return result; |
-} |
- |
-static int irt_sched_yield(void) { |
- return check_error(sched_yield()); |
-} |
- |
-static int irt_nanosleep(const struct timespec *requested_nacl, |
- struct timespec *remaining_nacl) { |
- struct timespec requested; |
- struct timespec remaining; |
- convert_from_nacl_timespec(&requested, requested_nacl); |
- int result = check_error(nanosleep(&requested, &remaining)); |
- if (remaining_nacl != NULL) |
- convert_to_nacl_timespec(remaining_nacl, &remaining); |
- return result; |
-} |
- |
-static int irt_sysconf(int name, int *value) { |
- switch (name) { |
- case NACL_ABI__SC_PAGESIZE: |
- /* |
- * For now, return the host's page size (typically 4k) rather |
- * than 64k (NaCl's usual page size), which pexes will usually |
- * be tested with. We could change this to 64k, but then the |
- * mmap() we define here should round up requested sizes to |
- * multiples of 64k. |
- */ |
- *value = getpagesize(); |
- return 0; |
- case NACL_ABI__SC_NPROCESSORS_ONLN: { |
- int result = sysconf(_SC_NPROCESSORS_ONLN); |
- if (result == 0) |
- return errno; |
- *value = result; |
- return 0; |
- } |
- default: |
- return EINVAL; |
- } |
-} |
- |
-static int irt_mmap(void **addr, size_t len, int prot, int flags, |
- int fd, nacl_irt_off_t off) { |
- int host_prot; |
- int host_flags; |
- if (!convert_from_nacl_mmap_prot(&host_prot, prot) || |
- !convert_from_nacl_mmap_flags(&host_flags, flags)) { |
- return EINVAL; |
- } |
- void *result = mmap(*addr, len, host_prot, host_flags, fd, off); |
- if (result == MAP_FAILED) |
- return errno; |
- *addr = result; |
- return 0; |
-} |
- |
-static int irt_munmap(void *addr, size_t len) { |
- return check_error(munmap(addr, len)); |
-} |
- |
-static int tls_init(void *ptr) { |
- g_tls_value = ptr; |
- return 0; |
-} |
- |
-static void *tls_get(void) { |
- return g_tls_value; |
-} |
- |
-void *__nacl_read_tp(void) { |
- return g_tls_value; |
-} |
- |
-struct thread_args { |
- void (*start_func)(void); |
- void *thread_ptr; |
-}; |
- |
-static void *start_thread(void *arg) { |
- struct thread_args args = *(struct thread_args *) arg; |
- free(arg); |
- g_tls_value = args.thread_ptr; |
- args.start_func(); |
- abort(); |
-} |
- |
-static int thread_create(void (*start_func)(void), void *stack, |
- void *thread_ptr) { |
- /* |
- * For now, we ignore the stack that user code provides and just use |
- * the stack that the host libpthread allocates. |
- */ |
- pthread_attr_t attr; |
- int error = pthread_attr_init(&attr); |
- if (error != 0) |
- return error; |
- error = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); |
- if (error != 0) |
- return error; |
- struct thread_args *args = malloc(sizeof(struct thread_args)); |
- if (args == NULL) { |
- error = ENOMEM; |
- goto cleanup; |
- } |
- args->start_func = start_func; |
- args->thread_ptr = thread_ptr; |
- pthread_t tid; |
- error = pthread_create(&tid, &attr, start_thread, args); |
- if (error != 0) |
- free(args); |
- cleanup: |
- pthread_attr_destroy(&attr); |
- return error; |
-} |
- |
-static void thread_exit(int32_t *stack_flag) { |
- *stack_flag = 0; /* Indicate that the user code's stack can be freed. */ |
- pthread_exit(NULL); |
-} |
- |
-static int thread_nice(const int nice) { |
- return 0; |
-} |
- |
-/* |
- * Mac OS X does not provide futexes or clock_gettime()/getres() natively. |
- * TODO(mseaborn): Make threads and clock_gettime() work on Mac OS X. |
- */ |
-#if defined(__linux__) |
-static int futex_wait_abs(volatile int *addr, int value, |
- const struct timespec *abstime_nacl) { |
- struct timespec reltime; |
- struct timespec *reltime_ptr = NULL; |
- if (abstime_nacl != NULL) { |
- struct timespec time_now; |
- if (clock_gettime(CLOCK_REALTIME, &time_now) != 0) |
- return errno; |
- |
- /* Convert the absolute time to a relative time. */ |
- const struct nacl_abi_timespec *abstime = |
- (const struct nacl_abi_timespec *) abstime_nacl; |
- reltime.tv_sec = abstime->tv_sec - time_now.tv_sec; |
- reltime.tv_nsec = abstime->tv_nsec - time_now.tv_nsec; |
- if (reltime.tv_nsec < 0) { |
- reltime.tv_sec -= 1; |
- reltime.tv_nsec += 1000000000; |
- } |
- /* |
- * Linux's FUTEX_WAIT returns EINVAL if given a negative relative |
- * time. But an absolute time that's in the past is a valid |
- * argument, for which we need to return ETIMEDOUT instead. |
- */ |
- if (reltime.tv_sec < 0) |
- return ETIMEDOUT; |
- reltime_ptr = &reltime; |
- } |
- return check_error(syscall(__NR_futex, addr, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, |
- value, reltime_ptr, 0, 0)); |
-} |
- |
-static int futex_wake(volatile int *addr, int nwake, int *count) { |
- int result = syscall(__NR_futex, addr, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, |
- nwake, 0, 0, 0); |
- if (result < 0) |
- return errno; |
- *count = result; |
- return 0; |
-} |
- |
-static int irt_clock_getres(nacl_irt_clockid_t clk_id, |
- struct timespec *time_nacl) { |
- struct timespec time; |
- int result = check_error(clock_getres(clk_id, &time)); |
- convert_to_nacl_timespec(time_nacl, &time); |
- return result; |
-} |
- |
-static int irt_clock_gettime(nacl_irt_clockid_t clk_id, |
- struct timespec *time_nacl) { |
- struct timespec time; |
- int result = check_error(clock_gettime(clk_id, &time)); |
- convert_to_nacl_timespec(time_nacl, &time); |
- return result; |
-} |
-#endif |
- |
-static int irt_open(const char *pathname, int flags, mode_t mode, int *new_fd) { |
- int fd = open(pathname, flags, mode); |
- if (fd < 0) |
- return errno; |
- *new_fd = fd; |
- return 0; |
-} |
- |
-static int irt_stat(const char *pathname, struct stat *stat_info_nacl) { |
- struct stat stat_info; |
- if (stat(pathname, &stat_info) != 0) |
- return errno; |
- convert_to_nacl_stat(stat_info_nacl, &stat_info); |
- return 0; |
-} |
- |
-static int irt_mkdir(const char *pathname, mode_t mode) { |
- return check_error(mkdir(pathname, mode)); |
-} |
- |
-static int irt_rmdir(const char *pathname) { |
- return check_error(rmdir(pathname)); |
-} |
- |
-static int irt_chdir(const char *pathname) { |
- return check_error(chdir(pathname)); |
-} |
- |
-static int irt_getcwd(char *pathname, size_t len) { |
- if (getcwd(pathname, len) == NULL) |
- return errno; |
- return 0; |
-} |
- |
-static int irt_unlink(const char *pathname) { |
- return check_error(unlink(pathname)); |
-} |
- |
-static int irt_getpid(int *pid) { |
- *pid = getpid(); |
- return 0; |
-} |
- |
-static void irt_stub_func(const char *name) { |
- fprintf(stderr, "Error: Unimplemented IRT function: %s\n", name); |
- abort(); |
-} |
- |
-#define DEFINE_STUB(name) \ |
- static void irt_stub_##name() { irt_stub_func(#name); } |
-#define USE_STUB(s, name) (typeof(s.name)) irt_stub_##name |
- |
-static const struct nacl_irt_basic irt_basic = { |
- irt_exit, |
- irt_gettod, |
- irt_clock_func, |
- irt_nanosleep, |
- irt_sched_yield, |
- irt_sysconf, |
-}; |
- |
-DEFINE_STUB(getdents) |
-static const struct nacl_irt_fdio irt_fdio = { |
- irt_close, |
- irt_dup, |
- irt_dup2, |
- irt_read, |
- irt_write, |
- irt_seek, |
- irt_fstat, |
- USE_STUB(irt_fdio, getdents), |
-}; |
- |
-DEFINE_STUB(mprotect) |
-static const struct nacl_irt_memory irt_memory = { |
- irt_mmap, |
- irt_munmap, |
- USE_STUB(irt_memory, mprotect), |
-}; |
- |
-static const struct nacl_irt_tls irt_tls = { |
- tls_init, |
- tls_get, |
-}; |
- |
-static const struct nacl_irt_thread irt_thread = { |
- thread_create, |
- thread_exit, |
- thread_nice, |
-}; |
- |
-#if defined(__linux__) |
-static const struct nacl_irt_futex irt_futex = { |
- futex_wait_abs, |
- futex_wake, |
-}; |
- |
-static const struct nacl_irt_clock irt_clock = { |
- irt_clock_getres, |
- irt_clock_gettime, |
-}; |
-#else |
-DEFINE_STUB(futex_wait_abs) |
-DEFINE_STUB(futex_wake) |
-static const struct nacl_irt_futex irt_futex = { |
- USE_STUB(irt_futex, futex_wait_abs), |
- USE_STUB(irt_futex, futex_wake), |
-}; |
-#endif |
- |
-DEFINE_STUB(truncate) |
-DEFINE_STUB(lstat) |
-DEFINE_STUB(link) |
-DEFINE_STUB(rename) |
-DEFINE_STUB(symlink) |
-DEFINE_STUB(chmod) |
-DEFINE_STUB(access) |
-DEFINE_STUB(readlink) |
-DEFINE_STUB(utimes) |
-static const struct nacl_irt_dev_filename irt_dev_filename = { |
- irt_open, |
- irt_stat, |
- irt_mkdir, |
- irt_rmdir, |
- irt_chdir, |
- irt_getcwd, |
- irt_unlink, |
- USE_STUB(irt_dev_filename, truncate), |
- USE_STUB(irt_dev_filename, lstat), |
- USE_STUB(irt_dev_filename, link), |
- USE_STUB(irt_dev_filename, rename), |
- USE_STUB(irt_dev_filename, symlink), |
- USE_STUB(irt_dev_filename, chmod), |
- USE_STUB(irt_dev_filename, access), |
- USE_STUB(irt_dev_filename, readlink), |
- USE_STUB(irt_dev_filename, utimes), |
-}; |
- |
-static const struct nacl_irt_dev_getpid irt_dev_getpid = { |
- irt_getpid, |
-}; |
- |
-struct nacl_interface_table { |
- const char *name; |
- const void *table; |
- size_t size; |
-}; |
- |
-static const struct nacl_interface_table irt_interfaces[] = { |
- { NACL_IRT_BASIC_v0_1, &irt_basic, sizeof(irt_basic) }, |
- { NACL_IRT_FDIO_v0_1, &irt_fdio, sizeof(irt_fdio) }, |
- { NACL_IRT_MEMORY_v0_3, &irt_memory, sizeof(irt_memory) }, |
- { NACL_IRT_TLS_v0_1, &irt_tls, sizeof(irt_tls) }, |
- { NACL_IRT_THREAD_v0_1, &irt_thread, sizeof(irt_thread) }, |
- { NACL_IRT_FUTEX_v0_1, &irt_futex, sizeof(irt_futex) }, |
-#if defined(__linux__) |
- { NACL_IRT_CLOCK_v0_1, &irt_clock, sizeof(irt_clock) }, |
-#endif |
- { NACL_IRT_DEV_FILENAME_v0_3, &irt_dev_filename, sizeof(irt_dev_filename) }, |
- { NACL_IRT_DEV_GETPID_v0_1, &irt_dev_getpid, sizeof(irt_dev_getpid) }, |
-}; |
- |
-static size_t irt_interface_query(const char *interface_ident, |
- void *table, size_t tablesize) { |
- unsigned i; |
- for (i = 0; i < NACL_ARRAY_SIZE(irt_interfaces); ++i) { |
- if (0 == strcmp(interface_ident, irt_interfaces[i].name)) { |
- const size_t size = irt_interfaces[i].size; |
- if (size <= tablesize) { |
- memcpy(table, irt_interfaces[i].table, size); |
- return size; |
- } |
- break; |
- } |
- } |
- fprintf(stderr, "Warning: unavailable IRT interface queried: %s\n", |
- interface_ident); |
- return 0; |
-} |
- |
-int main(int argc, char **argv, char **environ) { |
- /* Find size of environ array. */ |
- size_t env_count = 0; |
- while (environ[env_count] != NULL) |
- env_count++; |
- |
- size_t count = |
- 1 /* cleanup_func pointer */ |
- + 2 /* envc and argc counts */ |
- + argc + 1 /* argv array, with terminator */ |
- + env_count + 1 /* environ array, with terminator */ |
- + 4; /* auxv: 2 entries, one of them the terminator */ |
- uintptr_t *data = malloc(count * sizeof(uintptr_t)); |
- if (data == NULL) { |
- fprintf(stderr, "Failed to allocate argv/env/auxv array\n"); |
- return 1; |
- } |
- size_t pos = 0; |
- data[pos++] = 0; /* cleanup_func pointer */ |
- data[pos++] = env_count; |
- data[pos++] = argc; |
- /* Copy arrays, with terminators. */ |
- size_t i; |
- for (i = 0; i < (size_t) argc; i++) |
- data[pos++] = (uintptr_t) argv[i]; |
- data[pos++] = 0; |
- for (i = 0; i < env_count; i++) |
- data[pos++] = (uintptr_t) environ[i]; |
- data[pos++] = 0; |
- /* auxv[0] */ |
- data[pos++] = AT_SYSINFO; |
- data[pos++] = (uintptr_t) irt_interface_query; |
- /* auxv[1] */ |
- data[pos++] = 0; |
- data[pos++] = 0; |
- assert(pos == count); |
- |
- /* |
- * On Linux, we rename _start() to _user_start() to avoid a clash |
- * with the "_start" routine in the host toolchain. On Mac OS X, |
- * lacking objcopy, doing the symbol renaming is trickier, but also |
- * unnecessary, because the host toolchain doesn't have a "_start" |
- * routine. |
- */ |
-#if defined(__APPLE__) |
- _start(data); |
-#else |
- _user_start(data); |
-#endif |
- return 1; |
-} |