/* * 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; } }
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; }