/* This tests a NaCl syscall that takes no arguments. */ void TestSyscall(uintptr_t syscall_addr) { struct NaClSignalContext call_regs; char stack[0x10000]; RegsFillTestValues(&call_regs, /* seed= */ 0); call_regs.stack_ptr = (uintptr_t) stack + sizeof(stack); call_regs.prog_ctr = (uintptr_t) ContinueAfterSyscall; RegsApplySandboxConstraints(&call_regs); g_expected_regs = call_regs; RegsUnsetNonCalleeSavedRegisters(&g_expected_regs); SetNaClSwitchExpectations(&g_expected_regs); if (!setjmp(g_return_jmp_buf)) { #if defined(__i386__) call_regs.eax = syscall_addr; ASM_WITH_REGS( &call_regs, "push $ContinueAfterSyscall\n" /* Push return address */ "nacljmp %%eax\n"); #elif defined(__x86_64__) /* * This fast path syscall happens to preserve various registers, * but that is obviously not guaranteed by the ABI. */ if (syscall_addr == (uintptr_t) NACL_SYSCALL(tls_get) || syscall_addr == (uintptr_t) NACL_SYSCALL(second_tls_get)) { /* Undo some effects of RegsUnsetNonCalleeSavedRegisters(). */ g_expected_regs.rsi = call_regs.rsi; g_expected_regs.rdi = call_regs.rdi; g_expected_regs.r8 = call_regs.r8; g_expected_regs.r9 = call_regs.r9; g_expected_regs.r10 = call_regs.r10; /* * The current implementation clobbers %rcx with the * non-%r15-extended return address. */ g_expected_regs.rcx = (uint32_t) g_expected_regs.prog_ctr; } call_regs.rax = syscall_addr; ASM_WITH_REGS( &call_regs, "push $ContinueAfterSyscall\n" /* Push return address */ "nacljmp %%eax, %%r15\n"); #elif defined(__arm__) call_regs.r1 = syscall_addr; /* Scratch register */ call_regs.lr = (uintptr_t) ContinueAfterSyscall; /* Return address */ ASM_WITH_REGS( &call_regs, "bic r1, r1, #0xf000000f\n" "bx r1\n"); #else # error Unsupported architecture #endif assert(!"Should not reach here"); } }
void test_stack_in_code(void) { int rc = NACL_SYSCALL(exception_handler)(bad_stack_exception_handler, NULL); assert(rc == 0); rc = NACL_SYSCALL(exception_stack)(stack_in_code, stack_in_code_size); assert(rc == 0); fprintf(stderr, "** intended_exit_status=unwritable_exception_stack\n"); /* Cause crash. */ *(volatile int *) 0 = 0; }
/* * This test case does not crash. It successfully runs * bad_stack_exception_handler() in order to check that it works, so * that we can be sure that other tests do not crash (and hence pass) * accidentally. */ void test_stack_in_rwdata(void) { int rc = NACL_SYSCALL(exception_handler)(bad_stack_exception_handler, NULL); assert(rc == 0); rc = NACL_SYSCALL(exception_stack)((void *) stack_in_rwdata, sizeof(stack_in_rwdata)); assert(rc == 0); fprintf(stderr, "** intended_exit_status=1\n"); /* Cause crash. */ *(volatile int *) 0 = 0; }
/* * This checks that crashes in trusted code (such as inside NaCl * syscalls) do not cause the untrusted exception handler to run. */ void test_crash_in_syscall(void) { int rc = NACL_SYSCALL(exception_handler)(bad_stack_exception_handler, NULL); assert(rc == 0); rc = NACL_SYSCALL(exception_stack)((void *) stack_in_rwdata, sizeof(stack_in_rwdata)); assert(rc == 0); fprintf(stderr, "** intended_exit_status=trusted_segfault\n"); /* * Cause a crash inside a NaCl syscall. */ NACL_SYSCALL(test_crash)(NACL_TEST_CRASH_MEMORY); /* Should not reach here. */ _exit(1); }
static int nacl_irt_thread_create(void *start_user_address, void *stack, void *thread_ptr) { #if defined(NACL_IN_IRT) /* * We want the first TLS to point to an unmapped location. The * thread_create() syscall rejects a zero argument for the first * TLS, so use a non-zero value in the unmapped first 64k page. */ void *user_tls = (void *) 0x1000; return -NACL_SYSCALL(thread_create)(start_user_address, stack, user_tls, thread_ptr); #else return -NACL_SYSCALL(thread_create)(start_user_address, stack, thread_ptr, 0); #endif }
static int nc_thread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr) { cond->handle = NACL_SYSCALL(cond_create)(); /* 0 for success, 1 for failure */ return (cond->handle < 0); }
void _exit (int status) { NACL_SYSCALL (exit) (status); /* In case the syscall returns: */ while (1) __asm__("hlt"); }
static int nacl_irt_mutex_create(int *mutex_handle) { int rv = NACL_SYSCALL(mutex_create)(); if (rv < 0) return -rv; *mutex_handle = rv; return 0; }
int main(int argc, char* argv[]) { if (argc == 555) { /* this should never be executed */ var_tls = 11; var_tls_double = 22.0; var_static = 33; var_static_double = 44.0; var_global = 55; var_global_double = 66.0; } if (argc == 6666) { /* this should never be executed */ return (int) &var_tls + (int) &var_static + (int) &var_global + (int) &var_tls_double + (int) &var_static_double + (int) &var_global_double; } #if !defined(NO_NACL_STUFF) NACL_SYSCALL(exit)(55); #endif /* UNREACHABLE */ return 0; }
/* Set registers to known values and enter a NaCl syscall. */ static void SyscallRegisterSetterThread(struct SuspendTestShm *test_shm) { struct NaClSignalContext call_regs; char stack[0x10000]; RegsFillTestValues(&call_regs, /* seed= */ 0); call_regs.stack_ptr = (uintptr_t) stack + sizeof(stack); call_regs.prog_ctr = (uintptr_t) ContinueAfterSyscall; RegsApplySandboxConstraints(&call_regs); /* * call_regs are the registers we set on entry to the syscall. * expected_regs are the registers that should be reported by * NaClAppThreadGetSuspendedRegisters(). Since not all registers * are saved when entering a syscall, expected_regs will be the same * as call_regs but with various registers zeroed out. */ test_shm->expected_regs = call_regs; RegsUnsetNonCalleeSavedRegisters(&test_shm->expected_regs); uintptr_t syscall_addr = (uintptr_t) NACL_SYSCALL(test_syscall_1); if (!setjmp(return_jmp_buf)) { #if defined(__i386__) test_shm->expected_regs.stack_ptr -= 4; /* Account for argument */ call_regs.eax = syscall_addr; call_regs.ecx = (uintptr_t) test_shm; /* Scratch register */ ASM_WITH_REGS( &call_regs, "push %%ecx\n" /* Push syscall argument */ "push $ContinueAfterSyscall\n" /* Push return address */ "nacljmp %%eax\n"); #elif defined(__x86_64__) call_regs.rax = syscall_addr; call_regs.rdi = (uintptr_t) test_shm; /* Set syscall argument */ ASM_WITH_REGS( &call_regs, "push $ContinueAfterSyscall\n" /* Push return address */ "nacljmp %%eax, %%r15\n"); #elif defined(__arm__) call_regs.r0 = (uintptr_t) test_shm; /* Set syscall argument */ call_regs.r1 = syscall_addr; /* Scratch register */ call_regs.lr = (uintptr_t) ContinueAfterSyscall; ASM_WITH_REGS( &call_regs, "bic r1, r1, #0xf000000f\n" "bx r1\n"); #elif defined(__mips__) call_regs.a0 = (uintptr_t) test_shm; /* Set syscall argument */ call_regs.t9 = syscall_addr; /* Scratch register */ call_regs.return_addr = (uintptr_t) ContinueAfterSyscall; ASM_WITH_REGS( &call_regs, "and $t9, $t9, $t6\n" "jr $t9\n" "nop\n"); #else # error Unsupported architecture #endif assert(!"Should not reach here"); } }
static int nacl_irt_isatty(int fd, int *result) { int rv = NACL_SYSCALL(isatty)(fd); if (rv < 0) return -rv; *result = rv; return 0; }
static int nacl_irt_read(int fd, void *buf, size_t count, size_t *nread) { int rv = NACL_GC_WRAP_SYSCALL(NACL_SYSCALL(read)(fd, buf, count)); if (rv < 0) return -rv; *nread = rv; return 0; }
/* * This tests that when a new thread is created, untrusted code is * entered with well-defined register state. None of the registers * should come from uninitialised values. */ void TestInitialRegsAtThreadEntry(void) { char *stack_top = g_stack + sizeof(g_stack); uintptr_t aligned_stack_top = ((uintptr_t) stack_top & ~NACL_STACK_ALIGN_MASK) - NACL_STACK_PAD_BELOW_ALIGN; /* * We do not care about TLS for this test, but sel_ldr rejects a * zero tls argument, so use an arbitrary non-zero value. */ char *tls = (char *) 0x1000; g_stack_in_use = 1; int rc = NACL_SYSCALL(thread_create)((void *) (uintptr_t) ThreadFuncWrapper, stack_top, tls, 0); assert(rc == 0); /* Spin until the thread exits. */ while (g_stack_in_use) { sched_yield(); } ANNOTATE_CONDVAR_WAIT(&g_stack_in_use); struct NaClSignalContext actual_regs = g_initial_thread_regs; struct NaClSignalContext expected_regs; /* By default, we expect registers to be initialised to zero. */ memset(&expected_regs, 0, sizeof(expected_regs)); expected_regs.prog_ctr = (uintptr_t) ThreadFuncWrapper; expected_regs.stack_ptr = aligned_stack_top; RegsApplySandboxConstraints(&expected_regs); SetNaClSwitchExpectations(&expected_regs); #if defined(__x86_64__) /* NaCl happens to initialise %rbp to be the same as %rsp. */ expected_regs.rbp = expected_regs.stack_ptr; #endif RegsAssertEqual(&actual_regs, &expected_regs); }
/* * This replaces __pthread_initialize_minimal() from libnacl and * __pthread_initialize() from libpthread. */ void __pthread_initialize(void) { struct nc_combined_tdb *tdb; /* * Allocate the area. If malloc fails here, we'll crash before it returns. */ size_t combined_size = __nacl_tls_combined_size(sizeof(*tdb)); void *combined_area = malloc(combined_size); /* * Initialize TLS proper (i.e., __thread variable initializers). */ void *tp = __nacl_tls_initialize_memory(combined_area, sizeof(*tdb)); tdb = get_irt_tdb(tp); __nc_initialize_unjoinable_thread(tdb); tdb->tdb.irt_thread_data = combined_area; /* * Now install it for later fetching. * This is what our private version of __nacl_read_tp will read. */ NACL_SYSCALL(second_tls_set)(tp); /* * Finally, do newlib per-thread initialization. */ __newlib_thread_init(); __nc_initialize_globals(); }
static int nacl_irt_dup(int fd, int *newfd) { int rv = NACL_SYSCALL(dup)(fd); if (rv < 0) return -rv; *newfd = rv; return 0; }
static int nacl_irt_thread_create(void (*start_func)(void), void *stack, void *thread_ptr) { struct nc_combined_tdb *tdb; /* * Before we start the thread, allocate the IRT-private TLS area for it. */ size_t combined_size = __nacl_tls_combined_size(sizeof(*tdb)); void *combined_area = malloc(combined_size); if (combined_area == NULL) return EAGAIN; /* * Note that __nacl_tls_initialize_memory() is not reversible, * because it takes a pointer that need not be aligned and can * return a pointer that is aligned. In order to * free(combined_area) later, we must save the value of * combined_area. */ void *irt_tp = __nacl_tls_initialize_memory(combined_area, sizeof(*tdb)); tdb = get_irt_tdb(irt_tp); __nc_initialize_unjoinable_thread(tdb); tdb->tdb.irt_thread_data = combined_area; /* * We overload the libpthread start_func field to store a function * of a different type. */ tdb->tdb.start_func = (void *(*)(void *)) start_func; int error = -NACL_SYSCALL(thread_create)( (void *) (uintptr_t) &irt_start_thread, stack, thread_ptr, irt_tp); if (error != 0) free(combined_area); return error; }
static void SyscallInvokerThread(struct SuspendTestShm *test_shm) { uint32_t next_val = 0; while (!test_shm->should_exit) { NACL_SYSCALL(null)(); test_shm->var = next_val++; } }
static int nacl_irt_seek(int fd, off_t offset, int whence, off_t *new_offset) { int rv = NACL_SYSCALL(lseek)(fd, &offset, whence); if (rv < 0) return -rv; *new_offset = offset; return 0; }
static int nacl_irt_cond_create(int *cond_handle) { int rv = NACL_SYSCALL(cond_create)(); if (rv < 0) return -rv; *cond_handle = rv; return 0; }
static int nacl_irt_write(int fd, const void *buf, size_t count, size_t *nwrote) { int rv = NACL_GC_WRAP_SYSCALL(NACL_SYSCALL(write)(fd, buf, count)); if (rv < 0) return -rv; *nwrote = rv; return 0; }
int imc_connect(int d) { int retval = NACL_SYSCALL(imc_connect)(d); if (retval < 0) { errno = -retval; return -1; } return retval; }
static int nacl_irt_getdents(int fd, struct dirent *buf, size_t count, size_t *nread) { int rv = NACL_GC_WRAP_SYSCALL(NACL_SYSCALL(getdents)(fd, buf, count)); if (rv < 0) return -rv; *nread = rv; return 0; }
int imc_makeboundsock(int *dp) { int retval = NACL_SYSCALL(imc_makeboundsock)(dp); if (retval < 0) { errno = -retval; return -1; } return retval; }
int main(int argc, char **argv) { if (argc != 2) { fprintf(stderr, "Usage: %s <crash-type>\n", argv[0]); return 1; } char *crash_type = argv[1]; if (strcmp(crash_type, "NACL_TEST_CRASH_JUMP_TO_ZERO") == 0) { register_exception_handler(); NACL_SYSCALL(test_syscall_1)(); } else if (strcmp(crash_type, "NACL_TEST_CRASH_JUMP_INTO_SANDBOX") == 0) { register_exception_handler(); NACL_SYSCALL(test_syscall_2)(); } else { NACL_SYSCALL(test_crash)(look_up_crash_type(crash_type)); } return 1; }
int getdents(int desc, struct dirent *dirp, size_t count) { int retval = NACL_SYSCALL(getdents)(desc, dirp, count); if (retval < 0) { errno = -retval; return -1; } return retval; }
int munmap(void *start, size_t length) { int retval = NACL_SYSCALL(munmap)(start, length); if (retval < 0) { errno = -retval; return -1; } return retval; }
int nacl_dyncode_delete(void *dest, size_t size) { int error = -NACL_SYSCALL(dyncode_delete)(dest, size); if (error) { errno = error; return -1; } return 0; }
int nacl_dyncode_modify(void *dest, const void *src, size_t size) { int error = -NACL_SYSCALL(dyncode_modify)(dest, src, size); if (error) { errno = error; return -1; } return 0; }
int imc_sendmsg(int desc, struct NaClAbiNaClImcMsgHdr const *nmhp, int flags) { int retval = NACL_SYSCALL(imc_sendmsg)(desc, nmhp, flags); if (retval < 0) { errno = -retval; return -1; } return retval; }
int write(int desc, void const *buf, size_t count) { int retval = NACL_GC_WRAP_SYSCALL(NACL_SYSCALL(write)(desc, buf, count)); if (retval < 0) { errno = -retval; return -1; } return retval; }