/* * Test that we can wake up multiple threads, and that futex_wake() * heeds the wakeup limit. */ void test_futex_wakeup_limit(void) { volatile int futex_value = 1; struct ThreadState threads[4]; int i; for (i = 0; i < NACL_ARRAY_SIZE(threads); i++) { create_waiting_thread(&futex_value, &threads[i]); } check_futex_wake(&futex_value, 2, 2); /* * Test that threads are woken up in the order that they were added * to the wait queue. This is not necessarily true for the Linux * implementation of futexes, but it is true for NaCl's * implementation. */ assert_thread_woken(&threads[0]); assert_thread_woken(&threads[1]); assert_thread_not_woken(&threads[2]); assert_thread_not_woken(&threads[3]); /* Clean up: Wake the remaining threads so that they can exit. */ check_futex_wake(&futex_value, INT_MAX, 2); assert_thread_woken(&threads[2]); assert_thread_woken(&threads[3]); for (i = 0; i < NACL_ARRAY_SIZE(threads); i++) { ASSERT_EQ(pthread_join(threads[i].tid, NULL), 0); } }
int main(int argc, char **argv) { char buffer[4096]; char *bufptr = buffer; size_t ix; /* type signature of main is constrained by SDL */ UNREFERENCED_PARAMETER(argc); UNREFERENCED_PARAMETER(argv); NACL_ASSERT_IS_POINTER(bufptr); NACL_ASSERT_IS_ARRAY(buffer); /* * NACL_ASSERT_IS_ARRAY(bufptr); */ printf("#buffer = %"NACL_PRIuS"\n", NACL_ARRAY_SIZE(buffer)); /* * printf("#bufptr = %lu\n", ARRAY_SIZE(bufptr)); */ /* * for checking that the store to gNaClArrayCheck is moved out of * the loop. */ for (ix = 0; ix < NACL_ARRAY_SIZE(buffer); ++ix) { buffer[ix] = (char) ix; } return (buffer[10] + buffer[4095] == 0); /* loop was not dead code! */ }
int main(void) { char buffer[4096]; char *bufptr = buffer; size_t ix; NACL_ASSERT_IS_POINTER(bufptr); NACL_ASSERT_IS_ARRAY(buffer); /* * NACL_ASSERT_IS_ARRAY(bufptr); */ printf("#buffer = %"NACL_PRIuS"\n", NACL_ARRAY_SIZE(buffer)); /* * printf("#bufptr = %lu\n", ARRAY_SIZE(bufptr)); */ /* * for checking that the store to gNaClArrayCheck is moved out of * the loop. */ for (ix = 0; ix < NACL_ARRAY_SIZE(buffer); ++ix) { buffer[ix] = (char) ix; } return (buffer[10] + buffer[4095] == 0); /* loop was not dead code! */ }
/* * Reads the header of the message to determine whether to call RecvRequest or * RecvResponse. */ static ssize_t SrpcPeekMessage(struct NaClSrpcMessageChannel* channel, NaClSrpcRpc* rpc) { struct NaClImcMsgIoVec iov[1]; const size_t kMaxIovLen = NACL_ARRAY_SIZE(iov); size_t iov_len; NaClSrpcMessageHeader header; size_t expected_bytes; ssize_t retval; iov_len = 0; expected_bytes = 0; AddIovEntry(rpc, kRpcSize, kMaxIovLen, iov, &iov_len, &expected_bytes); header.iov = iov; header.iov_length = NACL_ARRAY_SIZE(iov); header.NACL_SRPC_MESSAGE_HEADER_DESCV = NULL; header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = 0; retval = NaClSrpcMessageChannelPeek(channel, &header); /* * Check that the peek read the RPC and that the argument lengths are sane. */ if (retval < (ssize_t) expected_bytes) { retval = ErrnoFromImcRet(retval); } else if (rpc->value_len > NACL_SRPC_MAX_ARGS || rpc->template_len > NACL_SRPC_MAX_ARGS) { retval = -NACL_ABI_EIO; } return retval; }
size_t NaClErrorGioGetOutput(struct NaClErrorGio *self, char *buffer, size_t buffer_size) { size_t num_copy; size_t ix; size_t count; num_copy = self->num_bytes; /* 0 <= num_copy <= NACL_ARRAY_SIZE(self->circular_buffer) */ if (0 == buffer_size) { return self->num_bytes; } /* buffer_size > 0 */ if (num_copy > buffer_size) { num_copy = buffer_size; } /* * 0 <= num_copy <= min(NACL_ARRAY_SIZE(self->circular_buffer), * buffer_size) */ ix = (self->insert_ix + NACL_ARRAY_SIZE(self->circular_buffer) - self->num_bytes) % NACL_ARRAY_SIZE(self->circular_buffer); for (count = 0; count < num_copy; ++count) { buffer[count] = self->circular_buffer[ix]; ix = (ix + 1) % NACL_ARRAY_SIZE(self->circular_buffer); } /* * count = num_copy * <= min(NACL_ARRAY_SIZE(self->circular_buffer), buffer_size) */ return self->num_bytes; }
/* * Install a syscall trampoline at target_addr. PIC version. */ void NaClPatchOneTrampoline(struct NaClApp *nap, uintptr_t target_addr) { struct NaClPatchInfo patch_info; struct NaClPatch patch32[1]; struct NaClPatch patch16[1]; UNREFERENCED_PARAMETER(nap); patch16[0].target = ((uintptr_t) &NaCl_tramp_cseg_patch) - 2; patch16[0].value = NaClGetGlobalCs(); patch32[0].target = ((uintptr_t) &NaCl_tramp_cseg_patch) - 6; patch32[0].value = (uintptr_t) nap->pcrel_thunk; NaClPatchInfoCtor(&patch_info); patch_info.abs16 = patch16; patch_info.num_abs16 = NACL_ARRAY_SIZE(patch16); patch_info.abs32 = patch32; patch_info.num_abs32 = NACL_ARRAY_SIZE(patch32);; patch_info.dst = target_addr; patch_info.src = (uintptr_t) &NaCl_trampoline_seg_code; patch_info.nbytes = ((uintptr_t) &NaCl_trampoline_seg_end - (uintptr_t) &NaCl_trampoline_seg_code); NaClApplyPatchToMemory(&patch_info); }
/* Add OperandZeroExtends_v instruction flag if applicable. */ void NaClAddZeroExtend32FlagIfApplicable(void) { if ((X86_64 == NACL_FLAGS_run_mode) && NaClInInstructionSet(kZeroExtend32Op, NACL_ARRAY_SIZE(kZeroExtend32Op), kZeroExtend32Opseq, NACL_ARRAY_SIZE(kZeroExtend32Opseq))) { AddZeroExtendToOpDestArgs(NaClGetDefInst()); } }
void NaClAddJumpFlagsIfApplicable(void) { NaClAddJumpFlags(JumpInstruction, kDefinesUnconditionalJump, NACL_ARRAY_SIZE(kDefinesUnconditionalJump)); NaClAddJumpFlags(ConditionalJump, kDefinesConditionalJumpWithHints, NACL_ARRAY_SIZE(kDefinesConditionalJumpWithHints)); NaClAddJumpFlags(BranchHints, kDefinesConditionalJumpWithHints, NACL_ARRAY_SIZE(kDefinesConditionalJumpWithHints)); NaClAddJumpFlags(ConditionalJump, kDefinesConditionalJumpWithoutHints, NACL_ARRAY_SIZE(kDefinesConditionalJumpWithoutHints)); }
int ReadWriteTest(void) { static int test_data[] = { 3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3, 2, 3, 8, 4, 6, 2, 6, 4, 3, 3, 8, 3, 2, 7, 9, 5, 0, 2, 8, 8, 4, 1, 9, 7, 1, 6, 9, 3, 9, 9, 3, 7, 5, 1, 0, 5, 8, 2, 0, 9, 7, 4, 9, 4, 4, 5, 9, 2, 3, 0, 7, 8, 1, 6, 4, 0, 6, 2, 8, 6, 2, 0, 8, 9, 9, 8, 6, 2, 8, 0, 3, 4, 8, 2, 5, 3, 4, 2, 1, 1, 7, 0, 6, 7, 6 }; struct DynArray da; int i; int nerrors = 0; printf("\nReadWriteTest\n"); DynArrayCtor(&da, 2); for (i = 0; i < NACL_ARRAY_SIZE(test_data); ++i) { if (!DynArraySet(&da, i, (void *) test_data[i])) { printf("insert for position %d failed\n", i); ++nerrors; } } for (i = 0; i < NACL_ARRAY_SIZE(test_data); ++i) { if ((int) DynArrayGet(&da, i) != test_data[i]) { printf("check for value at position %d failed\n", i); ++nerrors; } } DynArrayDtor(&da); DynArrayCtor(&da, 10); for (i = NACL_ARRAY_SIZE(test_data); --i >= 0; ) { if (!DynArraySet(&da, i, (void *) test_data[i])) { printf("insert for position %d failed\n", i); ++nerrors; } } for (i = NACL_ARRAY_SIZE(test_data); --i >= 0; ) { if ((int) DynArrayGet(&da, i) != test_data[i]) { printf("check for value at position %d failed\n", i); ++nerrors; } } DynArrayDtor(&da); printf(0 != nerrors ? "FAIL\n" : "OK\n"); return nerrors; }
void NaClAddRepPrefixFlagsIfApplicable() { if (NaClInInstructionSet(kAllowableRepMnemonic, NACL_ARRAY_SIZE(kAllowableRepMnemonic), kAllowableRepMnemonicOpseq, NACL_ARRAY_SIZE(kAllowableRepMnemonicOpseq))) { NaClAddIFlags(NACL_IFLAG(OpcodeAllowsRep)); } if (NaClInInstructionSet(kAllowableRepneMnemonic, NACL_ARRAY_SIZE(kAllowableRepneMnemonic), NULL, 0)) { NaClAddIFlags(NACL_IFLAG(OpcodeAllowsRepne)); } }
int main(void) { char buffer[4096]; printf("#buffer = %"NACL_PRIuS"\n", NACL_ARRAY_SIZE(buffer)); return 0; }
int NaClEnvInWhitelist(char const *env_entry) { return NULL != bsearch((void const *) &env_entry, (void const *) kNaClEnvWhitelist, NACL_ARRAY_SIZE(kNaClEnvWhitelist) - 1, /* NULL */ sizeof kNaClEnvWhitelist[0], EnvCmp); }
/* * Write out num_bytes (a multiple of 4) bytes of data. If * !halt_fill, ASCII NUL is used; otherwise NACL_HALT_WORD is used. */ int CreateTestData(int d, size_t num_bytes, int halt_fill) { static int buffer[1024]; size_t ix; size_t nbytes; size_t written = 0; ssize_t result; printf("num_bytes = %zx\n", num_bytes); CHECK((num_bytes & (size_t) 0x3) == 0); if (halt_fill) { for (ix = 0; ix < NACL_ARRAY_SIZE(buffer); ++ix) { buffer[ix] = NACL_HALT_WORD; } } else { memset(buffer, 0, sizeof buffer); } while (written < num_bytes) { nbytes = num_bytes - written; if (nbytes > sizeof buffer) { nbytes = sizeof buffer; } result = write(d, buffer, nbytes); if (result != nbytes) { return -1; } written += nbytes; } return 0; }
int main(void) { char *bufptr = NULL; printf("#bufptr = %"NACL_PRIuS"\n", NACL_ARRAY_SIZE(bufptr)); return 0; }
static void RegisterHandlers(void) { int signals[] = { SIGSEGV, SIGABRT }; size_t index; for (index = 0; index < NACL_ARRAY_SIZE(signals); index++) { CHECK(signal(signals[index], SignalHandler) == 0); } NaClSignalHandlerInit(); }
int NaClErrorGioCtor(struct NaClErrorGio *self, struct Gio *pass_through) { memset(self->circular_buffer, 0, NACL_ARRAY_SIZE(self->circular_buffer)); self->insert_ix = 0; self->num_bytes = 0; self->pass_through = pass_through; self->vtbl = &kNaClErrorGioVtbl; return 1; }
int NaCl_ThisCPUIsBlacklisted(void) { NaClCPUData data; const char* myid; NaClCPUDataGet(&data); myid = GetCPUIDString(&data); return IsCpuInList(myid, kNaClCpuBlacklist, NACL_ARRAY_SIZE(kNaClCpuBlacklist)); }
static int is_irt_interface_whitelisted(const char *interface_name) { int i; for (i = 0; i < NACL_ARRAY_SIZE(irt_interface_whitelist); i++) { if (mystrcmp(interface_name, irt_interface_whitelist[i]) == 0) { return 1; } } return 0; }
void NaClErrorGioDtor(struct Gio *vself) { struct NaClErrorGio *self = (struct NaClErrorGio *) vself; /* excessive paranoia? */ memset(self->circular_buffer, 0, NACL_ARRAY_SIZE(self->circular_buffer)); self->insert_ix = 0; self->num_bytes = 0; self->pass_through = NULL; self->vtbl = NULL; }
int NaClResourceNaClAppInit(struct NaClResourceNaClApp *rp, struct NaClApp *nap) { static struct NaClResourceSchemes const schemes[] = { { NACL_RESOURCE_FILE_PREFIX, 1, /* default scheme */ NaClResourceNaClAppFileOpen, }, }; NaClLog(4, "NaClResourceNaClAppInit -- Ctor with default schemes\n"); return NaClResourceNaClAppCtor(rp, schemes, NACL_ARRAY_SIZE(schemes), nap); }
/* * Read the next fragment of a message into channel's buffer. */ static uint32_t MessageChannelBufferFirstFragment( struct NaClSrpcMessageChannel* channel) { ssize_t imc_ret = -1; NaClSrpcMessageHeader buffer_header; struct NaClImcMsgIoVec iovec[1]; NaClSrpcLog(3, "MessageChannelBufferFirstFragment: waiting for message.\n"); /* Read the entire first fragment into channel's buffer. */ buffer_header.iov = iovec; buffer_header.iov_length = NACL_ARRAY_SIZE(iovec); buffer_header.NACL_SRPC_MESSAGE_HEADER_DESCV = channel->descs; buffer_header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = NACL_ARRAY_SIZE(channel->descs); buffer_header.iov[0].base = channel->bytes; buffer_header.iov[0].length = NACL_ARRAY_SIZE(channel->bytes); buffer_header.flags = 0; /* * The message receive should return at least * kFragmentOverhead[FIRST_FRAGMENT] bytes. */ imc_ret = ImcRecvmsg(channel->desc.raw_desc, &buffer_header, 0); if ((imc_ret < (ssize_t) kFragmentOverhead[FIRST_FRAGMENT]) || (buffer_header.flags != 0)) { NaClSrpcLog(3, "MessageChannelBufferFirstFragment: read failed (%" NACL_PRIdS").\n", imc_ret); return 0; } NaClSrpcLog(3, "MessageChannelBufferFirstFragment: buffered message: " "bytes %"NACL_PRIdS", descs %"NACL_PRIuS".\n", imc_ret, (size_t) buffer_header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH); channel->byte_count = imc_ret; channel->desc_count = buffer_header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH; return 1; }
static void RpcCheckingClosureRun(NaClSrpcClosure* self) { RpcCheckingClosure* vself = (RpcCheckingClosure*) self; NaClSrpcRpc* rpc = vself->rpc; ssize_t retval; do { const char* rpc_name; const char* arg_types; const char* ret_types; int i; NaClSrpcServiceMethodNameAndTypes(rpc->channel->server, rpc->rpc_number, &rpc_name, &arg_types, &ret_types); NaClSrpcLog(1, "RpcCheckingClosureRun: response(channel=%p," " rpc_number=%"NACL_PRIu32 ", rpc_name=\"%s\", result=%d, string=\"%s\")\n", (void*) rpc->channel, rpc->rpc_number, rpc_name, rpc->result, NaClSrpcErrorString(rpc->result)); for (i = 0; rpc->rets[i] != NULL; i++ ) { char buffer[256]; NaClSrpcFormatArg(2, rpc->rets[i], buffer, NACL_ARRAY_SIZE(buffer)); NaClSrpcLog(2, "RpcCheckingClosureRun: response(channel=%p, rets[%d]=%s)\n", (void*) rpc->channel, i, buffer); } } while(0); /* Send the RPC response to the caller. */ rpc->is_request = 0; rpc->dispatch_loop_should_continue = 1; if (NACL_SRPC_RESULT_BREAK == rpc->result) { NaClSrpcLog(2, "RpcCheckingClosureRun: server requested break\n"); rpc->result = NACL_SRPC_RESULT_OK; rpc->dispatch_loop_should_continue = 0; } retval = SrpcSendMessage(rpc, NULL, rpc->rets, rpc->channel->message_channel); if (retval < 0) { /* If the response write failed, drop request and continue. */ NaClSrpcLog(NACL_SRPC_LOG_ERROR, "RpcCheckingClosureRun: response write failed\n"); } free(self); }
/* * It is the responsibility of the invoking environment to delete the * file passed as command-line argument. See the build.scons file. */ int main(int ac, char **av) { char const *test_dir_name = "/tmp/nacl_host_desc_test"; struct NaClHostDesc hd; struct NaClHostDesc hd_ro; size_t error_count; size_t ix; int test_passed; int opt; int num_runs = 1; int test_run; while (EOF != (opt = getopt(ac, av, "c:t:"))) { switch (opt) { case 'c': num_runs = atoi(optarg); break; case 't': test_dir_name = optarg; break; default: fprintf(stderr, "Usage: nacl_host_desc_mmap_test [-c run_count]\n" " [-t test_temp_dir]\n"); exit(1); } } NaClPlatformInit(); error_count = 0; for (test_run = 0; test_run < num_runs; ++test_run) { printf("Test run %d\n\n", test_run); for (ix = 0; ix < NACL_ARRAY_SIZE(tests); ++ix) { char test_file_name[PATH_MAX]; SNPRINTF(test_file_name, sizeof test_file_name, "%s/f%d.%"NACL_PRIuS, test_dir_name, test_run, ix); printf("%s\n", tests[ix].test_name); CreateTestFile(&hd, &hd_ro, test_file_name, &tests[ix]); test_passed = (*tests[ix].test_func)(&hd, &hd_ro, tests[ix].test_params); CloseTestFile(&hd); error_count += !test_passed; printf("%s\n", test_passed ? "PASSED" : "FAILED"); } } NaClPlatformFini(); /* we ignore the 2^32 or 2^64 total errors case */ return (error_count > 255) ? 255 : error_count; }
/* * Logging hooks to get recent output up to and including that of the * LOG_FATAL that triggered this callback to the plugin and on-stack * for breakpad. * * NB: the total amount sent should not be greater than what can be * buffered in kernel buffers (typically 4K), since the plugin does * not necessarily have a thread blocked reading the data (we may add * one later). If the write blocks, then the abort-detection * machinery in the plugin cannot kick in, since that relies on * detecting communication channels (e.g., for reverse service) * closing as a side-effect of the service runtime exiting. * * It is safe to send blindly an amount less than what can be buffered * by the kernel, since even if we are running with a version of the * plugin that ignores the data, we won't block. */ void NaClBootstrapChannelErrorReporter(void *state, char *buf, size_t buf_bytes) { static int handling_error = 0; int horrible_recursive_error; struct NaClApp *nap = (struct NaClApp *) state; struct NaClDesc *channel = NULL; ssize_t rv; struct NaClImcTypedMsgHdr hdr; struct NaClImcMsgIoVec iov[1]; /* * NB: if any of the code below generates a NaClLog(LOG_FATAL, ...), * we would be called recursively, possibly ad infinitum/nauseum. * Try to prevent this by using a static boolean state variable to * detect it and return quickly. We cannot take the nap->mu lock, * since LOG_FATALs can occur while holding that lock and thus * result in a deadlock. Luckily, the bootstrap_channel member is * read-only before we go multi-threaded. */ NaClXMutexLock(&g_nacl_bootstrap_mu); horrible_recursive_error = handling_error; /* copy while holding lock */ handling_error = 1; NaClXMutexUnlock(&g_nacl_bootstrap_mu); if (horrible_recursive_error) { return; } if (NULL != nap->bootstrap_channel) { channel = nap->bootstrap_channel; iov[0].base = buf; iov[0].length = buf_bytes; hdr.iov = iov; hdr.iov_length = NACL_ARRAY_SIZE(iov); hdr.ndescv = NULL; hdr.ndesc_length = 0; hdr.flags = 0; rv = (*NACL_VTBL(NaClDesc, channel)->SendMsg)(channel, &hdr, 0); if (rv < 0 || (size_t) rv != buf_bytes) { fprintf(stderr, ("NaClBootstrapChannelErrorReporter: SendMsg returned %" NACL_PRIdS", expected %"NACL_PRIuS".\n"), rv, buf_bytes); } } /* done / give up */ }
size_t nacl_irt_interface(const char *interface_ident, void *table, size_t tablesize) { int 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; } } return 0; }
ssize_t NaClErrorGioWrite(struct Gio *vself, void const *buf, size_t count) { struct NaClErrorGio *self = (struct NaClErrorGio *) vself; uint8_t *byte_buf = (uint8_t *) buf; ssize_t actual; size_t ix; actual = (*self->pass_through->vtbl->Write)(self->pass_through, buf, count); if (actual > 0) { for (ix = 0; ix < (size_t) actual; ++ix) { self->circular_buffer[self->insert_ix] = byte_buf[ix]; self->insert_ix = (self->insert_ix + 1) % NACL_ARRAY_SIZE(self->circular_buffer); } if ((size_t) actual > NACL_ARRAY_SIZE(self->circular_buffer) - self->num_bytes) { self->num_bytes = NACL_ARRAY_SIZE(self->circular_buffer); } else { self->num_bytes += actual; } } return actual; }
static void NaClReportLogMessages(void) { char log_data[NACL_ERROR_GIO_MAX_BYTES]; size_t log_data_bytes; if (NULL != g_NaCl_log_abort_fn) { /* * Copy the last NACL_ERROR_GIO_MAX_BYTES of log output to the * calling thread's stack, so that breakpad will pick it up. */ log_data_bytes = NaClErrorGioGetOutput(&g_NaCl_log_gio, log_data, NACL_ARRAY_SIZE(log_data)); (*g_NaCl_log_abort_fn)(g_NaCl_log_abort_state, log_data, log_data_bytes); } }
void NaClSetSignalHandler(void) { struct sigaction action; stack_t stack; stack.ss_sp = g_nacl_altstack; stack.ss_flags = 0; stack.ss_size = NACL_ARRAY_SIZE(g_nacl_altstack); sigaltstack(&stack, (stack_t *) NULL); memset(&action, 0, sizeof action); action.sa_sigaction = NaClSignalHandler; sigfillset(&action.sa_mask); action.sa_flags = SA_ONSTACK | SA_SIGINFO; CHECK(0 == sigaction(kExpectedSignal, &action, (struct sigaction *) NULL)); }
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; }
void __NaClSrpcImcBufferCtor(NaClSrpcImcBuffer* buffer, int is_write_buf) { buffer->iovec[0].base = buffer->bytes; buffer->iovec[0].length = sizeof(buffer->bytes); buffer->header.iov = buffer->iovec; buffer->header.iov_length = sizeof(buffer->iovec) / sizeof(buffer->iovec[0]); NACL_SRPC_IMC_HEADER_DESCV(*buffer) = buffer->descs; if (is_write_buf) { NACL_SRPC_IMC_HEADER_DESC_LENGTH(*buffer) = 0; } else { NACL_SRPC_IMC_HEADER_DESC_LENGTH(*buffer) = NACL_ARRAY_SIZE(buffer->descs); } buffer->header.flags = 0; /* Buffers start out empty */ buffer->next_byte = 0; buffer->last_byte = 0; }