static NaClValidationStatus IsOnInstBoundary_x86_64( uintptr_t guest_addr, uintptr_t addr, const uint8_t *data, size_t size, const NaClCPUFeatures *f) { NaClCPUFeaturesX86 *cpu_features = (NaClCPUFeaturesX86 *) f; struct IsOnInstBoundaryCallbackData callback_data; uint32_t guest_bundle_addr = (addr & ~kBundleMask); const uint8_t *local_bundle_addr = data + (guest_bundle_addr - guest_addr); int rc; /* Check code range doesn't overflow. */ CHECK(guest_addr + size > guest_addr); CHECK(size % kBundleSize == 0 && size != 0); CHECK((uint32_t) (guest_addr & ~kBundleMask) == guest_addr); /* Check addr is within code boundary. */ if (addr < guest_addr || addr >= guest_addr + size) return NaClValidationFailed; callback_data.found_addr = FALSE; callback_data.addr = data + (addr - guest_addr); rc = ValidateChunkAMD64(local_bundle_addr, kBundleSize, CALL_USER_CALLBACK_ON_EACH_INSTRUCTION, cpu_features, IsOnInstBoundaryCallback, &callback_data); CHECK(rc); return callback_data.found_addr ? NaClValidationSucceeded : NaClValidationFailed; }
static NaClValidationStatus ValidatorCodeReplacement_x86_64( uintptr_t guest_addr, uint8_t *data_existing, uint8_t *data_new, size_t size, const NaClCPUFeatures *f) { /* TODO(jfb) Use a safe cast here. */ NaClCPUFeaturesX86 *cpu_features = (NaClCPUFeaturesX86 *) f; UNREFERENCED_PARAMETER(guest_addr); if (size & kBundleMask) return NaClValidationFailed; if (ValidateChunkAMD64(data_new, size, CALL_USER_CALLBACK_ON_EACH_INSTRUCTION, cpu_features, ProcessCodeReplacementInstruction, (void *)(data_existing - data_new))) return NaClValidationSucceeded; if (errno == ENOMEM) return NaClValidationFailedOutOfMemory; return NaClValidationFailed; }
static NaClValidationStatus ValidatorCodeCopy_x86_64( uintptr_t guest_addr, uint8_t *data_existing, uint8_t *data_new, size_t size, const NaClCPUFeatures *f, NaClCopyInstructionFunc copy_func) { /* TODO(jfb) Use a safe cast here. */ NaClCPUFeaturesX86 *cpu_features = (NaClCPUFeaturesX86 *) f; struct CodeCopyCallbackData callback_data; UNREFERENCED_PARAMETER(guest_addr); if (size & kBundleMask) return NaClValidationFailed; callback_data.copy_func = copy_func; callback_data.existing_minus_new = data_existing - data_new; if (ValidateChunkAMD64(data_new, size, CALL_USER_CALLBACK_ON_EACH_INSTRUCTION, cpu_features, NaClDfaProcessCodeCopyInstruction, &callback_data)) return NaClValidationSucceeded; if (errno == ENOMEM) return NaClValidationFailedOutOfMemory; return NaClValidationFailed; }
static NaClValidationStatus ApplyDfaValidator_x86_64( uintptr_t guest_addr, uint8_t *data, size_t size, int stubout_mode, uint32_t flags, int readonly_text, const NaClCPUFeatures *f, const struct NaClValidationMetadata *metadata, struct NaClValidationCache *cache) { /* TODO(jfb) Use a safe cast here. */ NaClCPUFeaturesX86 *cpu_features = (NaClCPUFeaturesX86 *) f; enum NaClValidationStatus status = NaClValidationFailed; void *query = NULL; struct StubOutCallbackData callback_data; callback_data.flags = flags; callback_data.did_rewrite = 0; UNREFERENCED_PARAMETER(guest_addr); if (stubout_mode) return NaClValidationFailedNotImplemented; if (!NaClArchSupportedX86(cpu_features)) return NaClValidationFailedCpuNotSupported; if (size & kBundleMask) return NaClValidationFailed; /* * If the validation caching interface is available and it would be * inexpensive to do so, perform a query. */ if (cache != NULL && NaClCachingIsInexpensive(cache, metadata)) query = cache->CreateQuery(cache->handle); if (query != NULL) { const char validator_id[] = "x86-64 dfa"; cache->AddData(query, (uint8_t *) validator_id, sizeof(validator_id)); cache->AddData(query, (uint8_t *) cpu_features, sizeof(*cpu_features)); NaClAddCodeIdentity(data, size, metadata, cache, query); if (cache->QueryKnownToValidate(query)) { cache->DestroyQuery(query); return NaClValidationSucceeded; } } if (readonly_text) { if (ValidateChunkAMD64(data, size, 0 /*options*/, cpu_features, NaClDfaProcessValidationError, NULL)) status = NaClValidationSucceeded; } else { if (ValidateChunkAMD64(data, size, 0 /*options*/, cpu_features, NaClDfaStubOutUnsupportedInstruction, &callback_data)) status = NaClValidationSucceeded; } if (status != NaClValidationSucceeded && errno == ENOMEM) status = NaClValidationFailedOutOfMemory; /* Cache the result if validation succeeded and the code was not modified. */ if (query != NULL) { if (status == NaClValidationSucceeded && callback_data.did_rewrite == 0) cache->SetKnownToValidate(query); cache->DestroyQuery(query); } return status; }
int ValidateFile(const char *filename, int repeat_count) { size_t data_size; uint8_t *data; ReadFile(filename, &data, &data_size); int count; if (data[4] == 1) { for (count = 0; count < repeat_count; ++count) { Elf32_Ehdr *header; int index; header = (Elf32_Ehdr *) data; CheckBounds(data, data_size, header, sizeof(*header)); assert(memcmp(header->e_ident, ELFMAG, strlen(ELFMAG)) == 0); for (index = 0; index < header->e_shnum; ++index) { Elf32_Shdr *section = (Elf32_Shdr *) (data + header->e_shoff + header->e_shentsize * index); CheckBounds(data, data_size, section, sizeof(*section)); if ((section->sh_flags & SHF_EXECINSTR) != 0) { struct ValidateState state; state.offset = data + section->sh_offset - section->sh_addr; if (section->sh_size <= 0xfff) { state.width = 4; } else if (section->sh_size <= 0xfffffff) { state.width = 8; } else { state.width = 12; } CheckBounds(data, data_size, data + section->sh_offset, section->sh_size); int res = ValidateChunkIA32(data + section->sh_offset, section->sh_size, ProcessError, &state); if (res != 0) { return res; } } } } } else if (data[4] == 2) { for (count = 0; count < repeat_count; ++count) { Elf64_Ehdr *header; int index; header = (Elf64_Ehdr *) data; CheckBounds(data, data_size, header, sizeof(*header)); assert(memcmp(header->e_ident, ELFMAG, strlen(ELFMAG)) == 0); for (index = 0; index < header->e_shnum; ++index) { Elf64_Shdr *section = (Elf64_Shdr *) (data + header->e_shoff + header->e_shentsize * index); CheckBounds(data, data_size, section, sizeof(*section)); if ((section->sh_flags & SHF_EXECINSTR) != 0) { struct ValidateState state; state.offset = data + section->sh_offset - section->sh_addr; if (section->sh_size <= 0xfff) { state.width = 4; } else if (section->sh_size <= 0xfffffff) { state.width = 8; } else if (section->sh_size <= 0xfffffffffffLL) { state.width = 12; } else { state.width = 16; } CheckBounds(data, data_size, data + section->sh_offset, section->sh_size); int res = ValidateChunkAMD64(data + section->sh_offset, section->sh_size, ProcessError, &state); if (res != 0) { return res; } } } } } else { printf("Unknown ELF class: %s\n", filename); exit(1); } return 0; }