示例#1
0
NaClErrorCode NaClAllocateSpace(void **mem, size_t addrsp_size) {
  int result;

  CHECK(NULL != mem);

  NaClAddrSpaceBeforeAlloc(addrsp_size);

#if NACL_LINUX
  /*
   * On 32 bit Linux, a 1 gigabyte block of address space may be reserved at
   * the zero-end of the address space during process creation, to address
   * sandbox layout requirements on ARM and performance issues on Intel ATOM.
   * Look for this prereserved block and if found, pass its address to the
   * page allocation function.
   */
  if (NaClFindPrereservedSandboxMemory(mem, addrsp_size)) {
    void *tmp_mem = (void *) NACL_TRAMPOLINE_START;
    CHECK(*mem == 0);
    addrsp_size -= NACL_TRAMPOLINE_START;
    result = NaCl_page_alloc_at_addr(&tmp_mem, addrsp_size);
  } else {
    /* Zero-based sandbox not prereserved. Attempt to allocate anyway. */
    result = NaCl_page_alloc(mem, addrsp_size);
  }
#elif NACL_WINDOWS
  /*
   * On 32 bit Windows, a 1 gigabyte block of address space is reserved before
   * starting up this process to make sure we can create the sandbox. Look for
   * this prereserved block and if found, pass its address to the page
   * allocation function.
   */
  if (0 == NaClFindPrereservedSandboxMemory(mem, addrsp_size)) {
    result = NaCl_page_alloc_at_addr(mem, addrsp_size);
  } else {
    result = NaCl_page_alloc(mem, addrsp_size);
  }
#else
  result = NaCl_page_alloc(mem, addrsp_size);
#endif

  if (0 != result) {
    NaClLog(2,
        "NaClAllocateSpace: NaCl_page_alloc 0x%08"NACL_PRIxPTR
        " failed\n",
        (uintptr_t) *mem);
    return LOAD_NO_MEMORY;
  }
  NaClLog(4, "NaClAllocateSpace: %"NACL_PRIxPTR", %"NACL_PRIxS"\n",
          (uintptr_t) *mem,
          addrsp_size);

  return LOAD_OK;
}
/* NOTE: This routine is almost identical to the x86_32 version.
 */
NaClErrorCode NaClAllocateSpaceAslr(void **mem, size_t addrsp_size,
                                    enum NaClAslrMode aslr_mode) {
  int result;
  void *tmp_mem = (void *) NACL_TRAMPOLINE_START;

  UNREFERENCED_PARAMETER(aslr_mode);
  CHECK(NULL != mem);

  /*
   * On ARM, we cheat slightly: we add two pages to the requested
   * allocation!  This accomodates the guard region we require at the
   * top end of untrusted memory.
   */
  addrsp_size += NACL_ADDRSPACE_UPPER_GUARD_SIZE;

  NaClAddrSpaceBeforeAlloc(addrsp_size);

  /*
   * On 32 bit Linux, a 1 gigabyte block of address space may be reserved at
   * the zero-end of the address space during process creation, to address
   * sandbox layout requirements on ARM and performance issues on Intel ATOM.
   * Look for this prereserved block and if found, pass its address to the
   * page allocation function.
   */
  if (!NaClFindPrereservedSandboxMemory(mem, addrsp_size)) {
    /* On ARM, we should always have prereserved sandbox memory. */
    NaClLog(LOG_ERROR, "NaClAllocateSpace:"
            " Could not find correct amount of prereserved memory"
            " (looked for 0x%016"NACL_PRIxS" bytes).\n",
            addrsp_size);
    return LOAD_NO_MEMORY;
  }
  /*
   * When creating a zero-based sandbox, we do not allocate the first 64K of
   * pages beneath the trampolines, because -- on Linux at least -- we cannot.
   * Instead, we allocate starting at the trampolines, and then coerce the
   * "mem" out parameter.
   */
  CHECK(*mem == NULL);
  addrsp_size -= NACL_TRAMPOLINE_START;
  result = NaCl_page_alloc_at_addr(&tmp_mem, addrsp_size);

  if (0 != result) {
    NaClLog(2,
            "NaClAllocateSpace: NaCl_page_alloc_at_addr 0x%08"NACL_PRIxPTR
            " failed\n",
            (uintptr_t) tmp_mem);
    return LOAD_NO_MEMORY;
  }
  NaClLog(4, "NaClAllocateSpace: %"NACL_PRIxPTR", %"NACL_PRIxS"\n",
          (uintptr_t) *mem,
          addrsp_size);

  return LOAD_OK;
}
NaClErrorCode NaClAllocateSpaceAslr(void **mem, size_t addrsp_size,
                                    enum NaClAslrMode aslr_mode) {
  /* 40G guard on each side */
  size_t        mem_sz = (NACL_ADDRSPACE_LOWER_GUARD_SIZE + FOURGIG +
                          NACL_ADDRSPACE_UPPER_GUARD_SIZE);
  size_t        log_align = ALIGN_BITS;
  void          *mem_ptr;
#if NACL_LINUX
  struct rlimit rlim;
#endif

  NaClLog(4, "NaClAllocateSpace(*, 0x%016"NACL_PRIxS" bytes).\n",
          addrsp_size);

  CHECK(addrsp_size == FOURGIG);

  if (NACL_X86_64_ZERO_BASED_SANDBOX) {
    mem_sz = 11 * FOURGIG;
    if (getenv("NACL_ENABLE_INSECURE_ZERO_BASED_SANDBOX") != NULL) {
      /*
       * For the zero-based 64-bit sandbox, we want to reserve 44GB of address
       * space: 4GB for the program plus 40GB of guard pages.  Due to a binutils
       * bug (see http://sourceware.org/bugzilla/show_bug.cgi?id=13400), the
       * amount of address space that the linker can pre-reserve is capped
       * at 4GB. For proper reservation, GNU ld version 2.22 or higher
       * needs to be used.
       *
       * Without the bug fix, trying to reserve 44GB will result in
       * pre-reserving the entire capped space of 4GB.  This tricks the run-time
       * into thinking that we can mmap up to 44GB.  This is unsafe as it can
       * overwrite the run-time program itself and/or other programs.
       *
       * For now, we allow a 4GB address space as a proof-of-concept insecure
       * sandboxing model.
       *
       * TODO(arbenson): remove this if block once the binutils bug is fixed
       */
      mem_sz = FOURGIG;
    }

    NaClAddrSpaceBeforeAlloc(mem_sz);
    if (NaClFindPrereservedSandboxMemory(mem, mem_sz)) {
      int result;
      void *tmp_mem = (void *) NACL_TRAMPOLINE_START;
      CHECK(*mem == 0);
      mem_sz -= NACL_TRAMPOLINE_START;
      result = NaClPageAllocAtAddr(&tmp_mem, mem_sz);
      if (0 != result) {
        NaClLog(2,
                "NaClAllocateSpace: NaClPageAlloc 0x%08"NACL_PRIxPTR
                " failed\n",
                (uintptr_t) *mem);
        return LOAD_NO_MEMORY;
      }
      NaClLog(4, "NaClAllocateSpace: %"NACL_PRIxPTR", %"NACL_PRIxS"\n",
              (uintptr_t) *mem,
              mem_sz);
      return LOAD_OK;
    }
    NaClLog(LOG_ERROR, "Failed to find prereserved memory\n");
    return LOAD_NO_MEMORY;
  }

  NaClAddrSpaceBeforeAlloc(mem_sz);

  errno = 0;
  mem_ptr = NaClAllocatePow2AlignedMemory(mem_sz, log_align, aslr_mode);
  if (NULL == mem_ptr) {
    if (0 != errno) {
      perror("NaClAllocatePow2AlignedMemory");
    }
    NaClLog(LOG_WARNING, "Memory allocation failed\n");
#if NACL_LINUX
    /*
     * Check with getrlimit whether RLIMIT_AS was likely to be the
     * problem with an allocation failure.  If so, generate a log
     * message.  Since this is a debugging aid and we don't know about
     * the memory requirement of the code that is embedding native
     * client, there is some slop.
     */
    if (0 != getrlimit(RLIMIT_AS, &rlim)) {
      perror("NaClAllocatePow2AlignedMemory::getrlimit");
    } else {
      if (rlim.rlim_cur < mem_sz) {
        /*
         * Developer hint/warning; this will show up in the crash log
         * and must be brief.
         */
        NaClLog(LOG_INFO,
                "Please run \"ulimit -v unlimited\" (bash)"
                " or \"limit vmemoryuse unlimited\" (tcsh)\n");
        NaClLog(LOG_INFO,
                "and restart the app.  NaCl requires at least %"NACL_PRIdS""
                " kilobytes of virtual\n",
                mem_sz / 1024);
        NaClLog(LOG_INFO,
                "address space. NB: Raising the hard limit requires"
                " root access.\n");
      }
    }
#elif NACL_OSX
    /*
     * In OSX, RLIMIT_AS and RLIMIT_RSS have the same value; i.e., OSX
     * conflates the notion of virtual address space used with the
     * resident set size.  In particular, the way NaCl uses virtual
     * address space is to allocate guard pages so that certain
     * addressing modes will not need to be explicitly masked; the
     * guard pages are allocated but inaccessible, never faulted so
     * not even zero-filled on demand, so they should not count
     * against the resident set -- which is supposed to be only the
     * frequently accessed pages in the first place.
     */
#endif

    return LOAD_NO_MEMORY;
  }
  /*
   * The module lives in the middle FOURGIG of the allocated region --
   * we skip over an initial 40G guard.
   */
  *mem = (void *) (((char *) mem_ptr) + NACL_ADDRSPACE_LOWER_GUARD_SIZE);
  NaClLog(4,
          "NaClAllocateSpace: addr space at 0x%016"NACL_PRIxPTR"\n",
          (uintptr_t) *mem);

  return LOAD_OK;
}