15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file.
45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "components/nacl/loader/nonsfi/elf_loader.h"
65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <elf.h>
85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <link.h>
95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <cstring>
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <string>
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <sys/mman.h>
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/logging.h"
155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/strings/string_number_conversions.h"
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "native_client/src/include/portability.h"
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "native_client/src/shared/platform/nacl_host_desc.h"
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "native_client/src/trusted/desc/nacl_desc_base.h"
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "native_client/src/trusted/desc/nacl_desc_effector_trusted_mem.h"
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "native_client/src/trusted/service_runtime/include/bits/mman.h"
215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Extracted from native_client/src/trusted/service_runtime/nacl_config.h.
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# if NACL_BUILD_SUBARCH == 64
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#  define NACL_ELF_E_MACHINE EM_X86_64
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# elif NACL_BUILD_SUBARCH == 32
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#  define NACL_ELF_E_MACHINE EM_386
285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# else
295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#  error Unknown platform.
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# endif
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_arm
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# define NACL_ELF_E_MACHINE EM_ARM
335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_mips
345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# define NACL_ELF_E_MACHINE EM_MIPS
355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#else
365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# error Unknown platform.
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace nacl {
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace nonsfi {
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace {
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Page size for non-SFI Mode.
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const ElfW(Addr) kNonSfiPageSize = 4096;
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)const ElfW(Addr) kNonSfiPageMask = kNonSfiPageSize - 1;
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)NaClErrorCode ValidateElfHeader(const ElfW(Ehdr)& ehdr) {
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (std::memcmp(ehdr.e_ident, ELFMAG, SELFMAG)) {
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "Bad elf magic";
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return LOAD_BAD_ELF_MAGIC;
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#if NACL_BUILD_SUBARCH == 32
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (ehdr.e_ident[EI_CLASS] != ELFCLASS32) {
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "Bad elf class";
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return LOAD_NOT_32_BIT;
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#elif NACL_BUILD_SUBARCH == 64
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (ehdr.e_ident[EI_CLASS] != ELFCLASS64) {
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "Bad elf class";
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return LOAD_NOT_64_BIT;
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#else
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)# error Unknown platform.
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#endif
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (ehdr.e_type != ET_DYN) {
685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "Not a relocatable ELF object (not ET_DYN)";
695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return LOAD_NOT_EXEC;
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (ehdr.e_machine != NACL_ELF_E_MACHINE) {
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "Bad machine: "
745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               << base::HexEncode(&ehdr.e_machine, sizeof(ehdr.e_machine));
755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return LOAD_BAD_MACHINE;
765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (ehdr.e_version != EV_CURRENT) {
795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "Bad elf version: "
805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               << base::HexEncode(&ehdr.e_version, sizeof(ehdr.e_version));
815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return LOAD_OK;
845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Returns the address of the page starting at address 'addr' for non-SFI mode.
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ElfW(Addr) GetPageStart(ElfW(Addr) addr) {
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return addr & ~kNonSfiPageMask;
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Returns the offset of address 'addr' in its memory page. In other words,
925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// this equals to 'addr' - GetPageStart(addr).
935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ElfW(Addr) GetPageOffset(ElfW(Addr) addr) {
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return addr & kNonSfiPageMask;
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Returns the address of the next page after address 'addr', unless 'addr' is
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// at the start of a page. This equals to:
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)//   addr == GetPageStart(addr) ? addr : GetPageStart(addr) + kNonSfiPageSize
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ElfW(Addr) GetPageEnd(ElfW(Addr) addr) {
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return GetPageStart(addr + kNonSfiPageSize - 1);
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Converts the pflags (in phdr) to mmap's prot flags.
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)int PFlagsToProt(int pflags) {
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return ((pflags & PF_X) ? PROT_EXEC : 0) |
1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)         ((pflags & PF_R) ? PROT_READ : 0) |
1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)         ((pflags & PF_W) ? PROT_WRITE : 0);
1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Converts the pflags (in phdr) to NaCl ABI's prot flags.
1125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)int PFlagsToNaClProt(int pflags) {
1135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return ((pflags & PF_X) ? NACL_ABI_PROT_EXEC : 0) |
1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)         ((pflags & PF_R) ? NACL_ABI_PROT_READ : 0) |
1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)         ((pflags & PF_W) ? NACL_ABI_PROT_WRITE : 0);
1165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Returns the load size for the given phdrs, or 0 on error.
1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ElfW(Addr) GetLoadSize(const ElfW(Phdr)* phdrs, int phnum) {
1205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ElfW(Addr) begin = ~static_cast<ElfW(Addr)>(0);
1215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ElfW(Addr) end = 0;
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (int i = 0; i < phnum; ++i) {
1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const ElfW(Phdr)& phdr = phdrs[i];
1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (phdr.p_type != PT_LOAD) {
1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // Do nothing for non PT_LOAD header.
1275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      continue;
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    begin = std::min(begin, phdr.p_vaddr);
1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    end = std::max(end, phdr.p_vaddr + phdr.p_memsz);
1325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (begin > end) {
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // The end address looks overflowing, or PT_LOAD is not found.
1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return 0;
1375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return GetPageEnd(end) - GetPageStart(begin);
1405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Reserves the memory for the given phdrs, and stores the memory bias to the
1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// load_bias.
1445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)NaClErrorCode ReserveMemory(const ElfW(Phdr)* phdrs,
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            int phnum,
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                            ElfW(Addr)* load_bias) {
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ElfW(Addr) size = GetLoadSize(phdrs, phnum);
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (size == 0) {
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "ReserveMemory failed to calculate size";
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return LOAD_UNLOADABLE;
1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Make sure that the given program headers represents PIE binary.
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (int i = 0; i < phnum; ++i) {
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (phdrs[i].p_type == PT_LOAD) {
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // Here, phdrs[i] is the first loadable segment.
1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (phdrs[i].p_vaddr != 0) {
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        // The binary is not PIE (i.e. needs to be loaded onto fixed addressed
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        // memory. We don't support such a case.
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        LOG(ERROR)
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            << "ReserveMemory: Non-PIE binary loading is not supported.";
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return LOAD_UNLOADABLE;
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      break;
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void* start = mmap(0, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (start == MAP_FAILED) {
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "ReserveMemory: failed to mmap.";
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return LOAD_NO_MEMORY;
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  *load_bias = reinterpret_cast<ElfW(Addr)>(start);
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return LOAD_OK;
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)NaClErrorCode LoadSegments(
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const ElfW(Phdr)* phdrs, int phnum, ElfW(Addr) load_bias,
1805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    struct NaClDesc* descriptor) {
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (int i = 0; i < phnum; ++i) {
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const ElfW(Phdr)& phdr = phdrs[i];
1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (phdr.p_type != PT_LOAD) {
1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      // Not a load target.
1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      continue;
1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Addresses on the memory.
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ElfW(Addr) seg_start = phdr.p_vaddr + load_bias;
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ElfW(Addr) seg_end = seg_start + phdr.p_memsz;
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ElfW(Addr) seg_page_start = GetPageStart(seg_start);
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ElfW(Addr) seg_page_end = GetPageEnd(seg_end);
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ElfW(Addr) seg_file_end = seg_start + phdr.p_filesz;
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Addresses on the file content.
1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ElfW(Addr) file_start = phdr.p_offset;
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ElfW(Addr) file_end = file_start + phdr.p_filesz;
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ElfW(Addr) file_page_start = GetPageStart(file_start);
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    uintptr_t seg_addr = (*NACL_VTBL(NaClDesc, descriptor)->Map)(
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        descriptor,
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        NaClDescEffectorTrustedMem(),
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        reinterpret_cast<void *>(seg_page_start),
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        file_end - file_page_start,
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        PFlagsToNaClProt(phdr.p_flags),
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        NACL_ABI_MAP_PRIVATE | NACL_ABI_MAP_FIXED,
2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        file_page_start);
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (NaClPtrIsNegErrno(&seg_addr)) {
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      LOG(ERROR) << "LoadSegments: [" << i << "] mmap failed, " << seg_addr;
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      return LOAD_NO_MEMORY;
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Handle the BSS: fill Zero between the segment end and the page boundary
2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // if necessary (i.e. if the segment doesn't end on a page boundary).
2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ElfW(Addr) seg_file_end_offset = GetPageOffset(seg_file_end);
2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if ((phdr.p_flags & PF_W) && seg_file_end_offset > 0) {
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      memset(reinterpret_cast<void *>(seg_file_end), 0,
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)             kNonSfiPageSize - seg_file_end_offset);
2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // Hereafter, seg_file_end is now the first page address after the file
2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // content. If seg_end is larger, we need to zero anything between them.
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    // This is done by using a private anonymous mmap for all extra pages.
2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    seg_file_end = GetPageEnd(seg_file_end);
2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (seg_page_end > seg_file_end) {
2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      void* zeromap = mmap(reinterpret_cast<void *>(seg_file_end),
2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           seg_page_end - seg_file_end,
2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           PFlagsToProt(phdr.p_flags),
2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE,
2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           -1, 0);
2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (zeromap == MAP_FAILED) {
2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        LOG(ERROR) << "LoadSegments: [" << i << "] Failed to zeromap.";
2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return LOAD_NO_MEMORY;
2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return LOAD_OK;
2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace
2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)struct ElfImage::Data {
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Limit of elf program headers allowed.
2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  enum {
2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    MAX_PROGRAM_HEADERS = 128
2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  };
2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ElfW(Ehdr) ehdr;
2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ElfW(Phdr) phdrs[MAX_PROGRAM_HEADERS];
2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ElfW(Addr) load_bias;
2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ElfImage::ElfImage() {
2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ElfImage::~ElfImage() {
2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)uintptr_t ElfImage::entry_point() const {
2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!data_) {
2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(DFATAL) << "entry_point must be called after Read().";
2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return 0;
2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return data_->ehdr.e_entry + data_->load_bias;
2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)NaClErrorCode ElfImage::Read(struct NaClDesc* descriptor) {
2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DCHECK(!data_);
2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ::scoped_ptr<Data> data(new Data);
2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Read elf header.
2735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ssize_t read_ret = (*NACL_VTBL(NaClDesc, descriptor)->PRead)(
2745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      descriptor, &data->ehdr, sizeof(data->ehdr), 0);
2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (NaClSSizeIsNegErrno(&read_ret) ||
2765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      static_cast<size_t>(read_ret) != sizeof(data->ehdr)) {
2775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "Could not load elf headers.";
2785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return LOAD_READ_ERROR;
2795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NaClErrorCode error_code = ValidateElfHeader(data->ehdr);
2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (error_code != LOAD_OK)
2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return error_code;
2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Read program headers.
2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (data->ehdr.e_phnum > Data::MAX_PROGRAM_HEADERS) {
2875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "Too many program headers";
2885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return LOAD_TOO_MANY_PROG_HDRS;
2895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (data->ehdr.e_phentsize != sizeof(data->phdrs[0])) {
2925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "Bad program headers size\n"
2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               << "  ehdr_.e_phentsize = " << data->ehdr.e_phentsize << "\n"
2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)               << "  sizeof phdrs[0] = " << sizeof(data->phdrs[0]);
2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return LOAD_BAD_PHENTSIZE;
2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  size_t read_size = data->ehdr.e_phnum * data->ehdr.e_phentsize;
2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  read_ret = (*NACL_VTBL(NaClDesc, descriptor)->PRead)(
3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      descriptor, data->phdrs, read_size, data->ehdr.e_phoff);
3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (NaClSSizeIsNegErrno(&read_ret) ||
3035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      static_cast<size_t>(read_ret) != read_size) {
3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "Cannot load prog headers";
3055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return LOAD_READ_ERROR;
3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  data_.swap(data);
3095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return LOAD_OK;
3105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)NaClErrorCode ElfImage::Load(struct NaClDesc* descriptor) {
3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (!data_) {
3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(DFATAL) << "ElfImage::Load() must be called after Read()";
3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return LOAD_INTERNAL;
3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  NaClErrorCode error =
3195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ReserveMemory(data_->phdrs, data_->ehdr.e_phnum, &data_->load_bias);
3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (error != LOAD_OK) {
3215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "ElfImage::Load: Failed to allocate memory";
3225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return error;
3235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  error = LoadSegments(
3265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      data_->phdrs, data_->ehdr.e_phnum, data_->load_bias, descriptor);
3275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (error != LOAD_OK) {
3285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    LOG(ERROR) << "ElfImage::Load: Failed to load segments";
3295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return error;
3305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return LOAD_OK;
3335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace nonsfi
3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}  // namespace nacl
337