int main(int argc, char **argv) { struct NaClApp app; struct NaClApp *nap = &app; struct NaClSyscallTableEntry syscall_table[NACL_MAX_SYSCALLS] = {{0}}; int index; int use_separate_thread = 0; for (index = 0; index < NACL_MAX_SYSCALLS; index++) { syscall_table[index].handler = NotImplementedDecoder; } syscall_table[TEST_SYSCALL_INVOKE].handler = MySyscallInvoke; syscall_table[TEST_SYSCALL_EXIT].handler = MySyscallExit; NaClAllModulesInit(); CHECK(NaClAppWithSyscallTableCtor(&app, syscall_table)); CHECK(NaClAppLoadFileFromFilename(&app, argv[1]) == LOAD_OK); struct NaClAppThread *natp; uintptr_t stack_ptr = NaClGetInitialStackTop(nap); /* Ensure the stack pointer is suitably aligned. */ stack_ptr &= ~NACL_STACK_ALIGN_MASK; stack_ptr -= NACL_STACK_PAD_BELOW_ALIGN; /* TODO(mseaborn): Make this interface more straightforward to use. */ stack_ptr = NaClSysToUserStackAddr(nap, NaClUserToSys(nap, stack_ptr)); natp = NaClAppThreadMake(nap, nap->initial_entry_pt, stack_ptr, 0, 0); CHECK(natp != NULL); NaClAppThreadLauncher(natp); printf("game over\n"); return 1; }
int main(int argc, char **argv) { struct NaClApp app; NaClHandleBootstrapArgs(&argc, &argv); if (argc != 2) { NaClLog(LOG_FATAL, "Expected 1 argument: executable filename\n"); } NaClAllModulesInit(); CHECK(NaClAppCtor(&app)); CHECK(NaClAppLoadFileFromFilename(&app, argv[1]) == LOAD_OK); NaClAppInitialDescriptorHookup(&app); g_nap = &app; g_expected_desc = MakeExampleDesc(); NaClAppSetDesc(&app, 10, g_expected_desc); CHECK(NaClCreateMainThread(&app, 0, NULL, NULL)); CHECK(NaClWaitForMainThreadToExit(&app) == 0); /* Check for leaks. */ CHECK(g_object_count == 0); /* * Avoid calling exit() because it runs process-global destructors * which might break code that is running in our unjoined threads. */ NaClExit(0); return 0; }
int main(int argc, char **argv) { struct NaClApp app; struct GioMemoryFileSnapshot gio_file; /* Register file-local handler first (so it ends up second in the chain). */ if (strcmp(argv[1], "unforwarded_trusted") != 0) { RegisterExceptionHandler(); } /* Install untrusted exception catcher after local handler. */ CHECK(NaClInterceptMachExceptions()); if (argc == 2 && strcmp(argv[1], "early_trusted") == 0) { g_expect_crash = 1; /* Cause a crash. */ *(volatile int *) 0 = 0; } if (argc != 3) { NaClLog(LOG_FATAL, "Expected 1 or 2 arguments\n"); } if (strcmp(argv[1], "trusted") == 0) { g_expect_crash = 1; } else if (strcmp(argv[1], "unforwarded_trusted") == 0) { fprintf(stderr, "** intended_exit_status=-10\n"); g_expect_crash = 0; } else if (strcmp(argv[1], "untrusted") == 0) { /* Expect the test to crash; untrusted crashes shouldn't be propagated. */ fprintf(stderr, "** intended_exit_status=-10\n"); g_expect_crash = 0; } else if (strcmp(argv[1], "untrusted_caught") == 0) { g_expect_crash = 0; } else { NaClLog(LOG_FATAL, "1st argument (%s) not recognised\n", argv[1]); } NaClAllModulesInit(); NaClFileNameForValgrind(argv[1]); CHECK(GioMemoryFileSnapshotCtor(&gio_file, argv[2])); CHECK(NaClAppCtor(&app)); app.enable_exception_handling = 1; CHECK(NaClAppLoadFile((struct Gio *) &gio_file, &app) == LOAD_OK); CHECK(NaClAppPrepareToLaunch(&app) == LOAD_OK); CHECK(NaClCreateMainThread(&app, 0, NULL, NULL)); CHECK(NaClWaitForMainThreadToExit(&app) == 0); if (g_expect_crash) { NaClLog(LOG_FATAL, "Did not expect the guest code to exit\n"); return 1; } else { fprintf(stderr, "No crashes, as intended.\n"); fprintf(stderr, "** intended_exit_status=0\n"); return 0; } }
int main(int argc, char **argv) { struct NaClApp app; struct NaClApp *nap = &app; struct GioMemoryFileSnapshot gio_file; NaClDebugExceptionHandlerStandaloneHandleArgs(argc, argv); NaClHandleBootstrapArgs(&argc, &argv); /* Turn off buffering to aid debugging. */ setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); NaClAllModulesInit(); if (argc != 2) { NaClLog(LOG_FATAL, "Expected 1 argument: executable filename\n"); } NaClFileNameForValgrind(argv[1]); CHECK(GioMemoryFileSnapshotCtor(&gio_file, argv[1])); CHECK(NaClAppCtor(nap)); CHECK(NaClAppLoadFile((struct Gio *) &gio_file, nap) == LOAD_OK); NaClAppInitialDescriptorHookup(nap); CHECK(NaClAppPrepareToLaunch(nap) == LOAD_OK); #if NACL_LINUX NaClSignalHandlerInit(); #elif NACL_OSX CHECK(NaClInterceptMachExceptions()); #elif NACL_WINDOWS nap->attach_debug_exception_handler_func = NaClDebugExceptionHandlerStandaloneAttach; #else # error Unknown host OS #endif CHECK(NaClFaultedThreadQueueEnable(nap)); printf("Running TestReceivingFault...\n"); TestReceivingFault(nap); printf("Running TestGettingRegistersInMacSwitchRemainingRegs...\n"); TestGettingRegistersInMacSwitchRemainingRegs(nap); /* * Avoid calling exit() because it runs process-global destructors * which might break code that is running in our unjoined threads. */ NaClExit(0); }
int main(int argc, char **argv) { struct NaClApp app; uint32_t mmap_addr; char arg_string[32]; char *args[] = {"prog_name", arg_string}; NaClAllModulesInit(); if (argc != 2) { NaClLog(LOG_FATAL, "Expected 1 argument: executable filename\n"); } NaClAddSyscall(NACL_sys_test_syscall_1, TestSyscall); CHECK(NaClAppCtor(&app)); CHECK(NaClAppLoadFileFromFilename(&app, argv[1]) == LOAD_OK); NaClAppInitialDescriptorHookup(&app); CHECK(NaClAppPrepareToLaunch(&app) == LOAD_OK); NaClSignalHandlerInit(); NaClSignalHandlerSet(TrapSignalHandler); /* * Allocate some space in untrusted address space. We pass the * address to the guest program so that it can write a register * snapshot for us to compare against. */ mmap_addr = NaClSysMmapIntern( &app, NULL, sizeof(*g_test_shm), NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE, NACL_ABI_MAP_PRIVATE | NACL_ABI_MAP_ANONYMOUS, -1, 0); g_test_shm = (struct RegsTestShm *) NaClUserToSys(&app, mmap_addr); SNPRINTF(arg_string, sizeof(arg_string), "0x%x", (unsigned int) mmap_addr); CHECK(NaClCreateMainThread(&app, 2, args, NULL)); CHECK(NaClWaitForMainThreadToExit(&app) == 0); CHECK(!g_in_untrusted_code); ASSERT_EQ(g_context_switch_count, (kNumberOfCallsToTest + kFastPathSyscallsToTest - 1) * 2); /* * Avoid calling exit() because it runs process-global destructors * which might break code that is running in our unjoined threads. */ NaClExit(0); return 0; }
int main(int argc, char **argv) { struct NaClApp app; NaClHandleBootstrapArgs(&argc, &argv); NaClDebugExceptionHandlerStandaloneHandleArgs(argc, argv); /* Turn off buffering to aid debugging. */ setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); NaClAllModulesInit(); if (argc != 3) { NaClLog(LOG_FATAL, "Expected 2 arguments: <executable-filename> <crash-type>\n"); } g_crash_type = argv[2]; CHECK(NaClAppCtor(&app)); CHECK(NaClAppLoadFileFromFilename(&app, argv[1]) == LOAD_OK); NaClAppInitialDescriptorHookup(&app); if (TestWithUntrustedExceptionHandling()) { app.enable_exception_handling = 1; #if NACL_WINDOWS app.attach_debug_exception_handler_func = NaClDebugExceptionHandlerStandaloneAttach; #endif } NaClAddSyscall(NACL_sys_test_syscall_1, JumpToZeroCrashSyscall); NaClAddSyscall(NACL_sys_test_syscall_2, JumpIntoSandboxCrashSyscall); RegisterHandlers(); CHECK(NaClCreateMainThread(&app, argc - 1, argv + 1, NULL)); NaClWaitForMainThreadToExit(&app); NaClLog(LOG_ERROR, "We did not expect the test program to exit cleanly\n"); return 1; }
int main(void) { size_t stack_size = SIGSTKSZ; char *stack; stack_t st; int rc; NaClAllModulesInit(); NaClSignalHandlerInit(); /* * Allocate and register a signal stack, and ensure that it is * filled with non-zero bytes. */ stack = malloc(stack_size); CHECK(stack != NULL); memset(stack, 0xff, stack_size); st.ss_size = stack_size; st.ss_sp = stack; st.ss_flags = 0; rc = sigaltstack(&st, NULL); CHECK(rc == 0); /* * Trigger a signal. This should produce a "** Signal X from * trusted code" message, which the test runner checks for. */ fprintf(stderr, "** intended_exit_status=trusted_segfault\n"); /* * Clang transmutes a NULL pointer reference into a generic "undefined" * case. That code crashes with a different signal than an actual bad * pointer reference, violating the tests' expectations. A pointer that * is known bad but is not literally NULL does not get this treatment. */ *(volatile int *) 1 = 0; fprintf(stderr, "Should never reach here.\n"); return 1; }
int main(void) { struct NaClApp ap; struct NaClApp *nap = ≈ struct NaClDesc *d_null; NaClAllModulesInit(); if (!NaClAppCtor(nap)) { NaClLog(LOG_FATAL, "NaClAppCtor failed\n"); } if (!NaClResourceNaClAppInit(&nap->resources, nap)) { NaClLog(LOG_FATAL, "NaClResourceNaClAppInit failed\n"); } d_null = NaClResourceOpen((struct NaClResource *) &nap->resources, "/dev/null", NACL_ABI_O_RDWR, 0777); if (NULL == d_null) { NaClLog(LOG_FATAL, "NaClResourceOpen failed\n"); } if (NACL_VTBL(NaClDesc, d_null)->typeTag != NACL_DESC_NULL) { NaClLog(LOG_FATAL, "NaClResourceOpen did not return a null descriptor\n"); } if ((*NACL_VTBL(NaClDesc, d_null)->Write)(d_null, NULL, MEGABYTE) != MEGABYTE) { NaClLog(LOG_FATAL, "Write failed\n"); } if ((*NACL_VTBL(NaClDesc, d_null)->Read)(d_null, NULL, MEGABYTE) != 0) { NaClLog(LOG_FATAL, "Read failed\n"); } printf("Passed.\n"); return 0; }
int main(int argc, char **argv) { struct NaClApp app[2]; struct NaClDesc *nd; NaClHandle handle_pair[2]; int i; char *domain1_args[] = {"prog", "domain1"}; char *domain2_args[] = {"prog", "domain2"}; int return_code; if (argc != 2) NaClLog(LOG_FATAL, "Expected 1 argument: executable filename\n"); NaClAllModulesInit(); NaClFileNameForValgrind(argv[1]); nd = (struct NaClDesc *) NaClDescIoDescOpen(argv[1], NACL_ABI_O_RDONLY, 0); CHECK(NULL != nd); for (i = 0; i < 2; i++) { CHECK(NaClAppCtor(&app[i])); /* Use a smaller guest address space size, because 32-bit Windows does not let us allocate 2GB of address space. We don't do this for x86-64 because there is an assertion in NaClAllocateSpace() that requires 4GB. */ #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32 app[i].addr_bits = 29; /* 512MB per process */ #endif /* * On x86-32, we cannot enable ASLR even when the address space is * 512MB. In particular, when on Windows where the available * contiguous address space is tight, if the random choice for the * base of the first 512MB address space puts that address space * in the middle of the available address space region, the * address space allocation code might not be able to (randomly) * find another contiguous 512MB region for the second NaCl * module. */ CHECK(NaClAppLoadFileAslr(nd, &app[i], NACL_DISABLE_ASLR) == LOAD_OK); NaClAppInitialDescriptorHookup(&app[i]); CHECK(NaClAppPrepareToLaunch(&app[i]) == LOAD_OK); } /* Set up an IMC connection between the two guests. This allows us to test communications between the two and also synchronise the output for the purpose of checking against the golden file. */ CHECK(NaClSocketPair(handle_pair) == 0); NaClAddImcHandle(&app[0], handle_pair[0], SEND_DESC); NaClAddImcHandle(&app[1], handle_pair[1], RECEIVE_DESC); CHECK(NaClCreateMainThread(&app[0], 2, domain1_args, NULL)); CHECK(NaClCreateMainThread(&app[1], 2, domain2_args, NULL)); return_code = NaClWaitForMainThreadToExit(&app[0]); CHECK(return_code == 101); return_code = NaClWaitForMainThreadToExit(&app[1]); CHECK(return_code == 102); /* * Avoid calling exit() because it runs process-global destructors * which might break code that is running in our unjoined threads. */ NaClExit(0); }
int NaClMainForChromium(int handle_count, const NaClHandle *handles, int debug) { char *av[1]; int ac = 1; const char **envp; struct NaClApp state; int main_thread_only = 1; int export_addr_to = kSrpcFd; /* Used to be set by -X. */ struct NaClApp *nap; NaClErrorCode errcode; int ret_code = 1; struct NaClEnvCleanser env_cleanser; #if NACL_OSX /* Mac dynamic libraries cannot access the environ variable directly. */ envp = (const char **) *_NSGetEnviron(); #else /* Overzealous code style check is overzealous. */ /* @IGNORE_LINES_FOR_CODE_HYGIENE[1] */ extern char **environ; envp = (const char **) environ; #endif NaClAllModulesInit(); /* Add a handler to catch untrusted errors only */ NaClSignalHandlerAdd(NaClSignalHandleUntrusted); /* to be passed to NaClMain, eventually... */ av[0] = "NaClMain"; if (!NaClAppCtor(&state)) { fprintf(stderr, "Error while constructing app state\n"); goto done; } state.restrict_to_main_thread = main_thread_only; nap = &state; errcode = LOAD_OK; /* import IMC handle - used to be "-i" */ CHECK(handle_count == 3); NaClAddImcHandle(nap, handles[0], export_addr_to); NaClAddImcHandle(nap, handles[1], 6); /* async_receive_desc */ NaClAddImcHandle(nap, handles[2], 7); /* async_send_desc */ /* * in order to report load error to the browser plugin through the * secure command channel, we do not immediate jump to cleanup code * on error. rather, we continue processing (assuming earlier * errors do not make it inappropriate) until the secure command * channel is set up, and then bail out. */ /* * Ensure this operating system platform is supported. */ errcode = NaClRunSelQualificationTests(); if (LOAD_OK != errcode) { nap->module_load_status = errcode; fprintf(stderr, "Error while loading in SelMain: %s\n", NaClErrorString(errcode)); } /* Give debuggers a well known point at which xlate_base is known. */ NaClGdbHook(&state); /* * If export_addr_to is set to a non-negative integer, we create a * bound socket and socket address pair and bind the former to * descriptor 3 and the latter to descriptor 4. The socket address * is written out to the export_addr_to descriptor. * * The service runtime also accepts a connection on the bound socket * and spawns a secure command channel thread to service it. * * If export_addr_to is -1, we only create the bound socket and * socket address pair, and we do not export to an IMC socket. This * use case is typically only used in testing, where we only "dump" * the socket address to stdout or similar channel. */ if (-2 < export_addr_to) { NaClCreateServiceSocket(nap); if (0 <= export_addr_to) { NaClSendServiceAddressTo(nap, export_addr_to); /* * NB: spawns a thread that uses the command channel. we do * this after NaClAppLoadFile so that NaClApp object is more * fully populated. Hereafter any changes to nap should be done * while holding locks. */ NaClSecureCommandChannel(nap); } } if (NULL != nap->secure_channel && LOAD_OK == errcode) { /* * wait for start_module RPC call on secure channel thread. */ errcode = NaClWaitForStartModuleCommand(nap); } /* * error reporting done; can quit now if there was an error earlier. */ if (LOAD_OK != errcode) { goto done; } /* * Enable debugging if requested. */ if (debug) NaClDebugSetAllow(1); NaClEnvCleanserCtor(&env_cleanser); if (!NaClEnvCleanserInit(&env_cleanser, envp)) { NaClLog(LOG_FATAL, "Failed to initialise env cleanser\n"); } /* * only nap->ehdrs.e_entry is usable, no symbol table is * available. */ if (!NaClCreateMainThread(nap, ac, av, NaClEnvCleanserEnvironment(&env_cleanser))) { fprintf(stderr, "creating main thread failed\n"); goto done; } NaClEnvCleanserDtor(&env_cleanser); ret_code = NaClWaitForMainThreadToExit(nap); /* * exit_group or equiv kills any still running threads while module * addr space is still valid. otherwise we'd have to kill threads * before we clean up the address space. */ return ret_code; done: fflush(stdout); NaClAllModulesFini(); return ret_code; }
int NaClSelLdrMain(int argc, char **argv) { int opt; char *rest; struct redir *entry; struct redir *redir_queue; struct redir **redir_qend; struct NaClApp state; char *nacl_file = NULL; char *blob_library_file = NULL; int rpc_supplies_nexe = 0; int export_addr_to = -1; struct NaClApp *nap = &state; struct GioFile gout; NaClErrorCode errcode = LOAD_INTERNAL; struct GioMemoryFileSnapshot blob_file; int ret_code; struct DynArray env_vars; char *log_file = NULL; int verbosity = 0; int fuzzing_quit_after_load = 0; int debug_mode_bypass_acl_checks = 0; int debug_mode_ignore_validator = 0; int skip_qualification = 0; int handle_signals = 0; int enable_debug_stub = 0; struct NaClPerfCounter time_all_main; const char **envp; struct NaClEnvCleanser env_cleanser; #if NACL_OSX /* Mac dynamic libraries cannot access the environ variable directly. */ envp = (const char **) *_NSGetEnviron(); #else /* Overzealous code style check is overzealous. */ /* @IGNORE_LINES_FOR_CODE_HYGIENE[1] */ extern char **environ; envp = (const char **) environ; #endif ret_code = 1; redir_queue = NULL; redir_qend = &redir_queue; memset(&state, 0, sizeof state); NaClAllModulesInit(); NaClBootstrapChannelErrorReporterInit(); NaClErrorLogHookInit(NaClBootstrapChannelErrorReporter, &state); verbosity = NaClLogGetVerbosity(); NaClPerfCounterCtor(&time_all_main, "SelMain"); fflush((FILE *) NULL); NaClDebugExceptionHandlerStandaloneHandleArgs(argc, argv); if (!GioFileRefCtor(&gout, stdout)) { fprintf(stderr, "Could not create general standard output channel\n"); exit(1); } if (!NaClAppCtor(&state)) { NaClLog(LOG_FATAL, "NaClAppCtor() failed\n"); } if (!DynArrayCtor(&env_vars, 0)) { NaClLog(LOG_FATAL, "Failed to allocate env var array\n"); } /* * On platforms with glibc getopt, require POSIXLY_CORRECT behavior, * viz, no reordering of the arglist -- stop argument processing as * soon as an unrecognized argument is encountered, so that, for * example, in the invocation * * sel_ldr foo.nexe -vvv * * the -vvv flags are made available to the nexe, rather than being * consumed by getopt. This makes the behavior of the Linux build * of sel_ldr consistent with the Windows and OSX builds. */ while ((opt = my_getopt(argc, argv, #if NACL_LINUX "+D:z:" #endif "aB:ceE:f:Fgh:i:l:Qr:RsSvw:X:Z")) != -1) { switch (opt) { case 'a': fprintf(stderr, "DEBUG MODE ENABLED (bypass acl)\n"); debug_mode_bypass_acl_checks = 1; break; case 'B': blob_library_file = optarg; break; case 'c': ++debug_mode_ignore_validator; break; #if NACL_LINUX case 'D': NaClHandleRDebug(optarg, argv[0]); break; #endif case 'e': nap->enable_exception_handling = 1; break; case 'E': /* * For simplicity, we treat the environment variables as a * list of strings rather than a key/value mapping. We do not * try to prevent duplicate keys or require the strings to be * of the form "KEY=VALUE". This is in line with how execve() * works in Unix. * * We expect that most callers passing "-E" will either pass * in a fixed list or will construct the list using a * high-level language, in which case de-duplicating keys * outside of sel_ldr is easier. However, we could do * de-duplication here if it proves to be worthwhile. */ if (!DynArraySet(&env_vars, env_vars.num_entries, optarg)) { NaClLog(LOG_FATAL, "Adding item to env_vars failed\n"); } break; case 'f': nacl_file = optarg; break; case 'F': fuzzing_quit_after_load = 1; break; case 'g': enable_debug_stub = 1; break; case 'h': case 'r': case 'w': /* import host descriptor */ entry = malloc(sizeof *entry); if (NULL == entry) { fprintf(stderr, "No memory for redirection queue\n"); exit(1); } entry->next = NULL; entry->nacl_desc = strtol(optarg, &rest, 0); entry->tag = HOST_DESC; entry->u.host.d = strtol(rest+1, (char **) 0, 0); entry->u.host.mode = ImportModeMap(opt); *redir_qend = entry; redir_qend = &entry->next; break; case 'i': /* import IMC handle */ entry = malloc(sizeof *entry); if (NULL == entry) { fprintf(stderr, "No memory for redirection queue\n"); exit(1); } entry->next = NULL; entry->nacl_desc = strtol(optarg, &rest, 0); entry->tag = IMC_DESC; entry->u.handle = (NaClHandle) strtol(rest+1, (char **) 0, 0); *redir_qend = entry; redir_qend = &entry->next; break; case 'l': log_file = optarg; break; case 'Q': fprintf(stderr, "PLATFORM QUALIFICATION DISABLED BY -Q - " "Native Client's sandbox will be unreliable!\n"); skip_qualification = 1; break; case 'R': rpc_supplies_nexe = 1; break; /* case 'r': with 'h' and 'w' above */ case 's': nap->validator_stub_out_mode = 1; break; case 'S': handle_signals = 1; break; case 'v': ++verbosity; NaClLogIncrVerbosity(); break; /* case 'w': with 'h' and 'r' above */ case 'X': export_addr_to = strtol(optarg, (char **) 0, 0); break; #if NACL_LINUX case 'z': NaClHandleReservedAtZero(optarg); break; #endif case 'Z': NaClLog(LOG_WARNING, "Enabling Fixed-Feature CPU Mode\n"); nap->fixed_feature_cpu_mode = 1; if (!nap->validator->FixCPUFeatures(nap->cpu_features)) { NaClLog(LOG_ERROR, "This CPU lacks features required by " "fixed-function CPU mode.\n"); exit(1); } break; default: fprintf(stderr, "ERROR: unknown option: [%c]\n\n", opt); PrintUsage(); exit(-1); } } if (debug_mode_ignore_validator == 1) fprintf(stderr, "DEBUG MODE ENABLED (ignore validator)\n"); else if (debug_mode_ignore_validator > 1) fprintf(stderr, "DEBUG MODE ENABLED (skip validator)\n"); if (verbosity) { int ix; char const *separator = ""; fprintf(stderr, "sel_ldr argument list:\n"); for (ix = 0; ix < argc; ++ix) { fprintf(stderr, "%s%s", separator, argv[ix]); separator = " "; } putc('\n', stderr); } if (debug_mode_bypass_acl_checks) { NaClInsecurelyBypassAllAclChecks(); } /* * change stdout/stderr to log file now, so that subsequent error * messages will go there. unfortunately, error messages that * result from getopt processing -- usually out-of-memory, which * shouldn't happen -- won't show up. */ if (NULL != log_file) { NaClLogSetFile(log_file); } if (rpc_supplies_nexe) { if (NULL != nacl_file) { fprintf(stderr, "sel_ldr: mutually exclusive flags -f and -R both used\n"); exit(1); } /* post: NULL == nacl_file */ if (export_addr_to < 0) { fprintf(stderr, "sel_ldr: -R requires -X to set up secure command channel\n"); exit(1); } } else { if (NULL == nacl_file && optind < argc) { nacl_file = argv[optind]; ++optind; } if (NULL == nacl_file) { fprintf(stderr, "No nacl file specified\n"); exit(1); } /* post: NULL != nacl_file */ } /* * post condition established by the above code (in Hoare logic * terminology): * * NULL == nacl_file iff rpc_supplies_nexe * * so hence forth, testing !rpc_supplies_nexe suffices for * establishing NULL != nacl_file. */ CHECK((NULL == nacl_file) == rpc_supplies_nexe); /* to be passed to NaClMain, eventually... */ argv[--optind] = (char *) "NaClMain"; state.ignore_validator_result = (debug_mode_ignore_validator > 0); state.skip_validator = (debug_mode_ignore_validator > 1); if (getenv("NACL_UNTRUSTED_EXCEPTION_HANDLING") != NULL) { state.enable_exception_handling = 1; } if (state.enable_exception_handling || enable_debug_stub) { #if NACL_WINDOWS state.attach_debug_exception_handler_func = NaClDebugExceptionHandlerStandaloneAttach; #elif NACL_LINUX /* NaCl's signal handler is always enabled on Linux. */ #elif NACL_OSX if (!NaClInterceptMachExceptions()) { fprintf(stderr, "ERROR setting up Mach exception interception.\n"); return -1; } #else # error Unknown host OS #endif } if (NACL_LINUX) { handle_signals = 1; } errcode = LOAD_OK; /* * in order to report load error to the browser plugin through the * secure command channel, we do not immediate jump to cleanup code * on error. rather, we continue processing (assuming earlier * errors do not make it inappropriate) until the secure command * channel is set up, and then bail out. */ /* * Ensure the platform qualification checks pass. * * NACL_DANGEROUS_SKIP_QUALIFICATION_TEST is used by tsan / memcheck * (see src/third_party/valgrind/). */ if (!skip_qualification && getenv("NACL_DANGEROUS_SKIP_QUALIFICATION_TEST") != NULL) { fprintf(stderr, "PLATFORM QUALIFICATION DISABLED BY ENVIRONMENT - " "Native Client's sandbox will be unreliable!\n"); skip_qualification = 1; } if (!skip_qualification) { NaClErrorCode pq_error = NACL_FI_VAL("pq", NaClErrorCode, NaClRunSelQualificationTests()); if (LOAD_OK != pq_error) { errcode = pq_error; nap->module_load_status = pq_error; fprintf(stderr, "Error while loading \"%s\": %s\n", NULL != nacl_file ? nacl_file : "(no file, to-be-supplied-via-RPC)", NaClErrorString(errcode)); } } if (handle_signals) { NaClSignalHandlerInit(); } else { /* * Patch the Windows exception dispatcher to be safe in the case * of faults inside x86-64 sandboxed code. The sandbox is not * secure on 64-bit Windows without this. */ #if (NACL_WINDOWS && NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && \ NACL_BUILD_SUBARCH == 64) NaClPatchWindowsExceptionDispatcher(); #endif } NaClSignalTestCrashOnStartup(); /* * Open both files first because (on Mac OS X at least) * NaClAppLoadFile() enables an outer sandbox. */ if (NULL != blob_library_file) { NaClFileNameForValgrind(blob_library_file); if (0 == GioMemoryFileSnapshotCtor(&blob_file, blob_library_file)) { perror("sel_main"); fprintf(stderr, "Cannot open \"%s\".\n", blob_library_file); exit(1); } NaClPerfCounterMark(&time_all_main, "SnapshotBlob"); NaClPerfCounterIntervalLast(&time_all_main); } NaClAppInitialDescriptorHookup(nap); if (!rpc_supplies_nexe) { struct GioMemoryFileSnapshot main_file; NaClFileNameForValgrind(nacl_file); if (0 == GioMemoryFileSnapshotCtor(&main_file, nacl_file)) { perror("sel_main"); fprintf(stderr, "Cannot open \"%s\".\n", nacl_file); exit(1); } NaClPerfCounterMark(&time_all_main, "SnapshotNaclFile"); NaClPerfCounterIntervalLast(&time_all_main); if (LOAD_OK == errcode) { NaClLog(2, "Loading nacl file %s (non-RPC)\n", nacl_file); errcode = NaClAppLoadFile((struct Gio *) &main_file, nap); if (LOAD_OK != errcode) { fprintf(stderr, "Error while loading \"%s\": %s\n", nacl_file, NaClErrorString(errcode)); fprintf(stderr, ("Using the wrong type of nexe (nacl-x86-32" " on an x86-64 or vice versa)\n" "or a corrupt nexe file may be" " responsible for this error.\n")); } NaClPerfCounterMark(&time_all_main, "AppLoadEnd"); NaClPerfCounterIntervalLast(&time_all_main); NaClXMutexLock(&nap->mu); nap->module_load_status = errcode; NaClXCondVarBroadcast(&nap->cv); NaClXMutexUnlock(&nap->mu); } if (-1 == (*((struct Gio *) &main_file)->vtbl->Close)((struct Gio *) &main_file)) { fprintf(stderr, "Error while closing \"%s\".\n", nacl_file); } (*((struct Gio *) &main_file)->vtbl->Dtor)((struct Gio *) &main_file); if (fuzzing_quit_after_load) { exit(0); } } /* * Execute additional I/O redirections. NB: since the NaClApp * takes ownership of host / IMC socket descriptors, all but * the first run will not get access if the NaClApp closes * them. Currently a normal NaClApp process exit does not * close descriptors, since the underlying host OS will do so * as part of service runtime exit. */ NaClLog(4, "Processing I/O redirection/inheritance from command line\n"); for (entry = redir_queue; NULL != entry; entry = entry->next) { switch (entry->tag) { case HOST_DESC: NaClAddHostDescriptor(nap, entry->u.host.d, entry->u.host.mode, entry->nacl_desc); break; case IMC_DESC: NaClAddImcHandle(nap, entry->u.handle, entry->nacl_desc); break; } } /* * If export_addr_to is set to a non-negative integer, we create a * bound socket and socket address pair and bind the former to * descriptor NACL_SERVICE_PORT_DESCRIPTOR (3 [see sel_ldr.h]) and * the latter to descriptor NACL_SERVICE_ADDRESS_DESCRIPTOR (4). * The socket address is sent to the export_addr_to descriptor. * * The service runtime also accepts a connection on the bound socket * and spawns a secure command channel thread to service it. */ if (0 <= export_addr_to) { NaClCreateServiceSocket(nap); /* * LOG_FATAL errors that occur before NaClSetUpBootstrapChannel will * not be reported via the crash log mechanism (for Chromium * embedding of NaCl, shown in the JavaScript console). * * Some errors, such as due to NaClRunSelQualificationTests, do not * trigger a LOG_FATAL but instead set module_load_status to be sent * in the start_module RPC reply. Log messages associated with such * errors would be seen, since NaClSetUpBootstrapChannel will get * called. */ NaClSetUpBootstrapChannel(nap, (NaClHandle) export_addr_to); /* * NB: spawns a thread that uses the command channel. we do * this after NaClAppLoadFile so that NaClApp object is more * fully populated. Hereafter any changes to nap should be done * while holding locks. */ NaClSecureCommandChannel(nap); } /* * May have created a thread, so need to synchronize uses of nap * contents henceforth. */ if (rpc_supplies_nexe) { errcode = NaClWaitForLoadModuleStatus(nap); NaClPerfCounterMark(&time_all_main, "WaitForLoad"); NaClPerfCounterIntervalLast(&time_all_main); } else { /************************************************************************** * TODO(bsy): This else block should be made unconditional and * invoked after the LoadModule RPC completes, eliminating the * essentially dulicated code in latter part of NaClLoadModuleRpc. * This cannot be done until we have full saucer separation * technology, since Chrome currently uses sel_main_chrome.c and * relies on the functionality of the duplicated code. *************************************************************************/ if (LOAD_OK == errcode) { if (verbosity) { gprintf((struct Gio *) &gout, "printing NaClApp details\n"); NaClAppPrintDetails(nap, (struct Gio *) &gout); } /* * Finish setting up the NaCl App. On x86-32, this means * allocating segment selectors. On x86-64 and ARM, this is * (currently) a no-op. */ errcode = NaClAppPrepareToLaunch(nap); if (LOAD_OK != errcode) { nap->module_load_status = errcode; fprintf(stderr, "NaClAppPrepareToLaunch returned %d", errcode); } NaClPerfCounterMark(&time_all_main, "AppPrepLaunch"); NaClPerfCounterIntervalLast(&time_all_main); } /* Give debuggers a well known point at which xlate_base is known. */ NaClGdbHook(&state); } /* * Tell the debug stub to bind a TCP port before enabling the outer * sandbox. This is only needed on Mac OS X since that is the only * platform where we have an outer sandbox in standalone sel_ldr. * In principle this call should work on all platforms, but Windows * XP seems to have some problems when we do bind()/listen() on a * separate thread from accept(). */ if (enable_debug_stub && NACL_OSX) { if (!NaClDebugBindSocket()) { exit(1); } } /* * Enable the outer sandbox, if one is defined. Do this as soon as * possible. * * This must come after NaClWaitForLoadModuleStatus(), which waits * for another thread to have called NaClAppLoadFile(). * NaClAppLoadFile() does not work inside the Mac outer sandbox in * standalone sel_ldr when using a dynamic code area because it uses * NaClCreateMemoryObject() which opens a file in /tmp. * * We cannot enable the sandbox if file access is enabled. */ if (!NaClAclBypassChecks && g_enable_outer_sandbox_func != NULL) { g_enable_outer_sandbox_func(); } if (NULL != blob_library_file) { if (LOAD_OK == errcode) { NaClLog(2, "Loading blob file %s\n", blob_library_file); errcode = NaClAppLoadFileDynamically(nap, (struct Gio *) &blob_file); if (LOAD_OK != errcode) { fprintf(stderr, "Error while loading \"%s\": %s\n", blob_library_file, NaClErrorString(errcode)); } NaClPerfCounterMark(&time_all_main, "BlobLoaded"); NaClPerfCounterIntervalLast(&time_all_main); } if (-1 == (*((struct Gio *) &blob_file)->vtbl->Close)((struct Gio *) &blob_file)) { fprintf(stderr, "Error while closing \"%s\".\n", blob_library_file); } (*((struct Gio *) &blob_file)->vtbl->Dtor)((struct Gio *) &blob_file); if (verbosity) { gprintf((struct Gio *) &gout, "printing post-IRT NaClApp details\n"); NaClAppPrintDetails(nap, (struct Gio *) &gout); } } /* * Print out a marker for scripts to use to mark the start of app * output. */ NaClLog(1, "NACL: Application output follows\n"); /* * Make sure all the file buffers are flushed before entering * the application code. */ fflush((FILE *) NULL); if (NULL != nap->secure_service) { NaClErrorCode start_result; /* * wait for start_module RPC call on secure channel thread. */ start_result = NaClWaitForStartModuleCommand(nap); NaClPerfCounterMark(&time_all_main, "WaitedForStartModuleCommand"); NaClPerfCounterIntervalLast(&time_all_main); if (LOAD_OK == errcode) { errcode = start_result; } } /* * error reporting done; can quit now if there was an error earlier. */ if (LOAD_OK != errcode) { NaClLog(4, "Not running app code since errcode is %s (%d)\n", NaClErrorString(errcode), errcode); goto done; } if (!DynArraySet(&env_vars, env_vars.num_entries, NULL)) { NaClLog(LOG_FATAL, "Adding env_vars NULL terminator failed\n"); } NaClEnvCleanserCtor(&env_cleanser, 0); if (!NaClEnvCleanserInit(&env_cleanser, envp, (char const *const *)env_vars.ptr_array)) { NaClLog(LOG_FATAL, "Failed to initialise env cleanser\n"); } if (!NaClAppLaunchServiceThreads(nap)) { fprintf(stderr, "Launch service threads failed\n"); goto done; } if (enable_debug_stub) { if (!NaClDebugInit(nap)) { goto done; } } NACL_TEST_INJECTION(BeforeMainThreadLaunches, ()); if (!NaClCreateMainThread(nap, argc - optind, argv + optind, NaClEnvCleanserEnvironment(&env_cleanser))) { fprintf(stderr, "creating main thread failed\n"); goto done; } NaClEnvCleanserDtor(&env_cleanser); NaClPerfCounterMark(&time_all_main, "CreateMainThread"); NaClPerfCounterIntervalLast(&time_all_main); DynArrayDtor(&env_vars); ret_code = NaClWaitForMainThreadToExit(nap); NaClPerfCounterMark(&time_all_main, "WaitForMainThread"); NaClPerfCounterIntervalLast(&time_all_main); NaClPerfCounterMark(&time_all_main, "SelMainEnd"); NaClPerfCounterIntervalTotal(&time_all_main); /* * exit_group or equiv kills any still running threads while module * addr space is still valid. otherwise we'd have to kill threads * before we clean up the address space. */ NaClExit(ret_code); done: fflush(stdout); if (verbosity) { gprintf((struct Gio *) &gout, "exiting -- printing NaClApp details\n"); NaClAppPrintDetails(nap, (struct Gio *) &gout); printf("Dumping vmmap.\n"); fflush(stdout); PrintVmmap(nap); fflush(stdout); } /* * If there is a secure command channel, we sent an RPC reply with * the reason that the nexe was rejected. If we exit now, that * reply may still be in-flight and the various channel closure (esp * reverse channel) may be detected first. This would result in a * crash being reported, rather than the error in the RPC reply. * Instead, we wait for the hard-shutdown on the command channel. */ if (LOAD_OK != errcode) { NaClBlockIfCommandChannelExists(nap); } if (verbosity > 0) { printf("Done.\n"); } fflush(stdout); if (handle_signals) NaClSignalHandlerFini(); NaClAllModulesFini(); NaClExit(ret_code); /* Unreachable, but having the return prevents a compiler error. */ return ret_code; }
int main(int argc, char **argv) { struct NaClApp app; struct NaClDesc *nd; NaClHandle handle_pair[2]; char *parse_args[] = {"prog", "parse"}; int return_code; char buffer[100]; NaClMessageHeader header; NaClIOVec vec; struct ncwebserver_t server; struct ncwebserver_conf_t conf; if (argc < 2){ usage(ncwebserver_usage_string); } NaClAllModulesInit(); NaClFileNameForValgrind(argv[1]); nd = (struct NaClDesc *) NaClDescIoDescOpen(argv[1], NACL_ABI_O_RDONLY, 0); CHECK(NULL != nd); CHECK(NaClAppCtor(&app)); /* Use a smaller guest address space size, because 32-bit Windows does not let us allocate 2GB of address space. We don't do this for x86-64 because there is an assertion in NaClAllocateSpace() that requires 4GB. */ #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 32 app.addr_bits = 29; /* 512MB per process */ #endif /* * On x86-32, we cannot enable ASLR even when the address space is * 512MB. In particular, when on Windows where the available * contiguous address space is tight, if the random choice for the * base of the first 512MB address space puts that address space * in the middle of the available address space region, the * address space allocation code might not be able to (randomly) * find another contiguous 512MB region for the second NaCl * module. */ CHECK(NaClAppLoadFileAslr(nd, &app, NACL_DISABLE_ASLR) == LOAD_OK); NaClAppInitialDescriptorHookup(&app); CHECK(NaClAppPrepareToLaunch(&app) == LOAD_OK); /* Set up an IMC connection between the host and guest. */ CHECK(NaClSocketPair(handle_pair) == 0); NaClAddImcHandle(&app, handle_pair[0], SEND_DESC); CHECK(NaClCreateMainThread(&app, 2, parse_args, NULL)); return_code = NaClWaitForMainThreadToExit(&app); CHECK(return_code == 101); // receive message sent from HTML parser vec.base = buffer; vec.length = sizeof buffer; memset(buffer, 0, sizeof buffer); header.iov = &vec; header.iov_length = 1; header.handles = NULL; header.handle_count = 0; return_code = NaClReceiveDatagram(handle_pair[1], &header, 0); assert(return_code == sizeof buffer); printf("Server received \"%s\" (with size = %d)\n", buffer+16, return_code); // run web server memset(&conf, 0, sizeof(conf)); parse_argv(argc, argv, &conf); ncwebserver_init(&server, &conf); ncwebserver_start(&server); /* * Avoid calling exit() because it runs process-global destructors * which might break code that is running in our unjoined threads. */ NaClExit(0); }
void NaClChromeMainInit(void) { CHECK(!g_initialized); NaClAllModulesInit(); g_initialized = 1; }
int main(int argc, char **argv) { int opt; uint64_t sleep_start_usec = kDefaultSleepStartMicroSeconds; uint64_t sleep_end_usec = kDefaultSleepEndMicroSeconds; uint64_t sleep_incr_usec = kDefaultSleepIncrMicroSeconds; uint64_t sleep_usec; uint64_t min_sleep; uint64_t max_sleep; uint64_t total_usec; char *nacl_verbosity = getenv("NACLVERBOSITY"); struct TestFunctorArg arg; int alarmer = 1; static void (*const test_tbl[])(void *) = { TestAbsWait, TestRelWait, }; size_t ix; while (EOF != (opt = getopt(argc, argv,"aAc:C:e:f:F:i:s:v"))) { switch (opt) { case 'a': alarmer = 1; break; case 'A': alarmer = 0; break; case 'c': gSchedulerMinFuzzConst = strtoul(optarg, (char **) 0, 0); break; case 'C': gSchedulerMaxMin = strtoul(optarg, (char **) 0, 0); break; case 'e': sleep_end_usec = strtoul(optarg, (char **) 0, 0); break; case 'f': gSchedulerMinFuzzFactor = atof(optarg); break; case 'F': gSchedulerMaxFuzzFactor = atof(optarg); break; case 'i': sleep_incr_usec = strtoul(optarg, (char **) 0, 0); break; case 's': sleep_start_usec = strtoul(optarg, (char **) 0, 0); break; case 'v': ++gVerbosity; break; default: fprintf(stderr, "Usage: nacl_sync_cond_test [flags]\n" " where flags specify the range of condition variable\n" " wait times:\n" " -a use an alarm thread to detect significant oversleep\n" " -A do not use an alarm thread\n" " -s start microseconds\n" " -e end microseconds\n" " -i increment microseconds\n" " -f scheduler fuzz factor (double; for min elapsed time)\n" " -F scheduler fuzz factor (double; max elapsed time)\n" " -c scheduler fuzz constant (int, uS)\n" " allow actual elapsed time to be this much less\n" " than requested.\n" " -C scheduler fuzz constant (int, uS)\n" " max allowed elapsed time is at least this\n" ); return 1; } } NaClAllModulesInit(); NaClLogSetVerbosity((NULL == nacl_verbosity) ? 0 : strtol(nacl_verbosity, (char **) 0, 0)); TestInit(); ASSERT_MSG(sleep_end_usec > sleep_start_usec, "nonsensical start/end times"); ASSERT_MSG(0 < sleep_incr_usec, "nonsensical increment time"); /* * sum of [m..n) by k is (m+n)(n-m)/k/2, and we run Rel and Abs, so * the expected time is twice the sum */ total_usec = (sleep_end_usec + sleep_start_usec) * (sleep_end_usec - sleep_start_usec) / sleep_incr_usec; printf("Test should take approximately %"NACL_PRId64 ".%06"NACL_PRId64" seconds" " on an unloaded machine.\n", total_usec / kMicroXinX, total_usec % kMicroXinX); for (sleep_usec = sleep_start_usec; sleep_usec < sleep_end_usec; sleep_usec += sleep_incr_usec) { if (gVerbosity) { printf("testing wait limit of %"NACL_PRId64 " microseconds.\n", sleep_usec); } arg.sleep_usec = sleep_usec; min_sleep = (int64_t) (gSchedulerMinFuzzFactor * sleep_usec); if (min_sleep < gSchedulerMinFuzzConst) { min_sleep = 0; } else { min_sleep -= gSchedulerMinFuzzConst; } max_sleep = (uint64_t) (gSchedulerMaxFuzzFactor * sleep_usec); if (max_sleep < gSchedulerMaxMin) { max_sleep = gSchedulerMaxMin; } for (ix = 0; ix < NACL_ARRAY_SIZE(test_tbl); ++ix) { FunctorDelays(test_tbl[ix], &arg, sleep_usec, min_sleep, max_sleep, alarmer); } } TestFini(); NaClAllModulesFini(); printf("PASS\n"); return 0; }
int main(int argc, char **argv) { char *nacl_file; struct NaClApp state; struct NaClApp *nap = &state; struct NaClAppThread nat, *natp = &nat; int errcode; uint32_t initial_addr; uint32_t addr; struct NaClVmmap *mem_map; struct NaClVmmapEntry *ent; char *nacl_verbosity = getenv("NACLVERBOSITY"); NaClHandleBootstrapArgs(&argc, &argv); if (argc < 2) { printf("No nexe file!\n\nFAIL\n"); } nacl_file = argv[1]; NaClAllModulesInit(); NaClLogSetVerbosity((NULL == nacl_verbosity) ? 0 : strtol(nacl_verbosity, (char **) 0, 0)); errcode = NaClAppCtor(&state); ASSERT_NE(errcode, 0); errcode = NaClAppLoadFileFromFilename(nap, nacl_file); ASSERT_EQ(errcode, LOAD_OK); InitThread(&state, natp); /* * Initial mappings: * 0. -- Zero page * 1. rx Static code segment * 2. r Read-only data segment * 3. rw Writable data segment * 4. rw Stack * There is no dynamic code area in this case. */ /* Check the initial mappings. */ mem_map = &state.mem_map; ASSERT_EQ(mem_map->nvalid, 5); CheckLowerMappings(mem_map); /* Allocate range */ addr = NaClSysMmapIntern(nap, 0, 3 * NACL_MAP_PAGESIZE, NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE, NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE, -1, 0); printf("addr=0x%"NACL_PRIx32"\n", addr); initial_addr = addr; /* * The mappings have changed to become: * 0. -- Zero page * 1. rx Static code segment * 2. r Read-only data segment * 3. rw Writable data segment * 4. rw mmap()'d anonymous, 3 pages (new) * 5. rw Stack */ /* Map to overwrite the start of the previously allocated range */ addr = NaClSysMmapIntern(nap, (void *) (uintptr_t) initial_addr, 2 * NACL_MAP_PAGESIZE, NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE, NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE | NACL_ABI_MAP_FIXED, -1, 0); printf("addr=0x%"NACL_PRIx32"\n", addr); ASSERT_EQ(addr, initial_addr); /* * The mappings have changed to become: * 0. -- Zero page * 1. rx Static code segment * 2. r Read-only data segment * 3. rw Writable data segment * 4. rw mmap()'d anonymous, 2 pages (new) * 5. rw mmap()'d anonymous, 1 pages (previous) * 6. rw Stack */ /* Allocate new page */ addr = NaClSysMmapIntern(nap, 0, NACL_MAP_PAGESIZE, NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE, NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE, -1, 0); printf("addr=0x%"NACL_PRIx32"\n", addr); /* * Our allocation strategy is to scan down from stack. This is an * implementation detail and not part of the guaranteed semantics, * but it is good to test that what we expect of our implementation * didn't change. */ ASSERT_EQ_MSG(addr, initial_addr - NACL_MAP_PAGESIZE, "Allocation strategy changed!"); /* * The mappings have changed to become: * 0. -- Zero page * 1. rx Static code segment * 2. r Read-only data segment * 3. rw Writable data segment * 4. rw mmap()'d anonymous, 1 pages (new) * 5. rw mmap()'d anonymous, 2 pages * 6. rw mmap()'d anonymous, 1 pages * 7. rw Stack */ NaClVmmapMakeSorted(mem_map); ASSERT_EQ(mem_map->nvalid, 8); CheckLowerMappings(mem_map); NaClVmmapDebug(mem_map, "After allocations"); /* Skip mappings 0, 1, 2 and 3. */ ASSERT_EQ(mem_map->vmentry[4]->page_num, (initial_addr - NACL_MAP_PAGESIZE) >> NACL_PAGESHIFT); ASSERT_EQ(mem_map->vmentry[4]->npages, NACL_PAGES_PER_MAP); ASSERT_EQ(mem_map->vmentry[5]->page_num, initial_addr >> NACL_PAGESHIFT); ASSERT_EQ(mem_map->vmentry[5]->npages, 2 * NACL_PAGES_PER_MAP); ASSERT_EQ(mem_map->vmentry[6]->page_num, (initial_addr + 2 * NACL_MAP_PAGESIZE) >> NACL_PAGESHIFT); ASSERT_EQ(mem_map->vmentry[6]->npages, NACL_PAGES_PER_MAP); /* * Undo effects of previous mmaps */ errcode = NaClSysMunmap(natp, (void *) (uintptr_t) (initial_addr - NACL_MAP_PAGESIZE), NACL_MAP_PAGESIZE * 4); ASSERT_EQ(errcode, 0); /* * Mappings return to being: * 0. -- Zero page * 1. rx Static code segment * 2. r Read-only data segment * 3. rw Writable data segment * 4. rw Stack */ ASSERT_EQ(mem_map->nvalid, 5); CheckLowerMappings(mem_map); /* Allocate range */ addr = NaClSysMmapIntern(nap, 0, 9 * NACL_MAP_PAGESIZE, NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE, NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE, -1, 0); printf("addr=0x%"NACL_PRIx32"\n", addr); initial_addr = addr; /* * The mappings have changed to become: * 0. -- Zero page * 1. rx Static code segment * 2. r Read-only data segment * 3. rw Writable data segment * 4. rw mmap()'d anonymous, 9 pages (new) * 5. rw Stack */ /* Map into middle of previously allocated range */ addr = NaClSysMmapIntern(nap, (void *) (uintptr_t) (initial_addr + 2 * NACL_MAP_PAGESIZE), 3 * NACL_MAP_PAGESIZE, NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE, NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE | NACL_ABI_MAP_FIXED, -1, 0); printf("addr=0x%"NACL_PRIx32"\n", addr); ASSERT_EQ(addr, initial_addr + NACL_MAP_PAGESIZE * 2); /* * The mappings have changed to become: * 0. -- Zero page * 1. rx Static code segment * 2. r Read-only data segment * 3. rw Writable data segment * 4. rw mmap()'d anonymous, 2 pages (previous) * 5. rw mmap()'d anonymous, 3 pages (new) * 6. rw mmap()'d anonymous, 4 pages (previous) * 7. rw Stack */ NaClVmmapMakeSorted(mem_map); ASSERT_EQ(mem_map->nvalid, 8); CheckLowerMappings(mem_map); ASSERT_EQ(mem_map->vmentry[4]->page_num, initial_addr >> NACL_PAGESHIFT); ASSERT_EQ(mem_map->vmentry[4]->npages, 2 * NACL_PAGES_PER_MAP); ASSERT_EQ(mem_map->vmentry[5]->page_num, (initial_addr + 2 * NACL_MAP_PAGESIZE) >> NACL_PAGESHIFT); ASSERT_EQ(mem_map->vmentry[5]->npages, 3 * NACL_PAGES_PER_MAP); ASSERT_EQ(mem_map->vmentry[6]->page_num, (initial_addr + 5 * NACL_MAP_PAGESIZE) >> NACL_PAGESHIFT); ASSERT_EQ(mem_map->vmentry[6]->npages, 4 * NACL_PAGES_PER_MAP); /* Change the memory protection of previously allocated range */ errcode = NaClSysMprotectInternal(nap, (initial_addr + 1 * NACL_MAP_PAGESIZE), 5 * NACL_MAP_PAGESIZE, NACL_ABI_PROT_READ); ASSERT_EQ(errcode, 0); /* * The mappings have changed to become: * 0. -- Zero page * 1. rx Static code segment * 2. r Read-only data segment * 3. rw Writable data segment * 4. rw mmap()'d anonymous, 1 pages (previous) * 5. r mmap()'d anonymous, 1 pages (new) * 6. r mmap()'d anonymous, 3 pages (new) * 7. r mmap()'d anonymous, 1 pages (new) * 8. rw mmap()'d anonymous, 3 pages (previous) * 9. rw Stack */ NaClVmmapMakeSorted(mem_map); ASSERT_EQ(mem_map->nvalid, 10); CheckLowerMappings(mem_map); ASSERT_EQ(mem_map->vmentry[4]->npages, 1 * NACL_PAGES_PER_MAP); ASSERT_EQ(mem_map->vmentry[4]->prot, NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE); ASSERT_EQ(mem_map->vmentry[5]->npages, 1 * NACL_PAGES_PER_MAP); ASSERT_EQ(mem_map->vmentry[5]->prot, NACL_ABI_PROT_READ); ASSERT_EQ(mem_map->vmentry[6]->npages, 3 * NACL_PAGES_PER_MAP); ASSERT_EQ(mem_map->vmentry[6]->prot, NACL_ABI_PROT_READ); ASSERT_EQ(mem_map->vmentry[7]->npages, 1 * NACL_PAGES_PER_MAP); ASSERT_EQ(mem_map->vmentry[7]->prot, NACL_ABI_PROT_READ); ASSERT_EQ(mem_map->vmentry[8]->npages, 3 * NACL_PAGES_PER_MAP); ASSERT_EQ(mem_map->vmentry[8]->prot, NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE); /* Change the memory protection of previously allocated range */ errcode = NaClSysMprotectInternal(nap, (initial_addr + 2 * NACL_MAP_PAGESIZE), 3 * NACL_MAP_PAGESIZE, NACL_ABI_PROT_NONE); ASSERT_EQ(errcode, 0); /* * The mappings have changed to become: * 0. -- Zero page * 1. rx Static code segment * 2. r Read-only data segment * 3. rw Writable data segment * 4. rw mmap()'d anonymous, 1 pages (previous) * 5. r mmap()'d anonymous, 1 pages (previous) * 6. -- mmap()'d anonymous, 3 pages (new) * 7. r mmap()'d anonymous, 1 pages (previous) * 8. rw mmap()'d anonymous, 3 pages (previous) * 9. rw Stack */ NaClVmmapMakeSorted(mem_map); ASSERT_EQ(mem_map->nvalid, 10); CheckLowerMappings(mem_map); ASSERT_EQ(mem_map->vmentry[4]->npages, 1 * NACL_PAGES_PER_MAP); ASSERT_EQ(mem_map->vmentry[4]->prot, NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE); ASSERT_EQ(mem_map->vmentry[5]->npages, 1 * NACL_PAGES_PER_MAP); ASSERT_EQ(mem_map->vmentry[5]->prot, NACL_ABI_PROT_READ); ASSERT_EQ(mem_map->vmentry[6]->npages, 3 * NACL_PAGES_PER_MAP); ASSERT_EQ(mem_map->vmentry[6]->prot, NACL_ABI_PROT_NONE); ASSERT_EQ(mem_map->vmentry[7]->npages, 1 * NACL_PAGES_PER_MAP); ASSERT_EQ(mem_map->vmentry[7]->prot, NACL_ABI_PROT_READ); ASSERT_EQ(mem_map->vmentry[8]->npages, 3 * NACL_PAGES_PER_MAP); ASSERT_EQ(mem_map->vmentry[8]->prot, NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE); /* * Undo effects of previous mmaps */ errcode = NaClSysMunmap(natp, (void *) (uintptr_t) initial_addr, 9 * NACL_MAP_PAGESIZE); ASSERT_EQ(errcode, 0); ASSERT_EQ(mem_map->nvalid, 5); CheckLowerMappings(mem_map); /* * Mappings return to being: * 0. -- Zero page * 1. rx Static code segment * 2. r Read-only data segment * 3. rw Writable data segment * 4. rw Stack */ /* * Check use of hint. */ addr = NaClSysMmapIntern(nap, (void *) (uintptr_t) initial_addr, NACL_MAP_PAGESIZE, NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE, NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE, -1, 0); ASSERT_LE(addr, 0xffff0000u); printf("addr=0x%"NACL_PRIx32"\n", addr); ASSERT_LE_MSG(initial_addr, addr, "returned address not at or above hint"); errcode = NaClSysMunmap(natp, (void *) (uintptr_t) addr, NACL_MAP_PAGESIZE); ASSERT_EQ(errcode, 0); /* Check handling of zero-sized mappings. */ addr = NaClSysMmapIntern(nap, 0, 0, NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE, NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE, -1, 0); ASSERT_EQ((int) addr, -NACL_ABI_EINVAL); errcode = NaClSysMunmap(natp, (void *) (uintptr_t) initial_addr, 0); ASSERT_EQ(errcode, -NACL_ABI_EINVAL); /* Check changing the memory protection of neighbouring mmaps */ addr = NaClSysMmapIntern(nap, 0, NACL_MAP_PAGESIZE, NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE, NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE, -1, 0); printf("addr=0x%"NACL_PRIx32"\n", addr); initial_addr = addr; addr = NaClSysMmapIntern(nap, (void *) (uintptr_t) (initial_addr + NACL_MAP_PAGESIZE), NACL_MAP_PAGESIZE, NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE, NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE | NACL_ABI_MAP_FIXED, -1, 0); printf("addr=0x%"NACL_PRIx32"\n", addr); ASSERT_EQ(addr, initial_addr + NACL_MAP_PAGESIZE); errcode = NaClSysMprotectInternal(nap, initial_addr, 2 * NACL_MAP_PAGESIZE, NACL_ABI_PROT_READ); ASSERT_EQ(errcode, 0); /* Undo effects of previous mmaps */ errcode = NaClSysMunmap(natp, (void *) (uintptr_t) initial_addr, 2 * NACL_MAP_PAGESIZE); ASSERT_EQ(errcode, 0); /* Check that we cannot make the read-only data segment writable */ ent = mem_map->vmentry[2]; errcode = NaClSysMprotectInternal(nap, (uint32_t) (ent->page_num << NACL_PAGESHIFT), ent->npages * NACL_MAP_PAGESIZE, NACL_ABI_PROT_WRITE); ASSERT_EQ(errcode, -NACL_ABI_EACCES); #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64 CheckForGuardRegion(nap->mem_start - ((size_t) 40 << 30), (size_t) 40 << 30); CheckForGuardRegion(nap->mem_start + ((size_t) 4 << 30), (size_t) 40 << 30); #endif NaClAddrSpaceFree(nap); printf("PASS\n"); return 0; }
int NaClMainForChromium(int handle_count, const NaClHandle *handles, int debug) { char *av[1]; int ac = 1; const char **envp; struct NaClApp state; int main_thread_only = 1; char *nacl_file = "test_nexe/hello_ppapi.nexe"; struct NaClApp *nap; enum NaClAbiCheckOption check_abi = NACL_ABI_CHECK_OPTION_CHECK; struct GioFile gout; struct GioMemoryFileSnapshot gf; NaClErrorCode errcode; int ret_code = 1; struct NaClEnvCleanser env_cleanser; #if NACL_OSX /* Mac dynamic libraries cannot access the environ variable directly. */ envp = (const char **) *_NSGetEnviron(); #else /* Overzealous code style check is overzealous. */ /* @IGNORE_LINES_FOR_CODE_HYGIENE[1] */ extern char **environ; envp = (const char **) environ; #endif NaClAllModulesInit(); /* Add a handler to catch untrusted errors only */ NaClSignalHandlerAdd(NaClSignalHandleUntrusted); /* to be passed to NaClMain, eventually... */ av[0] = "NaClMain"; if (!NaClAppCtor(&state)) { fprintf(stderr, "Error while constructing app state\n"); goto done; } state.restrict_to_main_thread = main_thread_only; nap = &state; errcode = LOAD_OK; /* * in order to report load error to the browser plugin through the * secure command channel, we do not immediate jump to cleanup code * on error. rather, we continue processing (assuming earlier * errors do not make it inappropriate) until the secure command * channel is set up, and then bail out. */ /* * Ensure this operating system platform is supported. */ errcode = NaClRunSelQualificationTests(); if (LOAD_OK != errcode) { nap->module_load_status = errcode; fprintf(stderr, "Error while loading in SelMain: %s\n", NaClErrorString(errcode)); } /* Give debuggers a well known point at which xlate_base is known. */ NaClGdbHook(&state); if (0 == GioMemoryFileSnapshotCtor(&gf, nacl_file)) { perror("sel_main"); fprintf(stderr, "Cannot open \"%s\".\n", nacl_file); errcode = LOAD_OPEN_ERROR; } if (LOAD_OK == errcode) { errcode = NaClAppLoadFile((struct Gio *) &gf, nap, check_abi); if (LOAD_OK != errcode) { fprintf(stderr, "Error while loading \"%s\": %s\n", nacl_file, NaClErrorString(errcode)); fprintf(stderr, ("Using the wrong type of nexe (nacl-x86-32" " on an x86-64 or vice versa)\n" "or a corrupt nexe file may be" " responsible for this error.\n")); } NaClXMutexLock(&nap->mu); nap->module_load_status = errcode; NaClXCondVarBroadcast(&nap->cv); NaClXMutexUnlock(&nap->mu); } if (LOAD_OK == errcode) { if (verbosity) { gprintf((struct Gio *) &gout, "printing NaClApp details\n"); NaClAppPrintDetails(nap, (struct Gio *) &gout); } /* * Finish setting up the NaCl App. This includes dup'ing * descriptors 0-2 and making them available to the NaCl App. */ errcode = NaClAppPrepareToLaunch(nap, 0, 1, 2); if (LOAD_OK != errcode) { nap->module_load_status = errcode; fprintf(stderr, "NaClAppPrepareToLaunch returned %d", errcode); } } if (-1 == (*((struct Gio *) &gf)->vtbl->Close)((struct Gio *) &gf)) { fprintf(stderr, "Error while closing \"%s\".\n", nacl_file); } (*((struct Gio *) &gf)->vtbl->Dtor)((struct Gio *) &gf); /* * Print out a marker for scripts to use to mark the start of app * output. */ NaClLog(1, "NACL: Application output follows\n"); /* * Make sure all the file buffers are flushed before entering * the application code. */ fflush((FILE *) NULL); /* * Enable debugging if requested. */ if (debug) NaClDebugSetAllow(1); NaClEnvCleanserCtor(&env_cleanser); if (!NaClEnvCleanserInit(&env_cleanser, envp)) { NaClLog(LOG_FATAL, "Failed to initialise env cleanser\n"); } /* * only nap->ehdrs.e_entry is usable, no symbol table is * available. */ if (!NaClCreateMainThread(nap, ac, av, NaClEnvCleanserEnvironment(&env_cleanser))) { fprintf(stderr, "creating main thread failed\n"); goto done; } NaClEnvCleanserDtor(&env_cleanser); ret_code = NaClWaitForMainThreadToExit(nap); /* * exit_group or equiv kills any still running threads while module * addr space is still valid. otherwise we'd have to kill threads * before we clean up the address space. */ return ret_code; done: fflush(stdout); NaClAllModulesFini(); return ret_code; }