Exemplo n.º 1
0
int32_t NaClSysDyncodeCreate(struct NaClAppThread *natp,
                             uint32_t             dest,
                             uint32_t             src,
                             uint32_t             size) {
  struct NaClApp              *nap = natp->nap;
  uintptr_t                   src_addr;
  uint8_t                     *code_copy;
  int32_t                     retval = -NACL_ABI_EINVAL;

  if (!nap->enable_dyncode_syscalls) {
    NaClLog(LOG_WARNING,
            "NaClSysDyncodeCreate: Dynamic code syscalls are disabled\n");
    return -NACL_ABI_ENOSYS;
  }

  src_addr = NaClUserToSysAddrRange(nap, src, size);
  if (kNaClBadAddress == src_addr) {
    NaClLog(1, "NaClSysDyncodeCreate: Source address out of range\n");
    return -NACL_ABI_EFAULT;
  }

  /*
   * Make a private copy of the code, so that we can validate it
   * without a TOCTTOU race condition.
   */
  code_copy = malloc(size);
  if (NULL == code_copy) {
    return -NACL_ABI_ENOMEM;
  }
  memcpy(code_copy, (uint8_t*) src_addr, size);

  /* Unknown data source, no metadata. */
  retval = NaClTextDyncodeCreate(nap, dest, code_copy, size, NULL);

  free(code_copy);
  return retval;
}
Exemplo n.º 2
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);
      }
    }
  }
Exemplo n.º 3
0
NaClErrorCode NaClElfImageLoadDynamically(struct NaClElfImage *image,
                                          struct NaClApp      *nap,
                                          struct Gio          *gfile) {
  int segnum;
  for (segnum = 0; segnum < image->ehdr.e_phnum; ++segnum) {
    const Elf_Phdr *php = &image->phdrs[segnum];
    int32_t result;

    /*
     * 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 NaClCommonSysMmapIntern().
     */
    if (PT_LOAD != php->p_type) {
      continue;
    }

    /*
     * Ideally, Gio would have a Pread() method which we would use
     * instead of Seek().  In practice, though, there is no
     * Seek()/Read() race condition here because both
     * GioMemoryFileSnapshot and NaClGioShm use a seek position that
     * is local and not shared between processes.
     */
    if ((*gfile->vtbl->Seek)(gfile, (off_t) php->p_offset,
                             SEEK_SET) == (off_t) -1) {
      NaClLog(1, "NaClElfImageLoadDynamically: seek failed\n");
      return LOAD_READ_ERROR;
    }

    if (0 != (php->p_flags & PF_X)) {
      /* Load code segment. */
      /*
       * We make a copy of the code.  This is not ideal given that
       * GioMemoryFileSnapshot and NaClGioShm already have a copy of
       * the file in memory or mmapped.
       * TODO(mseaborn): Reduce the amount of copying here.
       */
      char *code_copy = malloc(php->p_filesz);
      if (NULL == code_copy) {
        NaClLog(1, "NaClElfImageLoadDynamically: malloc failed\n");
        return LOAD_NO_MEMORY;
      }
      if ((Elf_Word) (*gfile->vtbl->Read)(gfile, code_copy, php->p_filesz)
          != php->p_filesz) {
        free(code_copy);
        NaClLog(1, "NaClElfImageLoadDynamically: "
                "failed to read code segment\n");
        return LOAD_READ_ERROR;
      }
      result = NaClTextDyncodeCreate(nap, (uint32_t) php->p_vaddr,
                                     code_copy, (uint32_t) php->p_filesz);
      free(code_copy);
      if (0 != result) {
        NaClLog(1, "NaClElfImageLoadDynamically: "
                "failed to load code segment\n");
        return LOAD_UNLOADABLE;
      }
    } else {
      /* Load data segment. */
      void *paddr = (void *) NaClUserToSys(nap, php->p_vaddr);
      size_t mapping_size = NaClRoundAllocPage(php->p_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 = NaClCommonSysMmapIntern(
          nap, (void *) php->p_vaddr, mapping_size,
          NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
          NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE,
          -1, 0);
      if ((int32_t) php->p_vaddr != result) {
        NaClLog(1, "NaClElfImageLoadDynamically: failed to map data segment\n");
        return LOAD_UNLOADABLE;
      }
      if ((Elf_Word) (*gfile->vtbl->Read)(gfile, paddr, php->p_filesz)
          != php->p_filesz) {
        NaClLog(1, "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 = NaCl_mprotect(paddr, mapping_size, NACL_ABI_PROT_READ);
        if (0 != rc) {
          NaClLog(1, "NaClElfImageLoadDynamically: "
                  "failed to mprotect read-only data segment\n");
          return LOAD_MPROTECT_FAIL;
        }

        NaClVmmapUpdate(&nap->mem_map,
                        php->p_vaddr >> NACL_PAGESHIFT,
                        mapping_size >> NACL_PAGESHIFT,
                        PROT_READ,
                        NULL,
                        0  /* remove: false */);
      }
    }
  }