int main(void) { struct nacl_irt_clock ti; int errs = 0; ShowCurrentDefinitions(); if (0 == nacl_interface_query(NACL_IRT_CLOCK_v0_1, &ti, sizeof(ti))) { fprintf(stderr, "IRT hook is not available\n"); return 1; } errs += TimeTest(ti.clock_getres, CLOCK_REALTIME, "clock_getres on realtime clock failed", "Realtime clock resolution"); errs += TimeTest(ti.clock_getres, CLOCK_MONOTONIC, "clock_getres on monotonic clock failed", "Monotonic clock resolution"); errs += TimeTest(ti.clock_gettime, CLOCK_REALTIME, "clock_gettime on realtime clock failed", "Realtime clock value"); errs += TimeTest(ti.clock_gettime, CLOCK_MONOTONIC, "clock_gettime on monotonic clock failed", "Monotonic clock value"); return errs; }
int main(void) { struct nacl_irt_thread ti; if (0 == nacl_interface_query(NACL_IRT_THREAD_v0_1, &ti, sizeof(ti))) { fprintf(stderr, "IRT hook is not available\n"); return 1; } return 0; }
/* * We don't do any locking here, but simultaneous calls are harmless enough. * They'll all be writing the same values to the same words. */ static void setup_irt_dyncode(void) { if (nacl_interface_query(NACL_IRT_DYNCODE_v0_1, &irt_dyncode, sizeof(irt_dyncode)) != sizeof(irt_dyncode)) { static const char fail_msg[] = "IRT interface query failed for essential interface \"" NACL_IRT_DYNCODE_v0_1 "\"!\n"; write(2, fail_msg, sizeof(fail_msg) - 1); _exit(-1); } }
/* * Check that the old version of the memory interface is * a prefix of the new version. */ void test_memory_interface_prefix(void) { struct nacl_irt_memory_v0_1 m1; struct nacl_irt_memory m2; void *addr; int rc; rc = nacl_interface_query(NACL_IRT_MEMORY_v0_1, &m1, sizeof m1); assert(rc == sizeof m1); /* Verify that v0.1 mmap ignores PROT_EXEC */ addr = 0; rc = m1.mmap(&addr, k64Kbytes, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, kAnonymousFiledesc, 0); /* Return value is actually new address and not a negative return code. */ assert(0xffff0000u > (uint32_t)rc); rc = nacl_interface_query(NACL_IRT_MEMORY_v0_2, &m2, sizeof m2); assert(rc == sizeof m2); /* Verify that v0.2 mmap does not ignore PROT_EXEC */ addr = 0; rc = m2.mmap(&addr, k64Kbytes, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, kAnonymousFiledesc, 0); assert(rc = -EINVAL); /* mmap is different, everything else should be the same. */ m2.mmap = m1.mmap; assert(memcmp(&m1, &m2, sizeof m1) == 0); }
int main(int argc, char **argv) { const size_t pagesize = getpagesize(); if (argc != 2) { fprintf(stderr, "Usage: %s FILENAME\n", argv[0]); return 2; } const char *filename = argv[1]; int fd = open(filename, O_RDONLY); if (fd < 0) { fprintf(stderr, "Cannot open '%s': %s\n", filename, strerror(errno)); return 2; } /* * This should match the IRT's g_dynamic_text_start and be the first * address that allocate_code_data wants to give out. */ void *address = (void *) DYNAMIC_CODE_SEGMENT_START; /* * Do a PROT_EXEC, MAP_FIXED mapping first thing, before any * uses of the allocate_code_data interface. */ try_map("first", fd, address, pagesize); struct nacl_irt_code_data_alloc alloc; int rc = nacl_interface_query(NACL_IRT_CODE_DATA_ALLOC_v0_1, &alloc, sizeof alloc); assert(rc == sizeof alloc); uintptr_t alloc_addr; rc = alloc.allocate_code_data(0, pagesize, 0, 0, &alloc_addr); assert(rc == 0); if (alloc_addr == (uintptr_t) address) { fprintf(stderr, "allocate_code_data returned address already used by mmap!\n"); return 1; } try_map("second", fd, (void *) alloc_addr, pagesize); return 0; }
int NaClCrashDumpInit(void) { int result; assert(g_ExceptionHandlingEnabled == 0); if (nacl_interface_query(NACL_IRT_DEV_EXCEPTION_HANDLING_v0_1, &g_ExceptionHandling, sizeof(g_ExceptionHandling)) == 0) { return 0; } result = pthread_key_create(&g_CrashStackKey, NaClCrashDumpThreadDestructor); assert(result == 0); if (g_ExceptionHandling.exception_handler(CrashHandler, NULL) != 0) { return 0; } g_ExceptionHandlingEnabled = 1; if (!NaClCrashDumpInitThread()) { g_ExceptionHandlingEnabled = 0; return 0; } return 1; }
/* * We don't do any locking here, but simultaneous calls are harmless enough. * They'll all be writing the same values to the same words. */ static int set_up_irt_exception_handling(void) { return nacl_interface_query(NACL_IRT_EXCEPTION_HANDLING_v0_1, &irt_exception_handling, sizeof(irt_exception_handling)) == sizeof(irt_exception_handling); }
static void chainload(const char *program, const char *interp_prefix, int argc, char **argv, int envc, char **envp) { if (nacl_interface_query(NACL_IRT_RESOURCE_OPEN_v0_1, &resource_open, sizeof(resource_open)) != sizeof(resource_open)) resource_open.open_resource = NULL; if (nacl_interface_query(NACL_IRT_CODE_DATA_ALLOC_v0_1, &code_data_alloc, sizeof(code_data_alloc)) != sizeof(code_data_alloc)) { fprintf(stderr, "Failed to find necessary IRT interface %s!\n", NACL_IRT_CODE_DATA_ALLOC_v0_1); exit(1); } const size_t pagesize = NACL_MAP_PAGESIZE; const TYPE_nacl_irt_query irt_query = __nacl_irt_query; /* * Populate our own info array on the stack. We do not assume that the * argv and envp arrays are in their usual layout, since the caller could * be passing different values. */ uint32_t info[NACL_STARTUP_ARGV + argc + 1 + envc + 1 + (kAuxvCount * 2)]; info[NACL_STARTUP_FINI] = 0; info[NACL_STARTUP_ENVC] = envc; info[NACL_STARTUP_ARGC] = argc; memcpy(nacl_startup_argv(info), argv, (argc + 1) * sizeof(argv[0])); memcpy(nacl_startup_envp(info), envp, (envc + 1) * sizeof(envp[0])); Elf32_auxv_t *auxv = nacl_startup_auxv(info); /* * Populate the auxiliary vector with the values dynamic linkers expect. */ auxv[kPhdr].a_type = AT_PHDR; auxv[kPhent].a_type = AT_PHENT; auxv[kPhent].a_un.a_val = sizeof(Elf32_Phdr); auxv[kPhnum].a_type = AT_PHNUM; auxv[kBase].a_type = AT_BASE; auxv[kEntry].a_type = AT_ENTRY; auxv[kSysinfo].a_type = AT_SYSINFO; auxv[kSysinfo].a_un.a_val = (uint32_t) irt_query; auxv[kNull].a_type = AT_NULL; auxv[kNull].a_un.a_val = 0; /* * Load the program and point the auxv elements at its phdrs and entry. */ const char *interp = NULL; uint32_t entry = load_elf_file(program, pagesize, &auxv[kBase].a_un.a_val, &auxv[kPhdr].a_un.a_val, &auxv[kPhnum].a_un.a_val, &interp); auxv[kEntry].a_un.a_val = entry; if (auxv[kPhdr].a_un.a_val == 0) auxv[kPhdr].a_type = AT_IGNORE; DEBUG_PRINTF("XXX loaded %s, entry %#x, interp %s\n", program, entry, interp); if (interp != NULL) { /* * There was a PT_INTERP, so we have a dynamic linker to load. */ char interp_buf[PATH_MAX]; if (interp_prefix != NULL) { /* * Apply the command-line-specified prefix to the embedded file name. */ snprintf(interp_buf, sizeof(interp_buf), "%s%s", interp_prefix, interp); interp = interp_buf; } entry = load_elf_file(interp, pagesize, NULL, NULL, NULL, NULL); DEBUG_PRINTF("XXX loaded PT_INTERP %s, entry %#x\n", interp, entry); } for (uint32_t *p = info; p < (uint32_t *) &auxv[kNull + 1]; ++p) DEBUG_PRINTF("XXX info[%d] = %#x\n", p - info, *p); /* * Off to the races! * The application's entry point should not return. Crash if it does. */ DEBUG_PRINTF("XXX user entry point: %#x(%#x)\n", entry, (uintptr_t) info); (*(void (*)(uint32_t[])) entry)(info); while (1) __builtin_trap(); }