/* Check that we can rewrite instruction that crosses align boundaries. */
void test_replacing_code_slowpaths(void) {
  uint8_t *load_area = allocate_code_space(1);
  uint8_t buf[NACL_BUNDLE_SIZE];
  size_t size;
  int rc;
  /* Offsets to copy an instruction to. */
  int off1, off2, off3;

  fill_nops(buf, sizeof(buf));
  size = (size_t) (&template_instr_end - &template_instr);
  assert(size <= 5);
  off1 = 4 - size + 1; /* Cross 4 byte boundary */
  off2 = 24 - size + 1; /* Cross 8 byte boundary */
  off3 = 16 - size + 1; /* Cross 16 byte boundary */
  memcpy(buf + off1, &template_instr, size);
  memcpy(buf + off2, &template_instr, size);
  memcpy(buf + off3, &template_instr, size);
  rc = nacl_dyncode_create(load_area, buf, sizeof(buf));
  assert(rc == 0);

  memcpy(buf + off1, &template_instr_replace, size);
  rc = nacl_dyncode_modify(load_area + off1, buf + off1, size);
  assert(rc == 0);
  assert(memcmp(buf + off1, load_area + off1, size) == 0);

  memcpy(buf + off2, &template_instr_replace, size);
  rc = nacl_dyncode_modify(load_area + off2, buf + off2, size);
  assert(rc == 0);
  assert(memcmp(buf + off2, load_area + off2, size) == 0);

  memcpy(buf + off3, &template_instr_replace, size);
  rc = nacl_dyncode_modify(load_area + off3, buf + off3, size);
  assert(rc == 0);
  assert(memcmp(buf + off3, load_area + off3, size) == 0);
}
void test_end_of_code_region() {
  int rc;
  void *dest;
  uint8_t data[32];
  fill_nops(data, sizeof(data));

  /* This tries to load into the data segment, which is definitely not
     allowed. */
  dest = (uint8_t *) DYNAMIC_CODE_SEGMENT_END;
  rc = nacl_load_code(dest, data, sizeof(data));
  assert(rc == -EFAULT);

  /* This tries to load into the last bundle of the code region, which
     sel_ldr disallows just in case there is some CPU bug in which the
     CPU fails to check for running off the end of an x86 code
     segment.  This is applied to other architectures for
     consistency. */
  dest = (uint8_t *) DYNAMIC_CODE_SEGMENT_END - sizeof(data);
  rc = nacl_load_code(dest, data, sizeof(data));
  assert(rc == -EFAULT);

  dest = (uint8_t *) DYNAMIC_CODE_SEGMENT_END - sizeof(data) * 2;
  rc = nacl_load_code(dest, data, sizeof(data));
  assert(rc == 0);
}
Ejemplo n.º 3
0
void copy_and_pad_fragment(void *dest,
                           size_t dest_size,
                           const char *frag,
                           size_t frag_size) {
  assert(dest_size % NACL_BUNDLE_SIZE == 0);
  assert(frag_size <= dest_size);
  fill_nops(dest, dest_size);
  memcpy(dest, frag, frag_size);
}
/*
 * Getting the assembler to pad our code fragments in templates.S is
 * awkward because we have to output them in data mode, in which the
 * assembler wants to output zeroes instead of NOPs for padding.
 */
void copy_and_pad_fragment(void *dest,
                           int dest_size,
                           const char *fragment_start,
                           const char *fragment_end) {
  int fragment_size = fragment_end - fragment_start;
  assert(dest_size % 32 == 0);
  assert(fragment_size <= dest_size);
  fill_nops(dest, dest_size);
  memcpy(dest, fragment_start, fragment_size);
}
/* Since there is an interaction with page size, we also test loading
   a multi-page chunk of code. */
void test_loading_large_chunk() {
  char *load_area = allocate_code_space(2);
  int size = 0x20000;
  uint8_t *data = alloca(size);
  int rc;

  fill_nops(data, size);
  rc = nacl_load_code(load_area, data, size);
  assert(rc == 0);
  assert(memcmp(load_area, data, size) == 0);
}
void test_hlt_filled_bundle() {
  uint8_t bad_code[NUM_BUNDLES_FOR_HLT * NACL_BUNDLE_SIZE];
  void *load_area;
  int ix;

  for (ix = 0; ix < NUM_BUNDLES_FOR_HLT; ++ix) {
    fill_nops(bad_code, sizeof bad_code);
    fill_hlts(bad_code + ix * NACL_BUNDLE_SIZE, NACL_BUNDLE_SIZE);

    load_area = allocate_code_space(1);
    /* hlts are now allowed */
    assert(0 == nacl_load_code(load_area, bad_code, sizeof bad_code));
    /* but not twice... */
    assert(0 != nacl_load_code(load_area, bad_code, sizeof bad_code));
  }
}
/*
 * Check that regions surrounding the region we load code into are
 * correctly filled with halt instructions.  Loading code causes the
 * pages to become allocated, and unused parts of these pages should
 * be filled with halts.
 */
void test_demand_alloc_surrounding_hlt_filling(void) {
  int pad_size = 0x4000; /* This must be less than one 64k page. */
  int code_size = 0x28000;
  int total_size = pad_size * 2 + code_size;
  assert(total_size % DYNAMIC_CODE_PAGE_SIZE == 0);
  char *load_area = allocate_code_space(total_size / DYNAMIC_CODE_PAGE_SIZE);
  uint8_t *data = alloca(code_size);
  int rc;

  fill_nops(data, code_size);
  rc = nacl_load_code(load_area + pad_size, data, code_size);
  assert(rc == 0);
  check_region_is_filled_with_hlts(load_area, pad_size);
  assert(memcmp(load_area + pad_size, data, code_size) == 0);
  check_region_is_filled_with_hlts(load_area + pad_size + code_size, pad_size);
}
/*
 * Check that dyncode_create() works on a set of pages when a strict
 * subset of those pages were allocated by a previous dyncode_create()
 * call.  This provides some coverage of the coalescing of mprotect()
 * calls that dyncode_create() does.
 */
void test_demand_alloc_of_fragmented_pages(void) {
  int smaller_size = 2 * DYNAMIC_CODE_PAGE_SIZE;
  int smaller_size_load_offset = 2 * DYNAMIC_CODE_PAGE_SIZE;
  int larger_size = 6 * DYNAMIC_CODE_PAGE_SIZE;
  char *load_area = allocate_code_space(6);
  uint8_t *data = alloca(larger_size);
  int rc;

  fill_nops(data, larger_size);

  /* Cause pages 2 and 3 to be allocated. */
  rc = nacl_load_code(load_area + smaller_size_load_offset, data, smaller_size);
  assert(rc == 0);

  rc = dyncode_delete_with_retry(load_area + smaller_size_load_offset,
                                 smaller_size);
  assert(rc == 0);

  /* Cause pages 0, 1, 4 and 5 to be allocated as well. */
  rc = nacl_load_code(load_area, data, larger_size);
  assert(rc == 0);
}
void test_fail_on_non_bundle_aligned_dest_addresses() {
  char *load_area = allocate_code_space(1);
  int rc;
  uint8_t nops[32];

  fill_nops(nops, sizeof(nops));

  /* Test unaligned destination. */
  rc = nacl_load_code(load_area + 1, nops, 32);
  assert(rc == -EINVAL);
  rc = nacl_load_code(load_area + 4, nops, 32);
  assert(rc == -EINVAL);

  /* Test unaligned size. */
  rc = nacl_load_code(load_area, nops + 1, 31);
  assert(rc == -EINVAL);
  rc = nacl_load_code(load_area, nops + 4, 28);
  assert(rc == -EINVAL);

  /* Check that the code we're trying works otherwise. */
  rc = nacl_load_code(load_area, nops, 32);
  assert(rc == 0);
}