示例#1
0
int main(int argc, char **argv) {
  struct NaClApp app;
  uint32_t mmap_addr;
  char arg_string[32];
  char *args[] = {"prog_name", arg_string};

  NaClAllModulesInit();

  if (argc != 2) {
    NaClLog(LOG_FATAL, "Expected 1 argument: executable filename\n");
  }

  NaClAddSyscall(NACL_sys_test_syscall_1, TestSyscall);

  CHECK(NaClAppCtor(&app));
  CHECK(NaClAppLoadFileFromFilename(&app, argv[1]) == LOAD_OK);
  NaClAppInitialDescriptorHookup(&app);
  CHECK(NaClAppPrepareToLaunch(&app) == LOAD_OK);

  NaClSignalHandlerInit();
  NaClSignalHandlerSet(TrapSignalHandler);

  /*
   * Allocate some space in untrusted address space.  We pass the
   * address to the guest program so that it can write a register
   * snapshot for us to compare against.
   */
  mmap_addr = NaClSysMmapIntern(
      &app, NULL, sizeof(*g_test_shm),
      NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
      NACL_ABI_MAP_PRIVATE | NACL_ABI_MAP_ANONYMOUS, -1, 0);
  g_test_shm = (struct RegsTestShm *) NaClUserToSys(&app, mmap_addr);
  SNPRINTF(arg_string, sizeof(arg_string), "0x%x", (unsigned int) mmap_addr);

  CHECK(NaClCreateMainThread(&app, 2, args, NULL));
  CHECK(NaClWaitForMainThreadToExit(&app) == 0);

  CHECK(!g_in_untrusted_code);
  ASSERT_EQ(g_context_switch_count,
            (kNumberOfCallsToTest + kFastPathSyscallsToTest - 1) * 2);

  /*
   * Avoid calling exit() because it runs process-global destructors
   * which might break code that is running in our unjoined threads.
   */
  NaClExit(0);
  return 0;
}
struct NaClSignalContext *StartGuestWithSharedMemory(
    struct NaClApp *nap) {
  char arg_string[32];
  char *args[] = {"prog_name", arg_string};
  uint32_t mmap_addr;
  struct NaClSignalContext *expected_regs;

  /*
   * Allocate some space in untrusted address space.  We pass the
   * address to the guest program so that we can share data with it.
   */
  mmap_addr = NaClSysMmapIntern(
      nap, NULL, sizeof(*expected_regs),
      NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
      NACL_ABI_MAP_PRIVATE | NACL_ABI_MAP_ANONYMOUS,
      -1, 0);
  SNPRINTF(arg_string, sizeof(arg_string), "0x%x", (unsigned int) mmap_addr);
  expected_regs = (struct NaClSignalContext *) NaClUserToSys(nap, mmap_addr);

  WaitForThreadToExitFully(nap);

  CHECK(NaClCreateMainThread(nap, NACL_ARRAY_SIZE(args), args, NULL));
  return expected_regs;
}
示例#3
0
NaClErrorCode NaClElfImageLoadDynamically(
    struct NaClElfImage *image,
    struct NaClApp *nap,
    struct NaClDesc *ndp,
    struct NaClValidationMetadata *metadata) {
  ssize_t read_ret;
  int segnum;
  for (segnum = 0; segnum < image->ehdr.e_phnum; ++segnum) {
    const Elf_Phdr *php = &image->phdrs[segnum];
    Elf_Addr vaddr = php->p_vaddr & ~(NACL_MAP_PAGESIZE - 1);
    Elf_Off offset = php->p_offset & ~(NACL_MAP_PAGESIZE - 1);
    Elf_Off filesz = php->p_offset + php->p_filesz - offset;
    Elf_Off memsz = php->p_offset + php->p_memsz - offset;
    int32_t result;

    /*
     * By checking if filesz is larger than memsz, we no longer run the risk of
     * a malicious ELF object overrunning into the trusted address space when
     * reading data of size "filez" into a buffer of size "memsz".
     */
    if (filesz > memsz) {
      return LOAD_UNLOADABLE;
    }

    /*
     * We check for PT_LOAD directly rather than using the "loadable"
     * array because we are not using NaClElfImageValidateProgramHeaders()
     * to fill out the "loadable" array for this ELF object.  This ELF
     * object does not have to fit such strict constraints (such as
     * having code at 0x20000), and safety checks are applied by
     * NaClTextDyncodeCreate() and NaClSysMmapIntern().
     */
    if (PT_LOAD != php->p_type) {
      continue;
    }

    if (0 != (php->p_flags & PF_X)) {
      /* Load code segment. */
      /*
       * We make a copy of the code.  This is not ideal given that this
       * code path is used only for loading the IRT, and we could assume
       * that the contents of the irt.nexe file will not change underneath
       * us.  We should be able to mmap() the IRT's code segment instead of
       * copying it.
       * TODO(mseaborn): Reduce the amount of copying here.
       */
      char *code_copy = malloc(filesz);
      if (NULL == code_copy) {
        NaClLog(LOG_ERROR, "NaClElfImageLoadDynamically: malloc failed\n");
        return LOAD_NO_MEMORY;
      }
      read_ret = (*NACL_VTBL(NaClDesc, ndp)->
                  PRead)(ndp, code_copy, filesz, (nacl_off64_t) offset);
      if (NaClSSizeIsNegErrno(&read_ret) ||
          (size_t) read_ret != filesz) {
        free(code_copy);
        NaClLog(LOG_ERROR, "NaClElfImageLoadDynamically: "
                "failed to read code segment\n");
        return LOAD_READ_ERROR;
      }
      if (NULL != metadata) {
        metadata->code_offset = offset;
      }
      result = NaClTextDyncodeCreate(nap, (uint32_t) vaddr,
                                     code_copy, (uint32_t) filesz, metadata);
      free(code_copy);
      if (0 != result) {
        NaClLog(LOG_ERROR, "NaClElfImageLoadDynamically: "
                "failed to load code segment\n");
        return LOAD_UNLOADABLE;
      }
    } else {
      /* Load data segment. */
      void *paddr = (void *) NaClUserToSys(nap, vaddr);
      size_t mapping_size = NaClRoundAllocPage(memsz);
      /*
       * Note that we do not used NACL_ABI_MAP_FIXED because we do not
       * want to silently overwrite any existing mappings, such as the
       * user app's data segment or the stack.  We detect overmapping
       * when mmap chooses not to use the preferred address we supply.
       * (Ideally mmap would provide a MAP_EXCL option for this
       * instead.)
       */
      result = NaClSysMmapIntern(
          nap, (void *) (uintptr_t) vaddr, mapping_size,
          NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
          NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE,
          -1, 0);
      if ((int32_t) vaddr != result) {
        NaClLog(LOG_ERROR, "NaClElfImageLoadDynamically: "
                "failed to map data segment\n");
        return LOAD_UNLOADABLE;
      }
      read_ret = (*NACL_VTBL(NaClDesc, ndp)->
                  PRead)(ndp, paddr, filesz, (nacl_off64_t) offset);
      if (NaClSSizeIsNegErrno(&read_ret) ||
          (size_t) read_ret != filesz) {
        NaClLog(LOG_ERROR, "NaClElfImageLoadDynamically: "
                "failed to read data segment\n");
        return LOAD_READ_ERROR;
      }
      /*
       * Note that we do not need to zero the BSS (the region from
       * p_filesz to p_memsz) because it should already be zero
       * filled.  This would not be the case if we were mapping the
       * data segment from the file.
       */

      if (0 == (php->p_flags & PF_W)) {
        /* Handle read-only data segment. */
        int rc = NaClMprotect(paddr, mapping_size, NACL_ABI_PROT_READ);
        if (0 != rc) {
          NaClLog(LOG_ERROR, "NaClElfImageLoadDynamically: "
                  "failed to mprotect read-only data segment\n");
          return LOAD_MPROTECT_FAIL;
        }

        NaClVmmapAddWithOverwrite(&nap->mem_map,
                                  vaddr >> NACL_PAGESHIFT,
                                  mapping_size >> NACL_PAGESHIFT,
                                  NACL_ABI_PROT_READ,
                                  NACL_ABI_MAP_PRIVATE,
                                  NULL,
                                  0,
                                  0);
      }
    }
  }
示例#4
0
int main(int argc, char **argv) {
    char *nacl_file;
    struct NaClApp state;
    struct NaClApp *nap = &state;
    struct NaClAppThread nat, *natp = &nat;
    int errcode;
    uint32_t initial_addr;
    uint32_t addr;
    struct NaClVmmap *mem_map;
    struct NaClVmmapEntry *ent;
    char *nacl_verbosity = getenv("NACLVERBOSITY");

    NaClHandleBootstrapArgs(&argc, &argv);

    if (argc < 2) {
        printf("No nexe file!\n\nFAIL\n");
    }
    nacl_file = argv[1];

    NaClAllModulesInit();

    NaClLogSetVerbosity((NULL == nacl_verbosity)
                        ? 0
                        : strtol(nacl_verbosity, (char **) 0, 0));

    errcode = NaClAppCtor(&state);
    ASSERT_NE(errcode, 0);
    errcode = NaClAppLoadFileFromFilename(nap, nacl_file);
    ASSERT_EQ(errcode, LOAD_OK);

    InitThread(&state, natp);

    /*
     * Initial mappings:
     * 0. --  Zero page
     * 1. rx  Static code segment
     * 2. r   Read-only data segment
     * 3. rw  Writable data segment
     * 4. rw  Stack
     * There is no dynamic code area in this case.
     */
    /* Check the initial mappings. */
    mem_map = &state.mem_map;
    ASSERT_EQ(mem_map->nvalid, 5);
    CheckLowerMappings(mem_map);

    /* Allocate range */
    addr = NaClSysMmapIntern(nap, 0, 3 * NACL_MAP_PAGESIZE,
                             NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
                             NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE,
                             -1, 0);
    printf("addr=0x%"NACL_PRIx32"\n", addr);
    initial_addr = addr;
    /*
     * The mappings have changed to become:
     * 0. --  Zero page
     * 1. rx  Static code segment
     * 2. r   Read-only data segment
     * 3. rw  Writable data segment
     * 4. rw  mmap()'d anonymous, 3 pages (new)
     * 5. rw  Stack
     */

    /* Map to overwrite the start of the previously allocated range */
    addr = NaClSysMmapIntern(nap, (void *) (uintptr_t) initial_addr,
                             2 * NACL_MAP_PAGESIZE,
                             NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
                             NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE
                             | NACL_ABI_MAP_FIXED,
                             -1, 0);
    printf("addr=0x%"NACL_PRIx32"\n", addr);
    ASSERT_EQ(addr, initial_addr);
    /*
     * The mappings have changed to become:
     * 0. --  Zero page
     * 1. rx  Static code segment
     * 2. r   Read-only data segment
     * 3. rw  Writable data segment
     * 4. rw  mmap()'d anonymous, 2 pages (new)
     * 5. rw  mmap()'d anonymous, 1 pages (previous)
     * 6. rw  Stack
     */

    /* Allocate new page */
    addr = NaClSysMmapIntern(nap, 0, NACL_MAP_PAGESIZE,
                             NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
                             NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE,
                             -1, 0);
    printf("addr=0x%"NACL_PRIx32"\n", addr);
    /*
     * Our allocation strategy is to scan down from stack.  This is an
     * implementation detail and not part of the guaranteed semantics,
     * but it is good to test that what we expect of our implementation
     * didn't change.
     */
    ASSERT_EQ_MSG(addr, initial_addr - NACL_MAP_PAGESIZE,
                  "Allocation strategy changed!");
    /*
     * The mappings have changed to become:
     * 0. --  Zero page
     * 1. rx  Static code segment
     * 2. r   Read-only data segment
     * 3. rw  Writable data segment
     * 4. rw  mmap()'d anonymous, 1 pages (new)
     * 5. rw  mmap()'d anonymous, 2 pages
     * 6. rw  mmap()'d anonymous, 1 pages
     * 7. rw  Stack
     */

    NaClVmmapMakeSorted(mem_map);
    ASSERT_EQ(mem_map->nvalid, 8);
    CheckLowerMappings(mem_map);
    NaClVmmapDebug(mem_map, "After allocations");
    /* Skip mappings 0, 1, 2 and 3. */
    ASSERT_EQ(mem_map->vmentry[4]->page_num,
              (initial_addr - NACL_MAP_PAGESIZE) >> NACL_PAGESHIFT);
    ASSERT_EQ(mem_map->vmentry[4]->npages,
              NACL_PAGES_PER_MAP);

    ASSERT_EQ(mem_map->vmentry[5]->page_num,
              initial_addr >> NACL_PAGESHIFT);
    ASSERT_EQ(mem_map->vmentry[5]->npages,
              2 * NACL_PAGES_PER_MAP);

    ASSERT_EQ(mem_map->vmentry[6]->page_num,
              (initial_addr +  2 * NACL_MAP_PAGESIZE) >> NACL_PAGESHIFT);
    ASSERT_EQ(mem_map->vmentry[6]->npages,
              NACL_PAGES_PER_MAP);

    /*
     * Undo effects of previous mmaps
     */
    errcode = NaClSysMunmap(natp,
                            (void *) (uintptr_t) (initial_addr
                                    - NACL_MAP_PAGESIZE),
                            NACL_MAP_PAGESIZE * 4);
    ASSERT_EQ(errcode, 0);
    /*
     * Mappings return to being:
     * 0. --  Zero page
     * 1. rx  Static code segment
     * 2. r   Read-only data segment
     * 3. rw  Writable data segment
     * 4. rw  Stack
     */
    ASSERT_EQ(mem_map->nvalid, 5);
    CheckLowerMappings(mem_map);


    /* Allocate range */
    addr = NaClSysMmapIntern(nap, 0, 9 * NACL_MAP_PAGESIZE,
                             NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
                             NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE,
                             -1, 0);
    printf("addr=0x%"NACL_PRIx32"\n", addr);
    initial_addr = addr;
    /*
     * The mappings have changed to become:
     * 0. --  Zero page
     * 1. rx  Static code segment
     * 2. r   Read-only data segment
     * 3. rw  Writable data segment
     * 4. rw  mmap()'d anonymous, 9 pages (new)
     * 5. rw  Stack
     */

    /* Map into middle of previously allocated range */
    addr = NaClSysMmapIntern(nap,
                             (void *) (uintptr_t) (initial_addr
                                     + 2 * NACL_MAP_PAGESIZE),
                             3 * NACL_MAP_PAGESIZE,
                             NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
                             NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE
                             | NACL_ABI_MAP_FIXED,
                             -1, 0);
    printf("addr=0x%"NACL_PRIx32"\n", addr);
    ASSERT_EQ(addr, initial_addr + NACL_MAP_PAGESIZE * 2);
    /*
     * The mappings have changed to become:
     * 0. --  Zero page
     * 1. rx  Static code segment
     * 2. r   Read-only data segment
     * 3. rw  Writable data segment
     * 4. rw  mmap()'d anonymous, 2 pages (previous)
     * 5. rw  mmap()'d anonymous, 3 pages (new)
     * 6. rw  mmap()'d anonymous, 4 pages (previous)
     * 7. rw  Stack
     */

    NaClVmmapMakeSorted(mem_map);
    ASSERT_EQ(mem_map->nvalid, 8);
    CheckLowerMappings(mem_map);

    ASSERT_EQ(mem_map->vmentry[4]->page_num,
              initial_addr >> NACL_PAGESHIFT);
    ASSERT_EQ(mem_map->vmentry[4]->npages,
              2 * NACL_PAGES_PER_MAP);

    ASSERT_EQ(mem_map->vmentry[5]->page_num,
              (initial_addr + 2 * NACL_MAP_PAGESIZE) >> NACL_PAGESHIFT);
    ASSERT_EQ(mem_map->vmentry[5]->npages,
              3 * NACL_PAGES_PER_MAP);

    ASSERT_EQ(mem_map->vmentry[6]->page_num,
              (initial_addr + 5 * NACL_MAP_PAGESIZE) >> NACL_PAGESHIFT);
    ASSERT_EQ(mem_map->vmentry[6]->npages,
              4 * NACL_PAGES_PER_MAP);


    /* Change the memory protection of previously allocated range */
    errcode = NaClSysMprotectInternal(nap, (initial_addr
                                            + 1 * NACL_MAP_PAGESIZE),
                                      5 * NACL_MAP_PAGESIZE,
                                      NACL_ABI_PROT_READ);
    ASSERT_EQ(errcode, 0);
    /*
     * The mappings have changed to become:
     * 0. --  Zero page
     * 1. rx  Static code segment
     * 2. r   Read-only data segment
     * 3. rw  Writable data segment
     * 4. rw  mmap()'d anonymous, 1 pages (previous)
     * 5. r   mmap()'d anonymous, 1 pages (new)
     * 6. r   mmap()'d anonymous, 3 pages (new)
     * 7. r   mmap()'d anonymous, 1 pages (new)
     * 8. rw  mmap()'d anonymous, 3 pages (previous)
     * 9. rw  Stack
     */

    NaClVmmapMakeSorted(mem_map);
    ASSERT_EQ(mem_map->nvalid, 10);
    CheckLowerMappings(mem_map);

    ASSERT_EQ(mem_map->vmentry[4]->npages,
              1 * NACL_PAGES_PER_MAP);
    ASSERT_EQ(mem_map->vmentry[4]->prot,
              NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE);

    ASSERT_EQ(mem_map->vmentry[5]->npages,
              1 * NACL_PAGES_PER_MAP);
    ASSERT_EQ(mem_map->vmentry[5]->prot,
              NACL_ABI_PROT_READ);

    ASSERT_EQ(mem_map->vmentry[6]->npages,
              3 * NACL_PAGES_PER_MAP);
    ASSERT_EQ(mem_map->vmentry[6]->prot,
              NACL_ABI_PROT_READ);

    ASSERT_EQ(mem_map->vmentry[7]->npages,
              1 * NACL_PAGES_PER_MAP);
    ASSERT_EQ(mem_map->vmentry[7]->prot,
              NACL_ABI_PROT_READ);

    ASSERT_EQ(mem_map->vmentry[8]->npages,
              3 * NACL_PAGES_PER_MAP);
    ASSERT_EQ(mem_map->vmentry[8]->prot,
              NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE);


    /* Change the memory protection of previously allocated range */
    errcode = NaClSysMprotectInternal(nap, (initial_addr
                                            + 2 * NACL_MAP_PAGESIZE),
                                      3 * NACL_MAP_PAGESIZE,
                                      NACL_ABI_PROT_NONE);
    ASSERT_EQ(errcode, 0);
    /*
     * The mappings have changed to become:
     * 0. --  Zero page
     * 1. rx  Static code segment
     * 2. r   Read-only data segment
     * 3. rw  Writable data segment
     * 4. rw  mmap()'d anonymous, 1 pages (previous)
     * 5. r   mmap()'d anonymous, 1 pages (previous)
     * 6. --  mmap()'d anonymous, 3 pages (new)
     * 7. r   mmap()'d anonymous, 1 pages (previous)
     * 8. rw  mmap()'d anonymous, 3 pages (previous)
     * 9. rw  Stack
     */

    NaClVmmapMakeSorted(mem_map);
    ASSERT_EQ(mem_map->nvalid, 10);
    CheckLowerMappings(mem_map);

    ASSERT_EQ(mem_map->vmentry[4]->npages,
              1 * NACL_PAGES_PER_MAP);
    ASSERT_EQ(mem_map->vmentry[4]->prot,
              NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE);

    ASSERT_EQ(mem_map->vmentry[5]->npages,
              1 * NACL_PAGES_PER_MAP);
    ASSERT_EQ(mem_map->vmentry[5]->prot,
              NACL_ABI_PROT_READ);

    ASSERT_EQ(mem_map->vmentry[6]->npages,
              3 * NACL_PAGES_PER_MAP);
    ASSERT_EQ(mem_map->vmentry[6]->prot,
              NACL_ABI_PROT_NONE);

    ASSERT_EQ(mem_map->vmentry[7]->npages,
              1 * NACL_PAGES_PER_MAP);
    ASSERT_EQ(mem_map->vmentry[7]->prot,
              NACL_ABI_PROT_READ);

    ASSERT_EQ(mem_map->vmentry[8]->npages,
              3 * NACL_PAGES_PER_MAP);
    ASSERT_EQ(mem_map->vmentry[8]->prot,
              NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE);


    /*
     * Undo effects of previous mmaps
     */
    errcode = NaClSysMunmap(natp, (void *) (uintptr_t) initial_addr,
                            9 * NACL_MAP_PAGESIZE);
    ASSERT_EQ(errcode, 0);
    ASSERT_EQ(mem_map->nvalid, 5);
    CheckLowerMappings(mem_map);
    /*
     * Mappings return to being:
     * 0. --  Zero page
     * 1. rx  Static code segment
     * 2. r   Read-only data segment
     * 3. rw  Writable data segment
     * 4. rw  Stack
     */

    /*
     * Check use of hint.
     */
    addr = NaClSysMmapIntern(nap, (void *) (uintptr_t) initial_addr,
                             NACL_MAP_PAGESIZE,
                             NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
                             NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE,
                             -1, 0);
    ASSERT_LE(addr, 0xffff0000u);
    printf("addr=0x%"NACL_PRIx32"\n", addr);
    ASSERT_LE_MSG(initial_addr, addr, "returned address not at or above hint");
    errcode = NaClSysMunmap(natp, (void *) (uintptr_t) addr, NACL_MAP_PAGESIZE);
    ASSERT_EQ(errcode, 0);

    /* Check handling of zero-sized mappings. */
    addr = NaClSysMmapIntern(nap, 0, 0,
                             NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
                             NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE,
                             -1, 0);
    ASSERT_EQ((int) addr, -NACL_ABI_EINVAL);

    errcode = NaClSysMunmap(natp, (void *) (uintptr_t) initial_addr, 0);
    ASSERT_EQ(errcode, -NACL_ABI_EINVAL);

    /* Check changing the memory protection of neighbouring mmaps */
    addr = NaClSysMmapIntern(nap, 0, NACL_MAP_PAGESIZE,
                             NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
                             NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE,
                             -1, 0);
    printf("addr=0x%"NACL_PRIx32"\n", addr);
    initial_addr = addr;
    addr = NaClSysMmapIntern(nap, (void *) (uintptr_t) (initial_addr +
                             NACL_MAP_PAGESIZE),
                             NACL_MAP_PAGESIZE,
                             NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
                             NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE
                             | NACL_ABI_MAP_FIXED,
                             -1, 0);
    printf("addr=0x%"NACL_PRIx32"\n", addr);
    ASSERT_EQ(addr, initial_addr + NACL_MAP_PAGESIZE);

    errcode = NaClSysMprotectInternal(nap, initial_addr,
                                      2 * NACL_MAP_PAGESIZE,
                                      NACL_ABI_PROT_READ);
    ASSERT_EQ(errcode, 0);

    /* Undo effects of previous mmaps */
    errcode = NaClSysMunmap(natp, (void *) (uintptr_t) initial_addr,
                            2 * NACL_MAP_PAGESIZE);
    ASSERT_EQ(errcode, 0);

    /* Check that we cannot make the read-only data segment writable */
    ent = mem_map->vmentry[2];
    errcode = NaClSysMprotectInternal(nap, (uint32_t) (ent->page_num <<
                                      NACL_PAGESHIFT),
                                      ent->npages * NACL_MAP_PAGESIZE,
                                      NACL_ABI_PROT_WRITE);
    ASSERT_EQ(errcode, -NACL_ABI_EACCES);

#if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64
    CheckForGuardRegion(nap->mem_start - ((size_t) 40 << 30), (size_t) 40 << 30);
    CheckForGuardRegion(nap->mem_start + ((size_t) 4 << 30), (size_t) 40 << 30);
#endif

    NaClAddrSpaceFree(nap);

    printf("PASS\n");
    return 0;
}