Пример #1
0
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;
}
Пример #2
0
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;
}
Пример #3
0
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;
}
Пример #4
0
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;
}
Пример #5
0
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;
}