LCOV - code coverage report
Current view: directory - src/trusted/service_runtime - elf_util.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 421 326 77.4 %
Date: 2014-06-18 Functions: 0 0 -

       1                 : /*
       2                 :  * Copyright (c) 2012 The Native Client Authors. All rights reserved.
       3                 :  * Use of this source code is governed by a BSD-style license that can be
       4                 :  * found in the LICENSE file.
       5                 :  */
       6                 : 
       7                 : /*
       8                 :  * NaCl helper functions to deal with elf images
       9                 :  */
      10                 : 
      11                 : #include "native_client/src/include/portability.h"
      12                 : 
      13                 : #include <stdio.h>
      14                 : 
      15                 : #include <stdlib.h>
      16                 : #include <string.h>
      17                 : 
      18                 : #define NACL_LOG_MODULE_NAME  "elf_util"
      19                 : 
      20                 : #include "native_client/src/include/elf_constants.h"
      21                 : #include "native_client/src/include/elf.h"
      22                 : #include "native_client/src/include/nacl_macros.h"
      23                 : #include "native_client/src/include/nacl_platform.h"
      24                 : 
      25                 : #include "native_client/src/shared/gio/gio.h"
      26                 : #include "native_client/src/shared/platform/nacl_check.h"
      27                 : #include "native_client/src/shared/platform/nacl_host_desc.h"
      28                 : #include "native_client/src/shared/platform/nacl_log.h"
      29                 : 
      30                 : #include "native_client/src/trusted/desc/nacl_desc_effector_trusted_mem.h"
      31                 : #include "native_client/src/trusted/fault_injection/fault_injection.h"
      32                 : #include "native_client/src/trusted/perf_counter/nacl_perf_counter.h"
      33                 : #include "native_client/src/trusted/service_runtime/elf_util.h"
      34                 : #include "native_client/src/trusted/service_runtime/include/bits/mman.h"
      35                 : #include "native_client/src/trusted/service_runtime/nacl_config.h"
      36                 : #include "native_client/src/trusted/service_runtime/nacl_text.h"
      37                 : #include "native_client/src/trusted/service_runtime/nacl_valgrind_hooks.h"
      38                 : #include "native_client/src/trusted/service_runtime/sel_memory.h"
      39                 : #include "native_client/src/trusted/service_runtime/sys_memory.h"
      40                 : #include "native_client/src/trusted/validator/validation_metadata.h"
      41                 : 
      42                 : /* private */
      43                 : struct NaClElfImage {
      44                 :   Elf_Ehdr  ehdr;
      45                 :   Elf_Phdr  phdrs[NACL_MAX_PROGRAM_HEADERS];
      46                 :   int       loadable[NACL_MAX_PROGRAM_HEADERS];
      47                 : };
      48                 : 
      49                 : 
      50                 : enum NaClPhdrCheckAction {
      51                 :   PCA_NONE,
      52                 :   PCA_TEXT_CHECK,
      53                 :   PCA_RODATA,
      54                 :   PCA_DATA,
      55                 :   PCA_IGNORE  /* ignore this segment. */
      56                 : };
      57                 : 
      58                 : 
      59                 : struct NaClPhdrChecks {
      60                 :   Elf_Word                  p_type;
      61                 :   Elf_Word                  p_flags;  /* rwx */
      62                 :   enum NaClPhdrCheckAction  action;
      63                 :   int                       required;  /* only for text for now */
      64                 :   Elf_Addr                  p_vaddr;  /* if non-zero, vaddr must be this */
      65                 : };
      66                 : 
      67                 : /*
      68                 :  * Other than empty segments, these are the only ones that are allowed.
      69                 :  */
      70                 : static const struct NaClPhdrChecks nacl_phdr_check_data[] = {
      71                 :   /* phdr */
      72                 :   { PT_PHDR, PF_R, PCA_IGNORE, 0, 0, },
      73                 :   /* text */
      74                 :   { PT_LOAD, PF_R|PF_X, PCA_TEXT_CHECK, 1, NACL_TRAMPOLINE_END, },
      75                 :   /* rodata */
      76                 :   { PT_LOAD, PF_R, PCA_RODATA, 0, 0, },
      77                 :   /* data/bss */
      78                 :   { PT_LOAD, PF_R|PF_W, PCA_DATA, 0, 0, },
      79                 :   /* tls */
      80                 :   { PT_TLS, PF_R, PCA_IGNORE, 0, 0},
      81                 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_arm
      82                 :   /* arm exception handling unwind info (for c++)*/
      83                 :   /* TODO(robertm): for some reason this does NOT end up in ro maybe because
      84                 :    *             it is relocatable. Try hacking the linker script to move it.
      85                 :    */
      86                 :   { PT_ARM_EXIDX, PF_R, PCA_IGNORE, 0, 0, },
      87                 : #endif
      88                 :   /*
      89                 :    * allow optional GNU stack permission marker, but require that the
      90                 :    * stack is non-executable.
      91                 :    */
      92                 :   { PT_GNU_STACK, PF_R|PF_W, PCA_NONE, 0, 0, },
      93                 :   /* ignored segments */
      94                 :   { PT_DYNAMIC, PF_R|PF_W, PCA_IGNORE, 0, 0},
      95                 :   /*
      96                 :    * PT_DYNAMIC with PF_R doesn't occur in practice, but leaving it here just
      97                 :    * in case it has been used.
      98                 :    */
      99                 :   { PT_DYNAMIC, PF_R, PCA_IGNORE, 0, 0},
     100                 :   { PT_INTERP, PF_R, PCA_IGNORE, 0, 0},
     101                 :   { PT_NOTE, PF_R, PCA_IGNORE, 0, 0},
     102                 :   { PT_GNU_EH_FRAME, PF_R, PCA_IGNORE, 0, 0},
     103                 :   { PT_GNU_RELRO, PF_R, PCA_IGNORE, 0, 0},
     104                 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_mips
     105                 :   { PT_MIPS_REGINFO, PF_R, PCA_IGNORE, 0, 0},
     106                 : #endif
     107                 :   { PT_NULL, PF_R, PCA_IGNORE, 0, 0},
     108                 : };
     109                 : 
     110                 : 
     111             278 : static void NaClDumpElfHeader(int loglevel, Elf_Ehdr *elf_hdr) {
     112                 : 
     113                 : #define DUMP(m,f)    do { NaClLog(loglevel,                     \
     114                 :                                   #m " = %" f "\n",             \
     115                 :                                   elf_hdr->m); } while (0)
     116                 : 
     117             556 :   NaClLog(loglevel, "=================================================\n");
     118             556 :   NaClLog(loglevel, "Elf header\n");
     119             556 :   NaClLog(loglevel, "==================================================\n");
     120                 : 
     121            1112 :   DUMP(e_ident+1, ".3s");
     122            1112 :   DUMP(e_type, "#x");
     123            1112 :   DUMP(e_machine, "#x");
     124            1112 :   DUMP(e_version, "#x");
     125            1112 :   DUMP(e_entry, "#"NACL_PRIxElf_Addr);
     126            1112 :   DUMP(e_phoff, "#"NACL_PRIxElf_Off);
     127            1112 :   DUMP(e_shoff, "#"NACL_PRIxElf_Off);
     128            1112 :   DUMP(e_flags, "#"NACL_PRIxElf_Word);
     129            1112 :   DUMP(e_ehsize, "#"NACL_PRIxElf_Half);
     130            1112 :   DUMP(e_phentsize, "#"NACL_PRIxElf_Half);
     131            1112 :   DUMP(e_phnum, "#"NACL_PRIxElf_Half);
     132            1112 :   DUMP(e_shentsize, "#"NACL_PRIxElf_Half);
     133            1112 :   DUMP(e_shnum, "#"NACL_PRIxElf_Half);
     134            1112 :   DUMP(e_shstrndx, "#"NACL_PRIxElf_Half);
     135                 : #undef DUMP
     136             556 :  NaClLog(loglevel, "sizeof(Elf32_Ehdr) = 0x%x\n", (int) sizeof *elf_hdr);
     137             278 : }
     138                 : 
     139                 : 
     140            1825 : static void NaClDumpElfProgramHeader(int     loglevel,
     141            1825 :                                      Elf_Phdr *phdr) {
     142                 : #define DUMP(mem, f) do {                                \
     143                 :     NaClLog(loglevel, "%s: %" f "\n", #mem, phdr->mem);  \
     144                 :   } while (0)
     145                 : 
     146            7300 :   DUMP(p_type, NACL_PRIxElf_Word);
     147            7300 :   DUMP(p_offset, NACL_PRIxElf_Off);
     148            7300 :   DUMP(p_vaddr, NACL_PRIxElf_Addr);
     149            7300 :   DUMP(p_paddr, NACL_PRIxElf_Addr);
     150            7300 :   DUMP(p_filesz, NACL_PRIxElf_Xword);
     151            7300 :   DUMP(p_memsz, NACL_PRIxElf_Xword);
     152            7300 :   DUMP(p_flags, NACL_PRIxElf_Word);
     153            3650 :   NaClLog(2, " (%s %s %s)\n",
     154                 :           (phdr->p_flags & PF_R) ? "PF_R" : "",
     155                 :           (phdr->p_flags & PF_W) ? "PF_W" : "",
     156                 :           (phdr->p_flags & PF_X) ? "PF_X" : "");
     157            7300 :   DUMP(p_align, NACL_PRIxElf_Xword);
     158                 : #undef  DUMP
     159            3650 :   NaClLog(loglevel, "\n");
     160            1825 : }
     161                 : 
     162                 : 
     163             278 : NaClErrorCode NaClElfImageValidateElfHeader(struct NaClElfImage *image) {
     164             278 :   const Elf_Ehdr *hdr = &image->ehdr;
     165                 : 
     166             278 :   if (memcmp(hdr->e_ident, ELFMAG, SELFMAG)) {
     167               0 :     NaClLog(LOG_ERROR, "bad elf magic\n");
     168               0 :     return LOAD_BAD_ELF_MAGIC;
     169                 :   }
     170                 : 
     171             278 :   if (ELFCLASS32 != hdr->e_ident[EI_CLASS]) {
     172               0 :     NaClLog(LOG_ERROR, "bad elf class\n");
     173               0 :     return LOAD_NOT_32_BIT;
     174                 :   }
     175                 : 
     176             278 :   if (ET_EXEC != hdr->e_type) {
     177               0 :     NaClLog(LOG_ERROR, "non executable\n");
     178               0 :     return LOAD_NOT_EXEC;
     179                 :   }
     180                 : 
     181             278 :   if (NACL_ELF_E_MACHINE != hdr->e_machine) {
     182               0 :     NaClLog(LOG_ERROR, "bad machine: %"NACL_PRIxElf_Half"\n", hdr->e_machine);
     183               0 :     return LOAD_BAD_MACHINE;
     184                 :   }
     185                 : 
     186             278 :   if (EV_CURRENT != hdr->e_version) {
     187               0 :     NaClLog(LOG_ERROR, "bad elf version: %"NACL_PRIxElf_Word"\n",
     188                 :             hdr->e_version);
     189               0 :     return LOAD_BAD_ELF_VERS;
     190                 :   }
     191                 : 
     192             278 :   return LOAD_OK;
     193             278 : }
     194                 : 
     195                 : /* TODO(robertm): decouple validation from computation of
     196                 :                    static_text_end and max_vaddr */
     197                 : NaClErrorCode NaClElfImageValidateProgramHeaders(
     198             271 :   struct NaClElfImage *image,
     199             271 :   uint8_t             addr_bits,
     200             271 :   struct NaClElfImageInfo *info) {
     201                 :     /*
     202                 :      * Scan phdrs and do sanity checks in-line.  Verify that the load
     203                 :      * address is NACL_TRAMPOLINE_END, that we have a single text
     204                 :      * segment.  Data and TLS segments are not required, though it is
     205                 :      * hard to avoid with standard tools, but in any case there should
     206                 :      * be at most one each.  Ensure that no segment's vaddr is outside
     207                 :      * of the address space.  Ensure that PT_GNU_STACK is present, and
     208                 :      * that x is off.
     209                 :      */
     210             271 :   const Elf_Ehdr      *hdr = &image->ehdr;
     211             271 :   int                 seen_seg[NACL_ARRAY_SIZE(nacl_phdr_check_data)];
     212                 : 
     213             271 :   int                 segnum;
     214             271 :   const Elf_Phdr      *php;
     215             271 :   size_t              j;
     216                 : 
     217             813 :   memset(info, 0, sizeof(*info));
     218                 : 
     219             271 :   info->max_vaddr = NACL_TRAMPOLINE_END;
     220                 : 
     221                 :   /*
     222                 :    * nacl_phdr_check_data is small, so O(|check_data| * nap->elf_hdr.e_phum)
     223                 :    * is okay.
     224                 :    */
     225             271 :   memset(seen_seg, 0, sizeof seen_seg);
     226            4130 :   for (segnum = 0; segnum < hdr->e_phnum; ++segnum) {
     227            1794 :     php = &image->phdrs[segnum];
     228            3588 :     NaClLog(3, "Looking at segment %d, type 0x%x, p_flags 0x%x\n",
     229                 :             segnum, php->p_type, php->p_flags);
     230            1794 :     if (0 == php->p_memsz) {
     231                 :       /*
     232                 :        * We will not load this segment.
     233                 :        */
     234             504 :       NaClLog(3, "Ignoring empty segment\n");
     235             252 :       continue;
     236                 :     }
     237                 : 
     238           17728 :     for (j = 0; j < NACL_ARRAY_SIZE(nacl_phdr_check_data); ++j) {
     239           11183 :       if (php->p_type == nacl_phdr_check_data[j].p_type
     240                 :           && php->p_flags == nacl_phdr_check_data[j].p_flags)
     241            1542 :         break;
     242            7322 :     }
     243            1542 :     if (j == NACL_ARRAY_SIZE(nacl_phdr_check_data)) {
     244                 :       /* segment not in nacl_phdr_check_data */
     245               0 :       NaClLog(2,
     246                 :               "Segment %d is of unexpected type 0x%x, flag 0x%x\n",
     247                 :               segnum,
     248                 :               php->p_type,
     249                 :               php->p_flags);
     250               0 :       return LOAD_BAD_SEGMENT;
     251                 :     }
     252                 : 
     253            3084 :     NaClLog(2, "Matched nacl_phdr_check_data[%"NACL_PRIuS"]\n", j);
     254            1542 :     if (seen_seg[j]) {
     255               0 :       NaClLog(2, "Segment %d is a type that has been seen\n", segnum);
     256               0 :       return LOAD_DUP_SEGMENT;
     257                 :     }
     258            1542 :     seen_seg[j] = 1;
     259                 : 
     260            1542 :     if (PCA_IGNORE == nacl_phdr_check_data[j].action) {
     261            1498 :       NaClLog(3, "Ignoring\n");
     262             749 :       continue;
     263                 :     }
     264                 : 
     265                 :     /*
     266                 :      * We will load this segment later.  Do the sanity checks.
     267                 :      */
     268            1064 :     if (0 != nacl_phdr_check_data[j].p_vaddr
     269                 :         && (nacl_phdr_check_data[j].p_vaddr != php->p_vaddr)) {
     270               0 :       NaClLog(2,
     271                 :               ("Segment %d: bad virtual address: 0x%08"
     272                 :                NACL_PRIxElf_Addr","
     273                 :                " expected 0x%08"NACL_PRIxElf_Addr"\n"),
     274                 :               segnum,
     275                 :               php->p_vaddr,
     276                 :               nacl_phdr_check_data[j].p_vaddr);
     277               0 :       return LOAD_SEGMENT_BAD_LOC;
     278                 :     }
     279             793 :     if (php->p_vaddr < NACL_TRAMPOLINE_END) {
     280               0 :       NaClLog(2,
     281                 :               ("Segment %d: virtual address (0x%08"NACL_PRIxElf_Addr
     282                 :                ") too low\n"),
     283                 :               segnum,
     284                 :               php->p_vaddr);
     285               0 :       return LOAD_SEGMENT_OUTSIDE_ADDRSPACE;
     286                 :     }
     287            1586 :     if (php->p_vaddr >= ((uint64_t) 1U << addr_bits) ||
     288                 :         ((uint64_t) 1U << addr_bits) - php->p_vaddr < php->p_memsz) {
     289               0 :       if (php->p_vaddr + php->p_memsz < php->p_vaddr) {
     290               0 :         NaClLog(2,
     291                 :                 "Segment %d: p_memsz caused integer overflow\n",
     292                 :                 segnum);
     293               0 :       } else {
     294               0 :         NaClLog(2,
     295                 :                 "Segment %d: too large, ends at 0x%08"NACL_PRIxElf_Addr"\n",
     296                 :                 segnum,
     297                 :                 php->p_vaddr + php->p_memsz);
     298                 :       }
     299               0 :       return LOAD_SEGMENT_OUTSIDE_ADDRSPACE;
     300                 :     }
     301             793 :     if (php->p_filesz > php->p_memsz) {
     302               0 :       NaClLog(2,
     303                 :               ("Segment %d: file size 0x%08"NACL_PRIxElf_Xword" larger"
     304                 :                " than memory size 0x%08"NACL_PRIxElf_Xword"\n"),
     305                 :               segnum,
     306                 :               php->p_filesz,
     307                 :               php->p_memsz);
     308               0 :       return LOAD_SEGMENT_BAD_PARAM;
     309                 :     }
     310                 : 
     311             793 :     image->loadable[segnum] = 1;
     312                 :     /* record our decision that we will load this segment */
     313                 : 
     314                 :     /*
     315                 :      * NACL_TRAMPOLINE_END <= p_vaddr
     316                 :      *                     <= p_vaddr + p_memsz
     317                 :      *                     < ((uintptr_t) 1U << nap->addr_bits)
     318                 :      */
     319             793 :     if (info->max_vaddr < php->p_vaddr + php->p_memsz) {
     320             791 :       info->max_vaddr = php->p_vaddr + php->p_memsz;
     321             791 :     }
     322                 : 
     323            1586 :     switch (nacl_phdr_check_data[j].action) {
     324                 :       case PCA_NONE:
     325               0 :         break;
     326                 :       case PCA_TEXT_CHECK:
     327             271 :         if (0 == php->p_memsz) {
     328               0 :           return LOAD_BAD_ELF_TEXT;
     329                 :         }
     330             271 :         info->static_text_end = NACL_TRAMPOLINE_END + php->p_filesz;
     331             271 :         break;
     332                 :       case PCA_RODATA:
     333             267 :         info->rodata_start = php->p_vaddr;
     334             267 :         info->rodata_end = php->p_vaddr + php->p_memsz;
     335             267 :         break;
     336                 :       case PCA_DATA:
     337             255 :         info->data_start = php->p_vaddr;
     338             255 :         info->data_end = php->p_vaddr + php->p_memsz;
     339             255 :         break;
     340                 :       case PCA_IGNORE:
     341               0 :         break;
     342                 :     }
     343             793 :   }
     344            7588 :   for (j = 0; j < NACL_ARRAY_SIZE(nacl_phdr_check_data); ++j) {
     345            3794 :     if (nacl_phdr_check_data[j].required && !seen_seg[j]) {
     346               0 :       return LOAD_REQUIRED_SEG_MISSING;
     347                 :     }
     348            3523 :   }
     349                 : 
     350             271 :   return LOAD_OK;
     351             271 : }
     352                 : 
     353                 : 
     354                 : 
     355             278 : struct NaClElfImage *NaClElfImageNew(struct NaClDesc *ndp,
     356             278 :                                      NaClErrorCode *err_code) {
     357             278 :   ssize_t read_ret;
     358             278 :   struct NaClElfImage *result;
     359             278 :   struct NaClElfImage image;
     360                 :   union {
     361                 :     Elf32_Ehdr ehdr32;
     362                 : #if NACL_TARGET_SUBARCH == 64
     363                 :     Elf64_Ehdr ehdr64;
     364                 : #endif
     365             278 :   } ehdr;
     366             278 :   int cur_ph;
     367                 : 
     368             278 :   memset(image.loadable, 0, sizeof image.loadable);
     369                 : 
     370                 :   /*
     371                 :    * We read the larger size of an ELFCLASS64 header even if it turns out
     372                 :    * we're reading an ELFCLASS32 file.  No usable ELFCLASS32 binary could
     373                 :    * be so small that it's not larger than Elf64_Ehdr anyway.
     374                 :    */
     375             278 :   read_ret = (*NACL_VTBL(NaClDesc, ndp)->PRead)(ndp, &ehdr, sizeof ehdr, 0);
     376             556 :   if (NaClSSizeIsNegErrno(&read_ret) || (size_t) read_ret != sizeof ehdr) {
     377               0 :     *err_code = LOAD_READ_ERROR;
     378               0 :     NaClLog(2, "could not load elf headers\n");
     379               0 :     return 0;
     380                 :   }
     381                 : 
     382                 : #if NACL_TARGET_SUBARCH == 64
     383             278 :   if (ELFCLASS64 == ehdr.ehdr64.e_ident[EI_CLASS]) {
     384                 :     /*
     385                 :      * Convert ELFCLASS64 format to ELFCLASS32 format.
     386                 :      * The initial four fields are the same in both classes.
     387                 :      */
     388             274 :     memcpy(image.ehdr.e_ident, ehdr.ehdr64.e_ident, EI_NIDENT);
     389             274 :     image.ehdr.e_ident[EI_CLASS] = ELFCLASS32;
     390             274 :     image.ehdr.e_type = ehdr.ehdr64.e_type;
     391             274 :     image.ehdr.e_machine = ehdr.ehdr64.e_machine;
     392             274 :     image.ehdr.e_version = ehdr.ehdr64.e_version;
     393             822 :     if (ehdr.ehdr64.e_entry > 0xffffffffU ||
     394                 :         ehdr.ehdr64.e_phoff > 0xffffffffU ||
     395                 :         ehdr.ehdr64.e_shoff > 0xffffffffU) {
     396               0 :       *err_code = LOAD_EHDR_OVERFLOW;
     397               0 :       NaClLog(2, "ELFCLASS64 file header fields overflow 32 bits\n");
     398               0 :       return 0;
     399                 :     }
     400             274 :     image.ehdr.e_entry = (Elf32_Addr) ehdr.ehdr64.e_entry;
     401             274 :     image.ehdr.e_phoff = (Elf32_Off) ehdr.ehdr64.e_phoff;
     402             274 :     image.ehdr.e_shoff = (Elf32_Off) ehdr.ehdr64.e_shoff;
     403             274 :     image.ehdr.e_flags = ehdr.ehdr64.e_flags;
     404             274 :     if (ehdr.ehdr64.e_ehsize != sizeof(ehdr.ehdr64)) {
     405               0 :       *err_code = LOAD_BAD_EHSIZE;
     406               0 :       NaClLog(2, "ELFCLASS64 file e_ehsize != %d\n", (int) sizeof(ehdr.ehdr64));
     407               0 :       return 0;
     408                 :     }
     409             274 :     image.ehdr.e_ehsize = sizeof(image.ehdr);
     410             274 :     image.ehdr.e_phentsize = sizeof(image.phdrs[0]);
     411             274 :     image.ehdr.e_phnum = ehdr.ehdr64.e_phnum;
     412             274 :     image.ehdr.e_shentsize = ehdr.ehdr64.e_shentsize;
     413             274 :     image.ehdr.e_shnum = ehdr.ehdr64.e_shnum;
     414             274 :     image.ehdr.e_shstrndx = ehdr.ehdr64.e_shstrndx;
     415             274 :   } else
     416                 : #endif
     417                 :   {
     418               4 :     image.ehdr = ehdr.ehdr32;
     419                 :   }
     420                 : 
     421             278 :   NaClDumpElfHeader(2, &image.ehdr);
     422                 : 
     423             278 :   *err_code = NaClElfImageValidateElfHeader(&image);
     424             278 :   if (LOAD_OK != *err_code) {
     425               0 :     return 0;
     426                 :   }
     427                 : 
     428                 :   /* read program headers */
     429             278 :   if (image.ehdr.e_phnum > NACL_MAX_PROGRAM_HEADERS) {
     430               0 :     *err_code = LOAD_TOO_MANY_PROG_HDRS;
     431               0 :     NaClLog(2, "too many prog headers\n");
     432               0 :     return 0;
     433                 :   }
     434                 : 
     435                 : #if NACL_TARGET_SUBARCH == 64
     436             278 :   if (ELFCLASS64 == ehdr.ehdr64.e_ident[EI_CLASS]) {
     437                 :     /*
     438                 :      * We'll load the 64-bit phdrs and convert them to 32-bit format.
     439                 :      */
     440             274 :     Elf64_Phdr phdr64[NACL_MAX_PROGRAM_HEADERS];
     441                 : 
     442             274 :     if (ehdr.ehdr64.e_phentsize != sizeof(Elf64_Phdr)) {
     443               0 :       *err_code = LOAD_BAD_PHENTSIZE;
     444               0 :       NaClLog(2, "bad prog headers size\n");
     445               0 :       NaClLog(2, " ehdr64.e_phentsize = 0x%"NACL_PRIxElf_Half"\n",
     446                 :               ehdr.ehdr64.e_phentsize);
     447               0 :       NaClLog(2, "  sizeof(Elf64_Phdr) = 0x%"NACL_PRIxS"\n",
     448                 :               sizeof(Elf64_Phdr));
     449               0 :       return 0;
     450                 :     }
     451                 : 
     452                 :     /*
     453                 :      * We know the multiplication won't overflow since we rejected
     454                 :      * e_phnum values larger than the small constant NACL_MAX_PROGRAM_HEADERS.
     455                 :      */
     456             274 :     read_ret = (*NACL_VTBL(NaClDesc, ndp)->
     457                 :                 PRead)(ndp,
     458                 :                        &phdr64[0],
     459                 :                        image.ehdr.e_phnum * sizeof phdr64[0],
     460                 :                        (nacl_off64_t) image.ehdr.e_phoff);
     461             548 :     if (NaClSSizeIsNegErrno(&read_ret) ||
     462                 :         (size_t) read_ret != image.ehdr.e_phnum * sizeof phdr64[0]) {
     463               0 :       *err_code = LOAD_READ_ERROR;
     464               0 :       NaClLog(2, "cannot load tp prog headers\n");
     465               0 :       return 0;
     466                 :     }
     467                 : 
     468            4180 :     for (cur_ph = 0; cur_ph < image.ehdr.e_phnum; ++cur_ph) {
     469           10906 :       if (phdr64[cur_ph].p_offset > 0xffffffffU ||
     470                 :           phdr64[cur_ph].p_vaddr > 0xffffffffU ||
     471                 :           phdr64[cur_ph].p_paddr > 0xffffffffU ||
     472                 :           phdr64[cur_ph].p_filesz > 0xffffffffU ||
     473                 :           phdr64[cur_ph].p_memsz > 0xffffffffU ||
     474                 :           phdr64[cur_ph].p_align > 0xffffffffU) {
     475               2 :         *err_code = LOAD_PHDR_OVERFLOW;
     476               4 :         NaClLog(2, "ELFCLASS64 program header fields overflow 32 bits\n");
     477               2 :         return 0;
     478                 :       }
     479            1816 :       image.phdrs[cur_ph].p_type = phdr64[cur_ph].p_type;
     480            1816 :       image.phdrs[cur_ph].p_offset = (Elf32_Off) phdr64[cur_ph].p_offset;
     481            1816 :       image.phdrs[cur_ph].p_vaddr = (Elf32_Addr) phdr64[cur_ph].p_vaddr;
     482            1816 :       image.phdrs[cur_ph].p_paddr = (Elf32_Addr) phdr64[cur_ph].p_paddr;
     483            1816 :       image.phdrs[cur_ph].p_filesz = (Elf32_Word) phdr64[cur_ph].p_filesz;
     484            1816 :       image.phdrs[cur_ph].p_memsz = (Elf32_Word) phdr64[cur_ph].p_memsz;
     485            1816 :       image.phdrs[cur_ph].p_flags = phdr64[cur_ph].p_flags;
     486            1816 :       image.phdrs[cur_ph].p_align = (Elf32_Word) phdr64[cur_ph].p_align;
     487            1816 :     }
     488             272 :   } else
     489                 : #endif
     490                 :   {
     491               4 :     if (image.ehdr.e_phentsize != sizeof image.phdrs[0]) {
     492               0 :       *err_code = LOAD_BAD_PHENTSIZE;
     493               0 :       NaClLog(2, "bad prog headers size\n");
     494               0 :       NaClLog(2, " image.ehdr.e_phentsize = 0x%"NACL_PRIxElf_Half"\n",
     495                 :               image.ehdr.e_phentsize);
     496               0 :       NaClLog(2, "  sizeof image.phdrs[0] = 0x%"NACL_PRIxS"\n",
     497                 :               sizeof image.phdrs[0]);
     498               0 :       return 0;
     499                 :     }
     500                 : 
     501               4 :     read_ret = (*NACL_VTBL(NaClDesc, ndp)->
     502                 :                 PRead)(ndp,
     503                 :                        &image.phdrs[0],
     504                 :                        image.ehdr.e_phnum * sizeof image.phdrs[0],
     505                 :                        (nacl_off64_t) image.ehdr.e_phoff);
     506               8 :     if (NaClSSizeIsNegErrno(&read_ret) ||
     507                 :         (size_t) read_ret != image.ehdr.e_phnum * sizeof image.phdrs[0]) {
     508               0 :       *err_code = LOAD_READ_ERROR;
     509               0 :       NaClLog(2, "cannot load tp prog headers\n");
     510               0 :       return 0;
     511                 :     }
     512                 :   }
     513                 : 
     514             552 :   NaClLog(2, "=================================================\n");
     515             552 :   NaClLog(2, "Elf Program headers\n");
     516             552 :   NaClLog(2, "==================================================\n");
     517            4202 :   for (cur_ph = 0; cur_ph <  image.ehdr.e_phnum; ++cur_ph) {
     518            1825 :     NaClDumpElfProgramHeader(2, &image.phdrs[cur_ph]);
     519            1825 :   }
     520                 : 
     521                 :   /* we delay allocating till the end to avoid cleanup code */
     522             276 :   result = malloc(sizeof image);
     523             276 :   if (result == 0) {
     524               0 :     *err_code = LOAD_NO_MEMORY;
     525               0 :     NaClLog(LOG_FATAL, "no enough memory for image meta data\n");
     526               0 :     return 0;
     527                 :   }
     528             828 :   memcpy(result, &image, sizeof image);
     529             276 :   *err_code = LOAD_OK;
     530             276 :   return result;
     531             278 : }
     532                 : 
     533                 : /*
     534                 :  * Attempt to map into the NaClApp object nap from the NaCl descriptor
     535                 :  * ndp an ELF segment of type p_flags that start at file_offset for
     536                 :  * segment_size bytes, to memory starting at paddr (system address).
     537                 :  * If it is a code segment, make a scratch mapping and check
     538                 :  * validation in readonly_text mode -- if it succeeds, we map into the
     539                 :  * target address; if it fails, we return failure so that pread-based
     540                 :  * loading can proceed.  For rodata and data segments, less checking
     541                 :  * is needed.  In the text and data case, the end of the segment may
     542                 :  * not land on a NACL_MAP_PAGESIZE boundary; when this occurs, we will
     543                 :  * map in all whole NACL_MAP_PAGESIZE chunks, and pread in the tail
     544                 :  * partial chunk.
     545                 :  *
     546                 :  * Returns: LOAD_OK, LOAD_STATUS_UNKNOWN, other error codes.
     547                 :  *
     548                 :  * LOAD_OK             -- if the segment has been fully handled
     549                 :  * LOAD_STATUS_UNKNOWN -- if pread-based fallback is required
     550                 :  * other error codes   -- if a fatal error occurs, and the caller
     551                 :  *                        should propagate up
     552                 :  *
     553                 :  * See NaClSysMmapIntern in nacl_syscall_common.c for corresponding
     554                 :  * mmap syscall where PROT_EXEC allows shared libraries to be mapped
     555                 :  * into dynamic code space.
     556                 :  */
     557               9 : static NaClErrorCode NaClElfFileMapSegment(struct NaClApp *nap,
     558               9 :                                            struct NaClDesc *ndp,
     559               9 :                                            Elf_Word p_flags,
     560               9 :                                            Elf_Off file_offset,
     561               9 :                                            Elf_Off segment_size,
     562               9 :                                            uintptr_t vaddr,
     563               9 :                                            uintptr_t paddr) {
     564               9 :   size_t rounded_filesz;       /* 64k rounded */
     565               9 :   int mmap_prot = 0;
     566               9 :   uintptr_t image_sys_addr;
     567               9 :   NaClValidationStatus validator_status = NaClValidationFailed;
     568               9 :   struct NaClValidationMetadata metadata;
     569               9 :   int read_last_page_if_partial_allocation_page = 1;
     570               9 :   ssize_t read_ret;
     571               9 :   struct NaClPerfCounter time_mmap_segment;
     572               9 :   NaClPerfCounterCtor(&time_mmap_segment, "NaClElfFileMapSegment");
     573                 : 
     574               9 :   rounded_filesz = NaClRoundAllocPage(segment_size);
     575                 : 
     576              18 :   NaClLog(4,
     577                 :           "NaClElfFileMapSegment: checking segment flags 0x%x"
     578                 :           " to determine map checks\n",
     579                 :           p_flags);
     580                 :   /*
     581                 :    * Is this the text segment?  If so, map into scratch memory and
     582                 :    * run validation (possibly cached result) with !stubout_mode,
     583                 :    * readonly_text.  If validator says it's okay, map directly into
     584                 :    * target location with NACL_ABI_PROT_READ|_EXEC.  If anything
     585                 :    * failed, fall back to PRead.  NB: the assumption is that there
     586                 :    * is only one PT_LOAD with PF_R|PF_X segment; this assumption is
     587                 :    * enforced by phdr seen_seg checks above in
     588                 :    * NaClElfImageValidateProgramHeaders.
     589                 :    *
     590                 :    * After this function returns, we will be setting memory protection
     591                 :    * in NaClMemoryProtection, so the actual memory protection used is
     592                 :    * immaterial.
     593                 :    *
     594                 :    * For rodata and data/bss, we mmap with NACL_ABI_PROT_READ or
     595                 :    * NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE as appropriate,
     596                 :    * without doing validation.  There is no fallback to PRead, since
     597                 :    * we don't validate the contents.
     598                 :    */
     599               9 :   switch (p_flags) {
     600                 :     case PF_R | PF_X:
     601               6 :       NaClLog(4,
     602                 :               "NaClElfFileMapSegment: text segment and"
     603                 :               " file is safe for mmap\n");
     604               3 :       if (NACL_VTBL(NaClDesc, ndp)->typeTag != NACL_DESC_HOST_IO) {
     605               0 :         NaClLog(4, "NaClElfFileMapSegment: not supported type, got %d\n",
     606                 :                 NACL_VTBL(NaClDesc, ndp)->typeTag);
     607               0 :         return LOAD_STATUS_UNKNOWN;
     608                 :       }
     609                 :       /*
     610                 :        * Unlike the mmap case, we do not re-run validation to
     611                 :        * allow patching here; instead, we handle validation
     612                 :        * failure by going to the pread_fallback case.  In the
     613                 :        * future, we should consider doing an in-place mapping and
     614                 :        * allowing HLT patch validation, which should be cheaper
     615                 :        * since those pages that do not require patching (hopefully
     616                 :        * majority) will remain file-backed and not require swap
     617                 :        * space, even if we had to fault in every page.
     618                 :        */
     619               6 :       NaClLog(1, "NaClElfFileMapSegment: mapping for validation\n");
     620               3 :       NaClPerfCounterMark(&time_mmap_segment, "PreMap");
     621               3 :       NaClPerfCounterIntervalLast(&time_mmap_segment);
     622               6 :       image_sys_addr = (*NACL_VTBL(NaClDesc, ndp)->
     623                 :                         Map)(ndp,
     624               3 :                              NaClDescEffectorTrustedMem(),
     625                 :                              (void *) NULL,
     626                 :                              rounded_filesz,
     627                 :                              NACL_ABI_PROT_READ,
     628                 :                              NACL_ABI_MAP_PRIVATE,
     629                 :                              file_offset);
     630               3 :       NaClPerfCounterMark(&time_mmap_segment, "MapForValidate");
     631               3 :       NaClPerfCounterIntervalLast(&time_mmap_segment);
     632               3 :       if (NaClPtrIsNegErrno(&image_sys_addr)) {
     633               0 :         NaClLog(LOG_INFO,
     634                 :                 "NaClElfFileMapSegment: Could not make scratch mapping,"
     635                 :                 " falling back to reading\n");
     636               0 :         return LOAD_STATUS_UNKNOWN;
     637                 :       }
     638                 :       /* ask validator / validation cache */
     639               3 :       NaClMetadataFromNaClDescCtor(&metadata, ndp);
     640               9 :       CHECK(segment_size == nap->static_text_end - NACL_TRAMPOLINE_END);
     641               9 :       validator_status = NACL_FI_VAL(
     642                 :           "ELF_LOAD_FORCE_VALIDATION_STATUS",
     643                 :           enum NaClValidationStatus,
     644                 :           (*nap->validator->
     645                 :            Validate)(vaddr,
     646                 :                      (uint8_t *) image_sys_addr,
     647                 :                      segment_size,  /* actual size */
     648                 :                      0,  /* stubout_mode: no */
     649                 :                      1,  /* readonly_text: yes */
     650                 :                      nap->cpu_features,
     651                 :                      &metadata,
     652                 :                      nap->validation_cache));
     653               3 :       NaClPerfCounterMark(&time_mmap_segment, "ValidateMapped");
     654               3 :       NaClPerfCounterIntervalLast(&time_mmap_segment);
     655               6 :       NaClLog(3, "NaClElfFileMapSegment: validator_status %d\n",
     656                 :               validator_status);
     657               3 :       NaClMetadataDtor(&metadata);
     658                 :       /*
     659                 :        * Remove scratch mapping, then map directly into untrusted
     660                 :        * address space or pread.
     661                 :        */
     662               3 :       NaClDescUnmapUnsafe(ndp, (void *) image_sys_addr,
     663                 :                           rounded_filesz);
     664                 :       NACL_MAKE_MEM_UNDEFINED((void *) paddr, rounded_filesz);
     665                 : 
     666               3 :       if (NaClValidationSucceeded != validator_status) {
     667               0 :         NaClLog(3,
     668                 :                 ("NaClElfFileMapSegment: readonly_text validation for mmap"
     669                 :                  " failed.  Will retry validation allowing HALT stubbing out"
     670                 :                  " of unsupported instruction extensions.\n"));
     671               0 :         return LOAD_STATUS_UNKNOWN;
     672                 :       }
     673                 : 
     674               6 :       NaClLog(1, "NaClElfFileMapSegment: mapping into code space\n");
     675                 :       /*
     676                 :        * Windows appears to not allow RWX mappings.  This interferes
     677                 :        * with HALT_SLED and having to HALT pad the last page.  We
     678                 :        * allow partial code pages, so
     679                 :        * read_last_page_if_partial_allocation_page will ensure that
     680                 :        * the last page is writable, so we will be able to write HALT
     681                 :        * instructions as needed.
     682                 :        */
     683               3 :       mmap_prot = NACL_ABI_PROT_READ | NACL_ABI_PROT_EXEC;
     684                 :       /*
     685                 :        * NB: the log string is used by tests/mmap_main_nexe/nacl.scons
     686                 :        * and must be logged at a level that is less than or equal to
     687                 :        * the requested verbosity level there.
     688                 :        */
     689               6 :       NaClLog(1, "NaClElfFileMapSegment: EXERCISING MMAP LOAD PATH\n");
     690               3 :       nap->main_exe_prevalidated = 1;
     691               3 :       break;
     692                 : 
     693                 :     case PF_R | PF_W:
     694                 :       /* read-write (initialized data) */
     695               3 :       mmap_prot = NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE;
     696                 :       /*
     697                 :        * NB: the partial page processing will result in zeros
     698                 :        * following the initialized data, so that the BSS will be zero.
     699                 :        * On a typical system, this page is mapped in and the BSS
     700                 :        * region is memset to zero, which means that this partial page
     701                 :        * is faulted in.  Rather than saving a syscall (pread) and
     702                 :        * faulting it in, we just use the same code path as for code,
     703                 :        * which is (slightly) simpler.
     704                 :        */
     705               3 :       break;
     706                 : 
     707                 :     case PF_R:
     708                 :       /* read-only */
     709               3 :       mmap_prot = NACL_ABI_PROT_READ;
     710                 :       /*
     711                 :        * For rodata, we allow mapping in "garbage" past a partial
     712                 :        * page; this potentially eliminates a disk I/O operation
     713                 :        * (if data section has no partial page), possibly delaying
     714                 :        * disk spin-up if the code was in the validation cache.
     715                 :        * And it saves another 64kB of swap.
     716                 :        */
     717               3 :       read_last_page_if_partial_allocation_page = 0;
     718               3 :       break;
     719                 : 
     720                 :     default:
     721               0 :       NaClLog(LOG_FATAL, "NaClElfFileMapSegment: unexpected p_flags %d\n",
     722                 :               p_flags);
     723               0 :   }
     724              15 :   if (rounded_filesz != segment_size &&
     725                 :       read_last_page_if_partial_allocation_page) {
     726               3 :     uintptr_t tail_offset = rounded_filesz - NACL_MAP_PAGESIZE;
     727               3 :     size_t tail_size = segment_size - tail_offset;
     728               6 :     NaClLog(4, "NaClElfFileMapSegment: pread tail\n");
     729               3 :     read_ret = (*NACL_VTBL(NaClDesc, ndp)->
     730                 :                 PRead)(ndp,
     731                 :                        (void *) (paddr + tail_offset),
     732                 :                        tail_size,
     733                 :                        (nacl_off64_t) (file_offset + tail_offset));
     734               3 :     NaClPerfCounterMark(&time_mmap_segment, "PRead tail");
     735               3 :     NaClPerfCounterIntervalLast(&time_mmap_segment);
     736               6 :     if (NaClSSizeIsNegErrno(&read_ret) || (size_t) read_ret != tail_size) {
     737               0 :       NaClLog(LOG_ERROR,
     738                 :               "NaClElfFileMapSegment: pread load of page tail failed\n");
     739               0 :       return LOAD_SEGMENT_BAD_PARAM;
     740                 :     }
     741               3 :     rounded_filesz -= NACL_MAP_PAGESIZE;
     742               3 :   }
     743                 :   /* mmap in */
     744               9 :   if (rounded_filesz == 0) {
     745               6 :     NaClLog(4,
     746                 :             "NaClElfFileMapSegment: no pages to map, probably because"
     747                 :             " the segment was a partial page, so it was processed by"
     748                 :             " reading.\n");
     749               3 :   } else {
     750              12 :     NaClLog(4,
     751                 :             "NaClElfFileMapSegment: mapping %"NACL_PRIuS" (0x%"
     752                 :             NACL_PRIxS") bytes to"
     753                 :             " address 0x%"NACL_PRIxPTR", position %"
     754                 :             NACL_PRIdElf_Off" (0x%"NACL_PRIxElf_Off")\n",
     755                 :             rounded_filesz, rounded_filesz,
     756                 :             paddr,
     757                 :             file_offset, file_offset);
     758               6 :     image_sys_addr = (*NACL_VTBL(NaClDesc, ndp)->
     759                 :                       Map)(ndp,
     760                 :                            nap->effp,
     761                 :                            (void *) paddr,
     762                 :                            rounded_filesz,
     763                 :                            mmap_prot,
     764                 :                            NACL_ABI_MAP_PRIVATE | NACL_ABI_MAP_FIXED,
     765                 :                            file_offset);
     766               6 :     NaClPerfCounterMark(&time_mmap_segment, "MapFinal");
     767               6 :     NaClPerfCounterIntervalLast(&time_mmap_segment);
     768               6 :     if (image_sys_addr != paddr) {
     769               0 :       NaClLog(LOG_FATAL,
     770                 :               ("NaClElfFileMapSegment: map to 0x%"NACL_PRIxPTR" (prot %x) "
     771                 :                "failed: got 0x%"NACL_PRIxPTR"\n"),
     772                 :               paddr, mmap_prot, image_sys_addr);
     773               0 :     }
     774                 :     /* Tell Valgrind that we've mapped a segment of nacl_file. */
     775               6 :     NaClFileMappingForValgrind(paddr, rounded_filesz, file_offset);
     776                 :   }
     777               9 :   return LOAD_OK;
     778               9 : }
     779                 : 
     780             268 : NaClErrorCode NaClElfImageLoad(struct NaClElfImage *image,
     781             268 :                                struct NaClDesc *ndp,
     782             268 :                                struct NaClApp *nap) {
     783             268 :   int segnum;
     784             268 :   uintptr_t vaddr;
     785             268 :   uintptr_t paddr;
     786             268 :   uintptr_t end_vaddr;
     787             268 :   ssize_t read_ret;
     788             268 :   int safe_for_mmap;
     789                 : 
     790            4100 :   for (segnum = 0; segnum < image->ehdr.e_phnum; ++segnum) {
     791            1782 :     const Elf_Phdr *php = &image->phdrs[segnum];
     792            1782 :     Elf_Off offset = (Elf_Off) NaClTruncAllocPage(php->p_offset);
     793            1782 :     Elf_Off filesz = php->p_offset + php->p_filesz - offset;
     794                 : 
     795                 :     /* did we decide that we will load this segment earlier? */
     796            1782 :     if (!image->loadable[segnum]) {
     797             998 :       continue;
     798                 :     }
     799                 : 
     800            1568 :     NaClLog(2, "loading segment %d\n", segnum);
     801                 : 
     802             784 :     if (0 == php->p_filesz) {
     803               2 :       NaClLog(4, "zero-sized segment.  ignoring...\n");
     804               1 :       continue;
     805                 :     }
     806                 : 
     807             783 :     end_vaddr = php->p_vaddr + php->p_filesz;
     808                 :     /* integer overflow? */
     809             783 :     if (end_vaddr < php->p_vaddr) {
     810               0 :       NaClLog(LOG_FATAL, "parameter error should have been detected already\n");
     811               0 :     }
     812                 :     /*
     813                 :      * is the end virtual address within the NaCl application's
     814                 :      * address space?  if it is, it implies that the start virtual
     815                 :      * address is also.
     816                 :      */
     817             783 :     if (end_vaddr >= ((uintptr_t) 1U << nap->addr_bits)) {
     818               0 :       NaClLog(LOG_FATAL, "parameter error should have been detected already\n");
     819               0 :     }
     820                 : 
     821             783 :     vaddr = NaClTruncAllocPage(php->p_vaddr);
     822             783 :     paddr = NaClUserToSysAddr(nap, vaddr);
     823            2349 :     CHECK(kNaClBadAddress != paddr);
     824                 : 
     825                 :     /*
     826                 :      * Check NaClDescIsSafeForMmap(ndp) to see if it might be okay to
     827                 :      * mmap.
     828                 :      */
     829            1566 :     NaClLog(4, "NaClElfImageLoad: checking descriptor mmap safety\n");
     830             783 :     safe_for_mmap = NaClDescIsSafeForMmap(ndp);
     831             783 :     if (safe_for_mmap) {
     832              12 :       NaClLog(4, "NaClElfImageLoad: safe-for-mmap\n");
     833               6 :     }
     834                 : 
     835             783 :     if (!safe_for_mmap &&
     836            1554 :         NACL_FI("ELF_LOAD_BYPASS_DESCRIPTOR_SAFETY_CHECK", 0, 1)) {
     837               6 :       NaClLog(LOG_WARNING, "WARNING: BYPASSING DESCRIPTOR SAFETY CHECK\n");
     838               3 :       safe_for_mmap = 1;
     839               3 :     }
     840             783 :     if (safe_for_mmap) {
     841               9 :       NaClErrorCode map_status;
     842              18 :       NaClLog(4, "NaClElfImageLoad: safe-for-mmap\n");
     843               9 :       map_status = NaClElfFileMapSegment(nap, ndp, php->p_flags,
     844                 :                                          offset, filesz, vaddr, paddr);
     845                 :       /*
     846                 :        * NB: -Werror=switch-enum forces us to not use a switch.
     847                 :        */
     848               9 :       if (LOAD_OK == map_status) {
     849                 :         /* Segment has been handled -- proceed to next segment */
     850               9 :         continue;
     851               0 :       } else if (LOAD_STATUS_UNKNOWN != map_status) {
     852                 :         /*
     853                 :          * A real error!  Return it so that this can be reported to
     854                 :          * the embedding code (via start_module status).
     855                 :          */
     856               0 :         return map_status;
     857                 :       }
     858                 :       /* Fall through: pread-based fallback requested */
     859               0 :     }
     860            1548 :     NaClLog(4,
     861                 :             "PReading %"NACL_PRIdElf_Xword" (0x%"NACL_PRIxElf_Xword") bytes to"
     862                 :             " address 0x%"NACL_PRIxPTR", position %"
     863                 :             NACL_PRIdElf_Off" (0x%"NACL_PRIxElf_Off")\n",
     864                 :             filesz, filesz,
     865                 :             paddr,
     866                 :             offset, offset);
     867                 : 
     868                 :     /*
     869                 :      * Tell valgrind that this memory is accessible and undefined. For more
     870                 :      * details see
     871                 :      * http://code.google.com/p/nativeclient/wiki/ValgrindMemcheck#Implementation_details
     872                 :      */
     873                 :     NACL_MAKE_MEM_UNDEFINED((void *) paddr, filesz);
     874                 : 
     875             774 :     read_ret = (*NACL_VTBL(NaClDesc, ndp)->
     876                 :                 PRead)(ndp, (void *) paddr, filesz, (nacl_off64_t) offset);
     877            1548 :     if (NaClSSizeIsNegErrno(&read_ret) || (size_t) read_ret != filesz) {
     878               0 :       NaClLog(LOG_ERROR, "load failure segment %d", segnum);
     879               0 :       return LOAD_SEGMENT_BAD_PARAM;
     880                 :     }
     881                 :     /* region from p_filesz to p_memsz should already be zero filled */
     882                 : 
     883                 :     /* Tell Valgrind that we've mapped a segment of nacl_file. */
     884             774 :     NaClFileMappingForValgrind(paddr, filesz, offset);
     885             774 :   }
     886                 : 
     887             268 :   return LOAD_OK;
     888             268 : }
     889                 : 
     890                 : 
     891                 : NaClErrorCode NaClElfImageLoadDynamically(
     892               5 :     struct NaClElfImage *image,
     893               5 :     struct NaClApp *nap,
     894               5 :     struct NaClDesc *ndp,
     895               5 :     struct NaClValidationMetadata *metadata) {
     896               5 :   ssize_t read_ret;
     897               5 :   int segnum;
     898              72 :   for (segnum = 0; segnum < image->ehdr.e_phnum; ++segnum) {
     899              31 :     const Elf_Phdr *php = &image->phdrs[segnum];
     900              31 :     Elf_Addr vaddr = php->p_vaddr & ~(NACL_MAP_PAGESIZE - 1);
     901              31 :     Elf_Off offset = php->p_offset & ~(NACL_MAP_PAGESIZE - 1);
     902              31 :     Elf_Off filesz = php->p_offset + php->p_filesz - offset;
     903              31 :     Elf_Off memsz = php->p_offset + php->p_memsz - offset;
     904              31 :     int32_t result;
     905                 : 
     906                 :     /*
     907                 :      * We check for PT_LOAD directly rather than using the "loadable"
     908                 :      * array because we are not using NaClElfImageValidateProgramHeaders()
     909                 :      * to fill out the "loadable" array for this ELF object.  This ELF
     910                 :      * object does not have to fit such strict constraints (such as
     911                 :      * having code at 0x20000), and safety checks are applied by
     912                 :      * NaClTextDyncodeCreate() and NaClSysMmapIntern().
     913                 :      */
     914              31 :     if (PT_LOAD != php->p_type) {
     915              16 :       continue;
     916                 :     }
     917                 : 
     918              15 :     if (0 != (php->p_flags & PF_X)) {
     919                 :       /* Load code segment. */
     920                 :       /*
     921                 :        * We make a copy of the code.  This is not ideal given that
     922                 :        * GioMemoryFileSnapshot and NaClGioShm already have a copy of
     923                 :        * the file in memory or mmapped.
     924                 :        * TODO(mseaborn): Reduce the amount of copying here.
     925                 :        */
     926               5 :       char *code_copy = malloc(filesz);
     927               5 :       if (NULL == code_copy) {
     928               0 :         NaClLog(LOG_ERROR, "NaClElfImageLoadDynamically: malloc failed\n");
     929               0 :         return LOAD_NO_MEMORY;
     930                 :       }
     931               5 :       read_ret = (*NACL_VTBL(NaClDesc, ndp)->
     932                 :                   PRead)(ndp, code_copy, filesz, (nacl_off64_t) offset);
     933              10 :       if (NaClSSizeIsNegErrno(&read_ret) ||
     934                 :           (size_t) read_ret != filesz) {
     935               0 :         free(code_copy);
     936               0 :         NaClLog(LOG_ERROR, "NaClElfImageLoadDynamically: "
     937                 :                 "failed to read code segment\n");
     938               0 :         return LOAD_READ_ERROR;
     939                 :       }
     940               5 :       if (NULL != metadata) {
     941               4 :         metadata->code_offset = offset;
     942               4 :       }
     943               5 :       result = NaClTextDyncodeCreate(nap, (uint32_t) vaddr,
     944                 :                                      code_copy, (uint32_t) filesz, metadata);
     945               5 :       free(code_copy);
     946               5 :       if (0 != result) {
     947               0 :         NaClLog(LOG_ERROR, "NaClElfImageLoadDynamically: "
     948                 :                 "failed to load code segment\n");
     949               0 :         return LOAD_UNLOADABLE;
     950                 :       }
     951               5 :     } else {
     952                 :       /* Load data segment. */
     953              10 :       void *paddr = (void *) NaClUserToSys(nap, vaddr);
     954              10 :       size_t mapping_size = NaClRoundAllocPage(memsz);
     955                 :       /*
     956                 :        * Note that we do not used NACL_ABI_MAP_FIXED because we do not
     957                 :        * want to silently overwrite any existing mappings, such as the
     958                 :        * user app's data segment or the stack.  We detect overmapping
     959                 :        * when mmap chooses not to use the preferred address we supply.
     960                 :        * (Ideally mmap would provide a MAP_EXCL option for this
     961                 :        * instead.)
     962                 :        */
     963              10 :       result = NaClSysMmapIntern(
     964                 :           nap, (void *) (uintptr_t) vaddr, mapping_size,
     965                 :           NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
     966                 :           NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE,
     967                 :           -1, 0);
     968              10 :       if ((int32_t) vaddr != result) {
     969               0 :         NaClLog(LOG_ERROR, "NaClElfImageLoadDynamically: "
     970                 :                 "failed to map data segment\n");
     971               0 :         return LOAD_UNLOADABLE;
     972                 :       }
     973              10 :       read_ret = (*NACL_VTBL(NaClDesc, ndp)->
     974                 :                   PRead)(ndp, paddr, filesz, (nacl_off64_t) offset);
     975              20 :       if (NaClSSizeIsNegErrno(&read_ret) ||
     976                 :           (size_t) read_ret != filesz) {
     977               0 :         NaClLog(LOG_ERROR, "NaClElfImageLoadDynamically: "
     978                 :                 "failed to read data segment\n");
     979               0 :         return LOAD_READ_ERROR;
     980                 :       }
     981                 :       /*
     982                 :        * Note that we do not need to zero the BSS (the region from
     983                 :        * p_filesz to p_memsz) because it should already be zero
     984                 :        * filled.  This would not be the case if we were mapping the
     985                 :        * data segment from the file.
     986                 :        */
     987                 : 
     988              10 :       if (0 == (php->p_flags & PF_W)) {
     989                 :         /* Handle read-only data segment. */
     990               5 :         int rc = NaClMprotect(paddr, mapping_size, NACL_ABI_PROT_READ);
     991               5 :         if (0 != rc) {
     992               0 :           NaClLog(LOG_ERROR, "NaClElfImageLoadDynamically: "
     993                 :                   "failed to mprotect read-only data segment\n");
     994               0 :           return LOAD_MPROTECT_FAIL;
     995                 :         }
     996                 : 
     997               5 :         NaClVmmapAddWithOverwrite(&nap->mem_map,
     998                 :                                   vaddr >> NACL_PAGESHIFT,
     999                 :                                   mapping_size >> NACL_PAGESHIFT,
    1000                 :                                   NACL_ABI_PROT_READ,
    1001                 :                                   NACL_ABI_MAP_PRIVATE,
    1002                 :                                   NULL,
    1003                 :                                   0,
    1004                 :                                   0);
    1005               5 :       }
    1006                 :     }
    1007              15 :   }
    1008               5 :   return LOAD_OK;
    1009               5 : }
    1010                 : 
    1011             276 : void NaClElfImageDelete(struct NaClElfImage *image) {
    1012             276 :   free(image);
    1013             276 : }
    1014                 : 
    1015                 : 
    1016             276 : uintptr_t NaClElfImageGetEntryPoint(struct NaClElfImage *image) {
    1017             276 :   return image->ehdr.e_entry;
    1018                 : }

Generated by: LCOV version 1.7