/*
 * mmap MAP_SHARED test
 *
 * Make sure two views of the same file see the changes made from one
 * view in the other.
 */
int map_shared_test(struct NaClHostDesc *d, void *test_specifics) {
  struct NaClDescEffector *null_eff = NaClDescEffectorTrustedMem();
  uintptr_t view1;
  uintptr_t view2;
  char *v1ptr;
  char *v2ptr;

  UNREFERENCED_PARAMETER(test_specifics);

  if ((uintptr_t) -4095 <
      (view1 = NaClHostDescMap(d,
                               null_eff,
                               NULL,
                               kNumFileBytes,
                               NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
                               NACL_ABI_MAP_SHARED,
                               /* offset */ 0))) {
    fprintf(stderr, "map_shared_test: view1 map failed, errno %d\n",
            -(int) view1);
    return 1;
  }

  if ((uintptr_t) -4095 <
      (view2 = NaClHostDescMap(d,
                               null_eff,
                               NULL,
                               kNumFileBytes,
                               NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
                               NACL_ABI_MAP_SHARED,
                               /* offset */ 0))) {
    fprintf(stderr, "map_shared_test: view2 map failed, errno %d\n",
            -(int) view2);
    return 1;
  }

  v1ptr = (char *) view1;
  v2ptr = (char *) view2;

  CHECK(v1ptr[0] == '\0');
  CHECK(v2ptr[0] == '\0');
  v1ptr[0] = 'x';
  CHECK(v2ptr[0] == 'x');
  v2ptr[0x400] = 'y';
  CHECK(v1ptr[0x400] == 'y');

  CHECK(0 == NaClHostDescUnmapUnsafe((void *) view1, kNumFileBytes));
  CHECK(0 == NaClHostDescUnmapUnsafe((void *) view2, kNumFileBytes));

  return 0;
}
int prot_exec_test(struct NaClHostDesc *d, void *test_specifics) {
  struct NaClDescEffector *null_eff = NaClDescEffectorTrustedMem();
  uintptr_t addr;
  int (*func)(int param);
  int param;
  int value;

  UNREFERENCED_PARAMETER(test_specifics);

  if ((uintptr_t) -4095 <
      (addr = NaClHostDescMap(d,
                              null_eff,
                              NULL,
                              kNumFileBytes,
                              NACL_ABI_PROT_READ | NACL_ABI_PROT_EXEC,
                              NACL_ABI_MAP_SHARED,
                              /* offset */ 0))) {
    fprintf(stderr, "prot_exec_test: map failed, errno %d\n", -(int) addr);
    return 1;
  }

  func = (int (*)(int)) addr;
  for (param = 0; param < 16; ++param) {
    printf("%d -> ", param);
    fflush(stdout);
    value = (*func)(param);
    printf("%d\n", value);
    CHECK(value == param+1);
  }

  CHECK(0 == NaClHostDescUnmapUnsafe((void *) addr, kNumFileBytes));

  return 0;
}
/* bool */
int TryToMap(struct NaClHostDesc *hd, size_t map_bytes, int prot, int flags,
             int expected_errno) {
  uintptr_t addr;

  addr = NaClHostDescMap(hd,
                         NaClDescEffectorTrustedMem(),
                         NULL,
                         map_bytes,
                         prot,
                         flags,
                         0);
  if (0 == expected_errno) {
    if ((uintptr_t) -4095 < addr) {
      NaClLog(LOG_ERROR, "NaClHostDescMap returned errno %d\n", -(int) addr);
      return 0;
    }
    CHECK(0 == NaClHostDescUnmapUnsafe((void *) addr, map_bytes));
    return 1;
  } else {
    if ((uintptr_t) -4095 < addr) {
      if (expected_errno != -(int) addr) {
        NaClLog(LOG_ERROR, "NaClHostDescMap returned errno %d, expected %d\n",
                -(int) addr, expected_errno);
      }
    } else {
      NaClLog(LOG_ERROR, "NaClHostDescMap succeeded, expected errno %d\n",
              expected_errno);
      CHECK(0 == NaClHostDescUnmapUnsafe((void *) addr, map_bytes));
    }
    return expected_errno == -(int) addr;
  }
}
Beispiel #4
0
static uintptr_t NaClDescIoDescMap(struct NaClDesc         *vself,
                                   struct NaClDescEffector *effp,
                                   void                    *start_addr,
                                   size_t                  len,
                                   int                     prot,
                                   int                     flags,
                                   nacl_off64_t            offset) {
  struct NaClDescIoDesc *self = (struct NaClDescIoDesc *) vself;
  uintptr_t             status;
  uintptr_t             addr;

  /*
   * prot must only contain NACL_ABI_PROT_* flags.
   */
  if (0 != (~(NACL_ABI_PROT_MASK) & prot)) {
    NaClLog(LOG_INFO,
            ("NaClDescIoDescMap: prot has other bits"
             " than NACL_ABI_PROT_{READ|WRITE|EXEC}\n"));
    return -NACL_ABI_EINVAL;
  }

  if (0 == (NACL_ABI_MAP_FIXED & flags)) {
    if (!NaClFindAddressSpace(&addr, len)) {
      NaClLog(1, "NaClDescIoDescMap: no address space?\n");
      return -NACL_ABI_ENOMEM;
    }
    NaClLog(4,
            "NaClDescIoDescMap: NaClFindAddressSpace"
            " returned 0x%"NACL_PRIxPTR"\n",
            addr);
    start_addr = (void *) addr;
  }
  flags |= NACL_ABI_MAP_FIXED;

  status = NaClHostDescMap((NULL == self) ? NULL : self->hd,
                           effp,
                           (void *) start_addr,
                           len,
                           prot,
                           flags,
                           offset);
  if (NACL_MAP_FAILED == (void *) status) {
    return -NACL_ABI_E_MOVE_ADDRESS_SPACE;
  }
  return (uintptr_t) start_addr;
}
/*
 * mmap MAP_PRIVATE test
 *
 * Make sure that a MAP_PRIVATE view initially sees the changes made
 * in a MAP_SHARED view, but after touching the private view further
 * changes become invisible.
 */
int map_private_test(struct NaClHostDesc *d, void *test_specifics) {
  struct MapPrivateSpecifics *params =
      (struct MapPrivateSpecifics *) test_specifics;
  struct NaClDescEffector *null_eff = NaClDescEffectorTrustedMem();
  uintptr_t view1;
  uintptr_t view2;
  nacl_off64_t off;
  ssize_t bytes_written;
  char *v1ptr;
  char *v2ptr;

  if ((uintptr_t) -4095 <
      (view1 = NaClHostDescMap(d,
                               null_eff,
                               NULL,
                               kNumFileBytes,
                               NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
                               NACL_ABI_MAP_SHARED,
                               /* offset */ 0))) {
    fprintf(stderr, "map_private_test: view1 map failed, errno %d\n",
            -(int) view1);
    return 1;
  }

  NaClLog(2, "map_private_test: view1 = 0x%"NACL_PRIxPTR"\n", view1);

  if ((uintptr_t) -4095 <
      (view2 = NaClHostDescMap(d,
                               null_eff,
                               NULL,
                               kNumFileBytes,
                               NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
                               NACL_ABI_MAP_PRIVATE,
                               /* offset */ 0))) {
    fprintf(stderr, "map_private_test: view2 map failed, errno %d\n",
            -(int) view2);
    return 1;
  }

  NaClLog(2, "map_private_test: view2 = 0x%"NACL_PRIxPTR"\n", view2);

  v1ptr = (char *) view1;
  v2ptr = (char *) view2;

  CHECK(v1ptr[0] == '\0');
  CHECK(v2ptr[0] == '\0');
  if (params->shm_not_write) {
    NaClLog(2, "map_private_test: changing via shm view\n");
    v1ptr[0] = 'x';  /* write through shared view */
  } else {
    NaClLog(2, "map_private_test: changing via write interface\n");
    off = NaClHostDescSeek(d, 0, 0);
    if (off < 0) {
      fprintf(stderr, "Could not seek: NaCl errno %d\n", (int) -off);
      return 1;
    }
    bytes_written = NaClHostDescWrite(d, "x", 1);
    if (1 != bytes_written) {
      fprintf(stderr, "Could not write: NaCl errno %d\n", (int) -bytes_written);
      return 1;
    }
  }
#if NACL_LINUX || NACL_WINDOWS
  /*
   * Most OSes have this behavior: a PRIVATE mapping is copy-on-write,
   * but the COW occurs when the fault occurs on that mapping, not
   * other mappings; otherwise, the page tables just point the system
   * to the buffer cache (or, if evicted, a stub entry that permits
   * faulting in the page).  So, a write through a writable file
   * descriptor or a SHARED mapping would modify the buffer cache, and
   * the PRIVATE mapping would see such changes until a fault occurs.
   */
  CHECK(v2ptr[0] == 'x');  /* visible! */
#elif NACL_OSX
  /*
   * On OSX, however, the underlying Mach primitives provide
   * bidirectional COW.
   */
  CHECK(v2ptr[0] == '\0');  /* NOT visible! */
#else
# error "Unsupported OS"
#endif

  v2ptr[0] = 'z';  /* COW fault */
  v1ptr[0] = 'y';
  CHECK(v2ptr[0] == 'z'); /* private! */

  CHECK(v1ptr[0x400] == '\0');
  v2ptr[0x400] = 'y';
  CHECK(v1ptr[0x400] == '\0');

  CHECK(0 == NaClHostDescUnmapUnsafe((void *) view1, kNumFileBytes));
  CHECK(0 == NaClHostDescUnmapUnsafe((void *) view2, kNumFileBytes));

  return 0;
}