void NaClReplaceDescIfValidationCacheAssertsMappable(
    struct NaClDesc **desc_in_out,
    struct NaClValidationCache *validation_cache) {
  struct NaClDesc *desc = *desc_in_out;
  struct NaClDesc *replacement;
  struct NaClFileToken file_token;

  if (NACL_FI("validation_cache_replacement_bypass", 0, 1)) {
    NaClDescMarkSafeForMmap(desc);
  } else if (!NaClDescGetFileToken(desc, &file_token)) {
    NaClLog(4,
            "NaClReplaceDescIfValidationCacheAssertsMappable: no valid"
            " file token\n");
  } else {
    replacement = NaClExchangeFileTokenForMappableDesc(&file_token,
                                                       validation_cache);
    if (NULL != replacement) {
      NaClDescUnref(desc);
      *desc_in_out = replacement;
    }
  }
}
Пример #2
0
NaClErrorCode NaClElfImageLoad(struct NaClElfImage *image,
                               struct NaClDesc *ndp,
                               struct NaClApp *nap) {
  int segnum;
  uintptr_t vaddr;
  uintptr_t paddr;
  uintptr_t end_vaddr;
  ssize_t read_ret;
  int safe_for_mmap;

  for (segnum = 0; segnum < image->ehdr.e_phnum; ++segnum) {
    const Elf_Phdr *php = &image->phdrs[segnum];
    Elf_Off offset = (Elf_Off) NaClTruncAllocPage(php->p_offset);
    Elf_Off filesz = php->p_offset + php->p_filesz - offset;

    /* did we decide that we will load this segment earlier? */
    if (!image->loadable[segnum]) {
      continue;
    }

    NaClLog(2, "loading segment %d\n", segnum);

    if (0 == php->p_filesz) {
      NaClLog(4, "zero-sized segment.  ignoring...\n");
      continue;
    }

    end_vaddr = php->p_vaddr + php->p_filesz;
    /* integer overflow? */
    if (end_vaddr < php->p_vaddr) {
      NaClLog(LOG_FATAL, "parameter error should have been detected already\n");
    }
    /*
     * is the end virtual address within the NaCl application's
     * address space?  if it is, it implies that the start virtual
     * address is also.
     */
    if (end_vaddr >= ((uintptr_t) 1U << nap->addr_bits)) {
      NaClLog(LOG_FATAL, "parameter error should have been detected already\n");
    }

    vaddr = NaClTruncAllocPage(php->p_vaddr);
    paddr = NaClUserToSysAddr(nap, vaddr);
    CHECK(kNaClBadAddress != paddr);

    /*
     * Check NaClDescIsSafeForMmap(ndp) to see if it might be okay to
     * mmap.
     */
    NaClLog(4, "NaClElfImageLoad: checking descriptor mmap safety\n");
    safe_for_mmap = NaClDescIsSafeForMmap(ndp);
    if (safe_for_mmap) {
      NaClLog(4, "NaClElfImageLoad: safe-for-mmap\n");
    }

    if (!safe_for_mmap &&
        NACL_FI("ELF_LOAD_BYPASS_DESCRIPTOR_SAFETY_CHECK", 0, 1)) {
      NaClLog(LOG_WARNING, "WARNING: BYPASSING DESCRIPTOR SAFETY CHECK\n");
      safe_for_mmap = 1;
    }
    if (safe_for_mmap) {
      NaClErrorCode map_status;
      NaClLog(4, "NaClElfImageLoad: safe-for-mmap\n");
      map_status = NaClElfFileMapSegment(nap, ndp, php->p_flags,
                                         offset, filesz, vaddr, paddr);
      /*
       * NB: -Werror=switch-enum forces us to not use a switch.
       */
      if (LOAD_OK == map_status) {
        /* Segment has been handled -- proceed to next segment */
        continue;
      } else if (LOAD_STATUS_UNKNOWN != map_status) {
        /*
         * A real error!  Return it so that this can be reported to
         * the embedding code (via start_module status).
         */
        return map_status;
      }
      /* Fall through: pread-based fallback requested */
    }
    NaClLog(4,
            "PReading %"NACL_PRIdElf_Xword" (0x%"NACL_PRIxElf_Xword") bytes to"
            " address 0x%"NACL_PRIxPTR", position %"
            NACL_PRIdElf_Off" (0x%"NACL_PRIxElf_Off")\n",
            filesz, filesz,
            paddr,
            offset, offset);

    /*
     * Tell valgrind that this memory is accessible and undefined. For more
     * details see
     * http://code.google.com/p/nativeclient/wiki/ValgrindMemcheck#Implementation_details
     */
    NACL_MAKE_MEM_UNDEFINED((void *) paddr, filesz);

    read_ret = (*NACL_VTBL(NaClDesc, ndp)->
                PRead)(ndp, (void *) paddr, filesz, (nacl_off64_t) offset);
    if (NaClSSizeIsNegErrno(&read_ret) || (size_t) read_ret != filesz) {
      NaClLog(LOG_ERROR, "load failure segment %d", segnum);
      return LOAD_SEGMENT_BAD_PARAM;
    }
    /* region from p_filesz to p_memsz should already be zero filled */

    /* Tell Valgrind that we've mapped a segment of nacl_file. */
    NaClFileMappingForValgrind(paddr, filesz, offset);
  }

  return LOAD_OK;
}