LCOV - code coverage report
Current view: directory - src/trusted/service_runtime - elf_util.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 224 124 55.4 %
Date: 2012-02-16 Functions: 0 0 -

       1                 : /*
       2                 :  * Copyright (c) 2011 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_log.h"
      27                 : 
      28                 : #include "native_client/src/trusted/service_runtime/elf_util.h"
      29                 : #include "native_client/src/trusted/service_runtime/include/bits/mman.h"
      30                 : #include "native_client/src/trusted/service_runtime/nacl_config.h"
      31                 : #include "native_client/src/trusted/service_runtime/nacl_syscall_common.h"
      32                 : #include "native_client/src/trusted/service_runtime/nacl_text.h"
      33                 : #include "native_client/src/trusted/service_runtime/nacl_valgrind_hooks.h"
      34                 : #include "native_client/src/trusted/service_runtime/sel_memory.h"
      35                 : 
      36                 : /* private */
      37                 : struct NaClElfImage {
      38                 :   Elf_Ehdr  ehdr;
      39                 :   Elf_Phdr  phdrs[NACL_MAX_PROGRAM_HEADERS];
      40                 :   int       loadable[NACL_MAX_PROGRAM_HEADERS];
      41                 : };
      42                 : 
      43                 : 
      44                 : enum NaClPhdrCheckAction {
      45                 :   PCA_NONE,
      46                 :   PCA_TEXT_CHECK,
      47                 :   PCA_RODATA,
      48                 :   PCA_DATA,
      49                 :   PCA_IGNORE  /* ignore this segment. */
      50                 : };
      51                 : 
      52                 : 
      53                 : struct NaClPhdrChecks {
      54                 :   Elf_Word                  p_type;
      55                 :   Elf_Word                  p_flags;  /* rwx */
      56                 :   enum NaClPhdrCheckAction  action;
      57                 :   int                       required;  /* only for text for now */
      58                 :   Elf_Addr                  p_vaddr;  /* if non-zero, vaddr must be this */
      59                 : };
      60                 : 
      61                 : /*
      62                 :  * Other than empty segments, these are the only ones that are allowed.
      63                 :  */
      64                 : static const struct NaClPhdrChecks nacl_phdr_check_data[] = {
      65                 :   /* phdr */
      66                 :   { PT_PHDR, PF_R, PCA_IGNORE, 0, 0, },
      67                 :   /* text */
      68                 :   { PT_LOAD, PF_R|PF_X, PCA_TEXT_CHECK, 1, NACL_TRAMPOLINE_END, },
      69                 :   /* rodata */
      70                 :   { PT_LOAD, PF_R, PCA_RODATA, 0, 0, },
      71                 :   /* data/bss */
      72                 :   { PT_LOAD, PF_R|PF_W, PCA_DATA, 0, 0, },
      73                 :   /* tls */
      74                 :   { PT_TLS, PF_R, PCA_IGNORE, 0, 0},
      75                 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_arm
      76                 :   /* arm exception handling unwind info (for c++)*/
      77                 :   /* TODO(robertm): for some reason this does NOT end up in ro maybe because
      78                 :    *             it is relocatable. Try hacking the linker script to move it.
      79                 :    */
      80                 :   { PT_ARM_EXIDX, PF_R, PCA_IGNORE, 0, 0, },
      81                 : #endif
      82                 :   /*
      83                 :    * allow optional GNU stack permission marker, but require that the
      84                 :    * stack is non-executable.
      85                 :    */
      86                 :   { PT_GNU_STACK, PF_R|PF_W, PCA_NONE, 0, 0, },
      87                 :   /* ignored segments */
      88                 :   { PT_DYNAMIC, PF_R, PCA_IGNORE, 0, 0},
      89                 :   { PT_INTERP, PF_R, PCA_IGNORE, 0, 0},
      90                 :   { PT_NOTE, PF_R, PCA_IGNORE, 0, 0},
      91                 :   { PT_GNU_EH_FRAME, PF_R, PCA_IGNORE, 0, 0},
      92                 :   { PT_GNU_RELRO, PF_R, PCA_IGNORE, 0, 0},
      93                 :   { PT_NULL, PF_R, PCA_IGNORE, 0, 0},
      94                 : };
      95                 : 
      96                 : 
      97                 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86
      98                 : # if NACL_BUILD_SUBARCH == 32
      99                 : #  define EM_EXPECTED_BY_NACL EM_386
     100                 : # elif NACL_BUILD_SUBARCH == 64
     101                 : #  define EM_EXPECTED_BY_NACL EM_X86_64
     102                 : # else
     103                 : #  error "No NACL_BUILD_SUBARCH for x86 -- are we on x86-128?"
     104                 : # endif
     105                 : #elif NACL_ARCH(NACL_BUILD_ARCH) == NACL_arm
     106                 : # define EM_EXPECTED_BY_NACL EM_ARM
     107                 : #else
     108                 : # error "Unknown platform!"
     109                 : #endif
     110                 : 
     111                 : 
     112              11 : static void NaClDumpElfHeader(int loglevel, Elf_Ehdr *elf_hdr) {
     113                 : 
     114                 : #define DUMP(m,f)    do { NaClLog(loglevel,                     \
     115                 :                                   #m " = %" f "\n",             \
     116                 :                                   elf_hdr->m); } while (0)
     117                 : 
     118              11 :   NaClLog(loglevel, "=================================================\n");
     119              11 :   NaClLog(loglevel, "Elf header\n");
     120              11 :   NaClLog(loglevel, "==================================================\n");
     121                 : 
     122              11 :   DUMP(e_ident+1, ".3s");
     123              11 :   DUMP(e_type, "#x");
     124              11 :   DUMP(e_machine, "#x");
     125              11 :   DUMP(e_version, "#x");
     126              11 :   DUMP(e_entry, "#"NACL_PRIxElf_Addr);
     127              11 :   DUMP(e_phoff, "#"NACL_PRIxElf_Off);
     128              11 :   DUMP(e_shoff, "#"NACL_PRIxElf_Off);
     129              11 :   DUMP(e_flags, "#"NACL_PRIxElf_Word);
     130              11 :   DUMP(e_ehsize, "#"NACL_PRIxElf_Half);
     131              11 :   DUMP(e_phentsize, "#"NACL_PRIxElf_Half);
     132              11 :   DUMP(e_phnum, "#"NACL_PRIxElf_Half);
     133              11 :   DUMP(e_shentsize, "#"NACL_PRIxElf_Half);
     134              11 :   DUMP(e_shnum, "#"NACL_PRIxElf_Half);
     135              11 :   DUMP(e_shstrndx, "#"NACL_PRIxElf_Half);
     136                 : #undef DUMP
     137              11 :  NaClLog(loglevel, "sizeof(Elf32_Ehdr) = 0x%x\n", (int) sizeof *elf_hdr);
     138              11 : }
     139                 : 
     140                 : 
     141                 : static void NaClDumpElfProgramHeader(int     loglevel,
     142              43 :                                     Elf_Phdr *phdr) {
     143                 : #define DUMP(mem, f) do {                                \
     144                 :     NaClLog(loglevel, "%s: %" f "\n", #mem, phdr->mem);  \
     145                 :   } while (0)
     146                 : 
     147              43 :   DUMP(p_type, NACL_PRIxElf_Word);
     148              43 :   DUMP(p_offset, NACL_PRIxElf_Off);
     149              43 :   DUMP(p_vaddr, NACL_PRIxElf_Addr);
     150              43 :   DUMP(p_paddr, NACL_PRIxElf_Addr);
     151              43 :   DUMP(p_filesz, NACL_PRIxElf_Xword);
     152              43 :   DUMP(p_memsz, NACL_PRIxElf_Xword);
     153              43 :   DUMP(p_flags, NACL_PRIxElf_Word);
     154              43 :   NaClLog(2, " (%s %s %s)\n",
     155                 :           (phdr->p_flags & PF_R) ? "PF_R" : "",
     156                 :           (phdr->p_flags & PF_W) ? "PF_W" : "",
     157                 :           (phdr->p_flags & PF_X) ? "PF_X" : "");
     158              43 :   DUMP(p_align, NACL_PRIxElf_Xword);
     159                 : #undef  DUMP
     160              43 :   NaClLog(loglevel, "\n");
     161              43 : }
     162                 : 
     163                 : 
     164              11 : NaClErrorCode NaClElfImageValidateElfHeader(struct NaClElfImage *image) {
     165              11 :   const Elf_Ehdr *hdr = &image->ehdr;
     166                 : 
     167              11 :   if (memcmp(hdr->e_ident, ELFMAG, SELFMAG)) {
     168               0 :     NaClLog(LOG_ERROR, "bad elf magic\n");
     169               0 :     return LOAD_BAD_ELF_MAGIC;
     170                 :   }
     171                 : 
     172              11 :   if (ELFCLASS32 != hdr->e_ident[EI_CLASS]) {
     173               0 :     NaClLog(LOG_ERROR, "bad elf class\n");
     174               0 :     return LOAD_NOT_32_BIT;
     175                 :   }
     176                 : 
     177              11 :   if (ET_EXEC != hdr->e_type) {
     178               0 :     NaClLog(LOG_ERROR, "non executable\n");
     179               0 :     return LOAD_NOT_EXEC;
     180                 :   }
     181                 : 
     182              11 :   if (EM_EXPECTED_BY_NACL != hdr->e_machine) {
     183               0 :     NaClLog(LOG_ERROR, "bad machine: %"NACL_PRIxElf_Half"\n", hdr->e_machine);
     184               0 :     return LOAD_BAD_MACHINE;
     185                 :   }
     186                 : 
     187              11 :   if (EV_CURRENT != hdr->e_version) {
     188               0 :     NaClLog(LOG_ERROR, "bad elf version: %"NACL_PRIxElf_Word"\n",
     189                 :             hdr->e_version);
     190               0 :     return LOAD_BAD_ELF_VERS;
     191                 :   }
     192                 : 
     193              11 :   return LOAD_OK;
     194                 : }
     195                 : 
     196                 : /* TODO(robertm): decouple validation from computation of
     197                 :                    static_text_end and max_vaddr */
     198                 : NaClErrorCode NaClElfImageValidateProgramHeaders(
     199                 :   struct NaClElfImage *image,
     200                 :   uint8_t             addr_bits,
     201                 :   uintptr_t           *static_text_end,
     202                 :   uintptr_t           *rodata_start,
     203                 :   uintptr_t           *rodata_end,
     204                 :   uintptr_t           *data_start,
     205                 :   uintptr_t           *data_end,
     206              11 :   uintptr_t           *max_vaddr) {
     207                 :     /*
     208                 :      * Scan phdrs and do sanity checks in-line.  Verify that the load
     209                 :      * address is NACL_TRAMPOLINE_END, that we have a single text
     210                 :      * segment.  Data and TLS segments are not required, though it is
     211                 :      * hard to avoid with standard tools, but in any case there should
     212                 :      * be at most one each.  Ensure that no segment's vaddr is outside
     213                 :      * of the address space.  Ensure that PT_GNU_STACK is present, and
     214                 :      * that x is off.
     215                 :      */
     216              11 :   const Elf_Ehdr      *hdr = &image->ehdr;
     217              11 :   int                 seen_seg[NACL_ARRAY_SIZE(nacl_phdr_check_data)];
     218                 : 
     219                 :   int                 segnum;
     220                 :   const Elf_Phdr      *php;
     221                 :   size_t              j;
     222                 : 
     223              11 :   *max_vaddr = NACL_TRAMPOLINE_END;
     224                 : 
     225                 :   /*
     226                 :    * nacl_phdr_check_data is small, so O(|check_data| * nap->elf_hdr.e_phum)
     227                 :    * is okay.
     228                 :    */
     229              11 :   memset(seen_seg, 0, sizeof seen_seg);
     230              45 :   for (segnum = 0; segnum < hdr->e_phnum; ++segnum) {
     231              37 :     php = &image->phdrs[segnum];
     232              37 :     NaClLog(3, "Looking at segment %d, type 0x%x, p_flags 0x%x\n",
     233                 :             segnum, php->p_type, php->p_flags);
     234              37 :     if (0 == php->p_memsz) {
     235                 :       /*
     236                 :        * We will not load this segment.
     237                 :        */
     238               0 :       NaClLog(3, "Ignoring empty segment\n");
     239               0 :       continue;
     240                 :     }
     241                 : 
     242              86 :     for (j = 0; j < NACL_ARRAY_SIZE(nacl_phdr_check_data); ++j) {
     243              86 :       if (php->p_type == nacl_phdr_check_data[j].p_type
     244                 :           && php->p_flags == nacl_phdr_check_data[j].p_flags)
     245              37 :         break;
     246                 :     }
     247              37 :     if (j == NACL_ARRAY_SIZE(nacl_phdr_check_data)) {
     248                 :       /* segment not in nacl_phdr_check_data */
     249               0 :       NaClLog(2,
     250                 :               "Segment %d is of unexpected type 0x%x, flag 0x%x\n",
     251                 :               segnum,
     252                 :               php->p_type,
     253                 :               php->p_flags);
     254               0 :       return LOAD_BAD_SEGMENT;
     255                 :     }
     256                 : 
     257              37 :     NaClLog(2, "Matched nacl_phdr_check_data[%"NACL_PRIdS"]\n", j);
     258              37 :     if (seen_seg[j]) {
     259               0 :       NaClLog(2, "Segment %d is a type that has been seen\n", segnum);
     260               0 :       return LOAD_DUP_SEGMENT;
     261                 :     }
     262              37 :     seen_seg[j] = 1;
     263                 : 
     264              37 :     if (PCA_IGNORE == nacl_phdr_check_data[j].action) {
     265              11 :       NaClLog(3, "Ignoring\n");
     266              11 :       continue;
     267                 :     }
     268                 : 
     269                 :     /*
     270                 :      * We will load this segment later.  Do the sanity checks.
     271                 :      */
     272              26 :     if (0 != nacl_phdr_check_data[j].p_vaddr
     273                 :         && (nacl_phdr_check_data[j].p_vaddr != php->p_vaddr)) {
     274               1 :       NaClLog(2,
     275                 :               ("Segment %d: bad virtual address: 0x%08"
     276                 :                NACL_PRIxElf_Addr","
     277                 :                " expected 0x%08"NACL_PRIxElf_Addr"\n"),
     278                 :               segnum,
     279                 :               php->p_vaddr,
     280                 :               nacl_phdr_check_data[j].p_vaddr);
     281               1 :       return LOAD_SEGMENT_BAD_LOC;
     282                 :     }
     283              25 :     if (php->p_vaddr < NACL_TRAMPOLINE_END) {
     284               0 :       NaClLog(2,
     285                 :               ("Segment %d: virtual address (0x%08"NACL_PRIxElf_Addr
     286                 :                ") too low\n"),
     287                 :               segnum,
     288                 :               php->p_vaddr);
     289               0 :       return LOAD_SEGMENT_OUTSIDE_ADDRSPACE;
     290                 :     }
     291              25 :     if (php->p_vaddr >= ((uint64_t) 1U << addr_bits) ||
     292                 :         ((uint64_t) 1U << addr_bits) - php->p_vaddr < php->p_memsz) {
     293               2 :       if (php->p_vaddr + php->p_memsz < php->p_vaddr) {
     294               0 :         NaClLog(2,
     295                 :                 "Segment %d: p_memsz caused integer overflow\n",
     296                 :                 segnum);
     297                 :       } else {
     298               2 :         NaClLog(2,
     299                 :                 "Segment %d: too large, ends at 0x%08"NACL_PRIxElf_Addr"\n",
     300                 :                 segnum,
     301                 :                 php->p_vaddr + php->p_memsz);
     302                 :       }
     303               2 :       return LOAD_SEGMENT_OUTSIDE_ADDRSPACE;
     304                 :     }
     305              23 :     if (php->p_filesz > php->p_memsz) {
     306               0 :       NaClLog(2,
     307                 :               ("Segment %d: file size 0x%08"NACL_PRIxElf_Xword" larger"
     308                 :                " than memory size 0x%08"NACL_PRIxElf_Xword"\n"),
     309                 :               segnum,
     310                 :               php->p_filesz,
     311                 :               php->p_memsz);
     312               0 :       return LOAD_SEGMENT_BAD_PARAM;
     313                 :     }
     314                 : 
     315              23 :     image->loadable[segnum] = 1;
     316                 :     /* record our decision that we will load this segment */
     317                 : 
     318                 :     /*
     319                 :      * NACL_TRAMPOLINE_END <= p_vaddr
     320                 :      *                     <= p_vaddr + p_memsz
     321                 :      *                     < ((uintptr_t) 1U << nap->addr_bits)
     322                 :      */
     323              23 :     if (*max_vaddr < php->p_vaddr + php->p_memsz) {
     324              23 :       *max_vaddr = php->p_vaddr + php->p_memsz;
     325                 :     }
     326                 : 
     327              23 :     switch (nacl_phdr_check_data[j].action) {
     328                 :       case PCA_NONE:
     329               0 :         break;
     330                 :       case PCA_TEXT_CHECK:
     331               8 :         if (0 == php->p_memsz) {
     332               0 :           return LOAD_BAD_ELF_TEXT;
     333                 :         }
     334               8 :         *static_text_end = NACL_TRAMPOLINE_END + php->p_filesz;
     335               8 :         break;
     336                 :       case PCA_RODATA:
     337               7 :         *rodata_start = php->p_vaddr;
     338               7 :         *rodata_end = php->p_vaddr + php->p_memsz;
     339               7 :         break;
     340                 :       case PCA_DATA:
     341               8 :         *data_start = php->p_vaddr;
     342               8 :         *data_end = php->p_vaddr + php->p_memsz;
     343                 :         break;
     344                 :       case PCA_IGNORE:
     345                 :         break;
     346                 :     }
     347                 :   }
     348             104 :   for (j = 0; j < NACL_ARRAY_SIZE(nacl_phdr_check_data); ++j) {
     349              96 :     if (nacl_phdr_check_data[j].required && !seen_seg[j]) {
     350               0 :       return LOAD_REQUIRED_SEG_MISSING;
     351                 :     }
     352                 :   }
     353                 : 
     354                 :   /*
     355                 :    * Memory allocation will use NaClRoundPage(nap->break_addr), but
     356                 :    * the system notion of break is always an exact address.  Even
     357                 :    * though we must allocate and make accessible multiples of pages,
     358                 :    * the linux-style brk system call (which returns current break on
     359                 :    * failure) permits an arbitrarily aligned address as argument.
     360                 :    */
     361                 : 
     362               8 :   return LOAD_OK;
     363                 : }
     364                 : 
     365                 : 
     366                 : struct NaClElfImage *NaClElfImageNew(struct Gio     *gp,
     367              11 :                                      NaClErrorCode  *err_code) {
     368                 :   struct NaClElfImage *result;
     369                 :   struct NaClElfImage image;
     370                 :   union {
     371                 :     Elf32_Ehdr ehdr32;
     372                 : #if NACL_TARGET_SUBARCH == 64
     373                 :     Elf64_Ehdr ehdr64;
     374                 : #endif
     375                 :   } ehdr;
     376                 :   int                 cur_ph;
     377                 : 
     378              11 :   memset(image.loadable, 0, sizeof image.loadable);
     379              11 :   if (-1 == (*gp->vtbl->Seek)(gp, 0, 0)) {
     380               0 :     NaClLog(2, "could not seek to beginning of Gio object containing nexe\n");
     381               0 :     if (NULL != err_code) {
     382               0 :       *err_code = LOAD_READ_ERROR;
     383                 :     }
     384               0 :     return 0;
     385                 :   }
     386                 : 
     387                 :   /*
     388                 :    * We read the larger size of an ELFCLASS64 header even if it turns out
     389                 :    * we're reading an ELFCLASS32 file.  No usable ELFCLASS32 binary could
     390                 :    * be so small that it's not larger than Elf64_Ehdr anyway.
     391                 :    */
     392              11 :   if ((*gp->vtbl->Read)(gp,
     393                 :                         &ehdr,
     394                 :                         sizeof ehdr)
     395                 :       != sizeof ehdr) {
     396               0 :     if (NULL != err_code) {
     397               0 :       *err_code = LOAD_READ_ERROR;
     398                 :     }
     399               0 :     NaClLog(2, "could not load elf headers\n");
     400               0 :     return 0;
     401                 :   }
     402                 : 
     403                 : #if NACL_TARGET_SUBARCH == 64
     404                 :   if (ELFCLASS64 == ehdr.ehdr64.e_ident[EI_CLASS]) {
     405                 :     /*
     406                 :      * Convert ELFCLASS64 format to ELFCLASS32 format.
     407                 :      * The initial four fields are the same in both classes.
     408                 :      */
     409                 :     memcpy(image.ehdr.e_ident, ehdr.ehdr64.e_ident, EI_NIDENT);
     410                 :     image.ehdr.e_ident[EI_CLASS] = ELFCLASS32;
     411                 :     image.ehdr.e_type = ehdr.ehdr64.e_type;
     412                 :     image.ehdr.e_machine = ehdr.ehdr64.e_machine;
     413                 :     image.ehdr.e_version = ehdr.ehdr64.e_version;
     414                 :     if (ehdr.ehdr64.e_entry > 0xffffffffU ||
     415                 :         ehdr.ehdr64.e_phoff > 0xffffffffU ||
     416                 :         ehdr.ehdr64.e_shoff > 0xffffffffU) {
     417                 :       if (NULL != err_code) {
     418                 :         *err_code = LOAD_EHDR_OVERFLOW;
     419                 :       }
     420                 :       NaClLog(2, "ELFCLASS64 file header fields overflow 32 bits\n");
     421                 :       return 0;
     422                 :     }
     423                 :     image.ehdr.e_entry = (Elf32_Addr) ehdr.ehdr64.e_entry;
     424                 :     image.ehdr.e_phoff = (Elf32_Off) ehdr.ehdr64.e_phoff;
     425                 :     image.ehdr.e_shoff = (Elf32_Off) ehdr.ehdr64.e_shoff;
     426                 :     image.ehdr.e_flags = ehdr.ehdr64.e_flags;
     427                 :     if (ehdr.ehdr64.e_ehsize != sizeof(ehdr.ehdr64)) {
     428                 :       if (NULL != err_code) {
     429                 :         *err_code = LOAD_BAD_EHSIZE;
     430                 :       }
     431                 :       NaClLog(2, "ELFCLASS64 file e_ehsize != %d\n", (int) sizeof(ehdr.ehdr64));
     432                 :       return 0;
     433                 :     }
     434                 :     image.ehdr.e_ehsize = sizeof(image.ehdr);
     435                 :     image.ehdr.e_phentsize = sizeof(image.phdrs[0]);
     436                 :     image.ehdr.e_phnum = ehdr.ehdr64.e_phnum;
     437                 :     image.ehdr.e_shentsize = ehdr.ehdr64.e_shentsize;
     438                 :     image.ehdr.e_shnum = ehdr.ehdr64.e_shnum;
     439                 :     image.ehdr.e_shstrndx = ehdr.ehdr64.e_shstrndx;
     440                 :   } else
     441                 : #endif
     442                 :   {
     443              11 :     image.ehdr = ehdr.ehdr32;
     444                 :   }
     445                 : 
     446              11 :   NaClDumpElfHeader(2, &image.ehdr);
     447                 : 
     448                 :   /* read program headers */
     449              11 :   if (image.ehdr.e_phnum > NACL_MAX_PROGRAM_HEADERS) {
     450               0 :     if (NULL != err_code)
     451               0 :       *err_code = LOAD_TOO_MANY_PROG_HDRS;
     452               0 :     NaClLog(2, "too many prog headers\n");
     453               0 :     return 0;
     454                 :   }
     455                 : 
     456              11 :   if ((*gp->vtbl->Seek)(gp,
     457                 :                         (off_t) image.ehdr.e_phoff,
     458                 :                         SEEK_SET) == (off_t) -1) {
     459               0 :     if (NULL != err_code) {
     460               0 :       *err_code = LOAD_READ_ERROR;
     461                 :     }
     462               0 :     NaClLog(2, "cannot seek tp prog headers\n");
     463               0 :     return 0;
     464                 :   }
     465                 : 
     466                 : #if NACL_TARGET_SUBARCH == 64
     467                 :   if (ELFCLASS64 == ehdr.ehdr64.e_ident[EI_CLASS]) {
     468                 :     /*
     469                 :      * We'll load the 64-bit phdrs and convert them to 32-bit format.
     470                 :      */
     471                 :     Elf64_Phdr phdr64[NACL_MAX_PROGRAM_HEADERS];
     472                 : 
     473                 :     if (ehdr.ehdr64.e_phentsize != sizeof(Elf64_Phdr)) {
     474                 :       if (NULL != err_code) {
     475                 :         *err_code = LOAD_BAD_PHENTSIZE;
     476                 :       }
     477                 :       NaClLog(2, "bad prog headers size\n");
     478                 :       NaClLog(2, " ehdr64.e_phentsize = 0x%"NACL_PRIxElf_Half"\n",
     479                 :               ehdr.ehdr64.e_phentsize);
     480                 :       NaClLog(2, "  sizeof(Elf64_Phdr) = 0x%"NACL_PRIxS"\n",
     481                 :               sizeof(Elf64_Phdr));
     482                 :       return 0;
     483                 :     }
     484                 : 
     485                 :     /*
     486                 :      * We know the multiplication won't overflow since we rejected
     487                 :      * e_phnum values larger than the small constant NACL_MAX_PROGRAM_HEADERS.
     488                 :      */
     489                 :     if ((size_t) (*gp->vtbl->Read)(gp,
     490                 :                                    &phdr64[0],
     491                 :                                    image.ehdr.e_phnum * sizeof phdr64[0])
     492                 :         != (image.ehdr.e_phnum * sizeof phdr64[0])) {
     493                 :       if (NULL != err_code) {
     494                 :         *err_code = LOAD_READ_ERROR;
     495                 :       }
     496                 :       NaClLog(2, "cannot load tp prog headers\n");
     497                 :       return 0;
     498                 :     }
     499                 : 
     500                 :     for (cur_ph = 0; cur_ph < image.ehdr.e_phnum; ++cur_ph) {
     501                 :       if (phdr64[cur_ph].p_offset > 0xffffffffU ||
     502                 :           phdr64[cur_ph].p_vaddr > 0xffffffffU ||
     503                 :           phdr64[cur_ph].p_paddr > 0xffffffffU ||
     504                 :           phdr64[cur_ph].p_filesz > 0xffffffffU ||
     505                 :           phdr64[cur_ph].p_memsz > 0xffffffffU ||
     506                 :           phdr64[cur_ph].p_align > 0xffffffffU) {
     507                 :         if (NULL != err_code) {
     508                 :           *err_code = LOAD_PHDR_OVERFLOW;
     509                 :         }
     510                 :         NaClLog(2, "ELFCLASS64 program header fields overflow 32 bits\n");
     511                 :         return 0;
     512                 :       }
     513                 :       image.phdrs[cur_ph].p_type = phdr64[cur_ph].p_type;
     514                 :       image.phdrs[cur_ph].p_offset = (Elf32_Off) phdr64[cur_ph].p_offset;
     515                 :       image.phdrs[cur_ph].p_vaddr = (Elf32_Addr) phdr64[cur_ph].p_vaddr;
     516                 :       image.phdrs[cur_ph].p_paddr = (Elf32_Addr) phdr64[cur_ph].p_paddr;
     517                 :       image.phdrs[cur_ph].p_filesz = (Elf32_Word) phdr64[cur_ph].p_filesz;
     518                 :       image.phdrs[cur_ph].p_memsz = (Elf32_Word) phdr64[cur_ph].p_memsz;
     519                 :       image.phdrs[cur_ph].p_flags = phdr64[cur_ph].p_flags;
     520                 :       image.phdrs[cur_ph].p_align = (Elf32_Word) phdr64[cur_ph].p_align;
     521                 :     }
     522                 :   } else
     523                 : #endif
     524                 :   {
     525              11 :     if (image.ehdr.e_phentsize != sizeof image.phdrs[0]) {
     526               0 :       if (NULL != err_code) {
     527               0 :         *err_code = LOAD_BAD_PHENTSIZE;
     528                 :       }
     529               0 :       NaClLog(2, "bad prog headers size\n");
     530               0 :       NaClLog(2, " image.ehdr.e_phentsize = 0x%"NACL_PRIxElf_Half"\n",
     531                 :               image.ehdr.e_phentsize);
     532               0 :       NaClLog(2, "  sizeof image.phdrs[0] = 0x%"NACL_PRIxS"\n",
     533                 :               sizeof image.phdrs[0]);
     534               0 :       return 0;
     535                 :     }
     536                 : 
     537              11 :     if ((size_t) (*gp->vtbl->Read)(gp,
     538                 :                                    &image.phdrs[0],
     539                 :                                    image.ehdr.e_phnum * sizeof image.phdrs[0])
     540                 :         != (image.ehdr.e_phnum * sizeof image.phdrs[0])) {
     541               0 :       if (NULL != err_code) {
     542               0 :         *err_code = LOAD_READ_ERROR;
     543                 :       }
     544               0 :       NaClLog(2, "cannot load tp prog headers\n");
     545               0 :       return 0;
     546                 :     }
     547                 :   }
     548                 : 
     549              11 :   NaClLog(2, "=================================================\n");
     550              11 :   NaClLog(2, "Elf Program headers\n");
     551              11 :   NaClLog(2, "==================================================\n");
     552              54 :   for (cur_ph = 0; cur_ph <  image.ehdr.e_phnum; ++cur_ph) {
     553              43 :     NaClDumpElfProgramHeader(2, &image.phdrs[cur_ph]);
     554                 :   }
     555                 : 
     556                 :   /* we delay allocating till the end to avoid cleanup code */
     557              11 :   result = malloc(sizeof image);
     558              11 :   if (result == 0) {
     559               0 :     if (NULL != err_code) {
     560               0 :       *err_code = LOAD_NO_MEMORY;
     561                 :     }
     562               0 :     NaClLog(LOG_FATAL, "no enough memory for image meta data\n");
     563               0 :     return 0;
     564                 :   }
     565              11 :   memcpy(result, &image, sizeof image);
     566              11 :   return result;
     567                 : }
     568                 : 
     569                 : 
     570                 : NaClErrorCode NaClElfImageLoad(struct NaClElfImage *image,
     571                 :                                struct Gio          *gp,
     572                 :                                uint8_t             addr_bits,
     573               3 :                                uintptr_t           mem_start) {
     574                 :   int               segnum;
     575                 :   uintptr_t         paddr;
     576                 :   uintptr_t         end_vaddr;
     577                 : 
     578              15 :   for (segnum = 0; segnum < image->ehdr.e_phnum; ++segnum) {
     579              12 :     const Elf_Phdr *php = &image->phdrs[segnum];
     580                 : 
     581                 :     /* did we decide that we will load this segment earlier? */
     582              12 :     if (!image->loadable[segnum]) {
     583               3 :       continue;
     584                 :     }
     585                 : 
     586               9 :     NaClLog(2, "loading segment %d\n", segnum);
     587                 : 
     588               9 :     if (0 == php->p_filesz) {
     589               0 :       NaClLog(4, "zero-sized segment.  ignoring...\n");
     590               0 :       continue;
     591                 :     }
     592                 : 
     593               9 :     end_vaddr = php->p_vaddr + php->p_filesz;
     594                 :     /* integer overflow? */
     595               9 :     if (end_vaddr < php->p_vaddr) {
     596               0 :       NaClLog(LOG_FATAL, "parameter error should have been detected already\n");
     597                 :     }
     598                 :     /*
     599                 :      * is the end virtual address within the NaCl application's
     600                 :      * address space?  if it is, it implies that the start virtual
     601                 :      * address is also.
     602                 :      */
     603               9 :     if (end_vaddr >= ((uintptr_t) 1U << addr_bits)) {
     604               0 :       NaClLog(LOG_FATAL, "parameter error should have been detected already\n");
     605                 :     }
     606                 : 
     607               9 :     paddr = mem_start + php->p_vaddr;
     608                 : 
     609               9 :     NaClLog(4,
     610                 :             "Seek to position %"NACL_PRIdElf_Off" (0x%"NACL_PRIxElf_Off").\n",
     611                 :             php->p_offset,
     612                 :             php->p_offset);
     613                 : 
     614                 :     /*
     615                 :      * NB: php->p_offset may not be a valid off_t on 64-bit systems, but
     616                 :      * in that case Seek() will error out.
     617                 :      */
     618               9 :     if ((*gp->vtbl->Seek)(gp, (off_t) php->p_offset, SEEK_SET) == (off_t) -1) {
     619               0 :       NaClLog(LOG_ERROR, "seek failure segment %d", segnum);
     620               0 :       return LOAD_SEGMENT_BAD_PARAM;
     621                 :     }
     622               9 :     NaClLog(4,
     623                 :             "Reading %"NACL_PRIdElf_Xword" (0x%"NACL_PRIxElf_Xword") bytes to"
     624                 :             " address 0x%"NACL_PRIxPTR"\n",
     625                 :             php->p_filesz,
     626                 :             php->p_filesz,
     627                 :             paddr);
     628                 : 
     629                 :     /*
     630                 :      * Tell valgrind that this memory is accessible and undefined. For more
     631                 :      * details see
     632                 :      * http://code.google.com/p/nativeclient/wiki/ValgrindMemcheck#Implementation_details
     633                 :      */
     634                 :     NACL_MAKE_MEM_UNDEFINED((void *) paddr, php->p_filesz);
     635                 : 
     636               9 :     if ((Elf_Word) (*gp->vtbl->Read)(gp, (void *) paddr, php->p_filesz)
     637                 :         != php->p_filesz) {
     638               0 :       NaClLog(LOG_ERROR, "load failure segment %d", segnum);
     639               0 :       return LOAD_SEGMENT_BAD_PARAM;
     640                 :     }
     641                 :     /* region from p_filesz to p_memsz should already be zero filled */
     642                 : 
     643                 :     /* Tell Valgrind that we've mapped a segment of nacl_file. */
     644               9 :     NaClFileMappingForValgrind(paddr, php->p_filesz, php->p_offset);
     645                 :   }
     646                 : 
     647               3 :   return LOAD_OK;
     648                 : }
     649                 : 
     650                 : 
     651                 : NaClErrorCode NaClElfImageLoadDynamically(struct NaClElfImage *image,
     652                 :                                           struct NaClApp      *nap,
     653               0 :                                           struct Gio          *gfile) {
     654                 :   int segnum;
     655               0 :   for (segnum = 0; segnum < image->ehdr.e_phnum; ++segnum) {
     656               0 :     const Elf_Phdr *php = &image->phdrs[segnum];
     657                 :     int32_t result;
     658                 : 
     659                 :     /*
     660                 :      * We check for PT_LOAD directly rather than using the "loadable"
     661                 :      * array because we are not using NaClElfImageValidateProgramHeaders()
     662                 :      * to fill out the "loadable" array for this ELF object.  This ELF
     663                 :      * object does not have to fit such strict constraints (such as
     664                 :      * having code at 0x20000), and safety checks are applied by
     665                 :      * NaClTextDyncodeCreate() and NaClCommonSysMmapIntern().
     666                 :      */
     667               0 :     if (PT_LOAD != php->p_type) {
     668               0 :       continue;
     669                 :     }
     670                 : 
     671                 :     /*
     672                 :      * Ideally, Gio would have a Pread() method which we would use
     673                 :      * instead of Seek().  In practice, though, there is no
     674                 :      * Seek()/Read() race condition here because both
     675                 :      * GioMemoryFileSnapshot and NaClGioShm use a seek position that
     676                 :      * is local and not shared between processes.
     677                 :      */
     678               0 :     if ((*gfile->vtbl->Seek)(gfile, (off_t) php->p_offset,
     679                 :                              SEEK_SET) == (off_t) -1) {
     680               0 :       NaClLog(1, "NaClElfImageLoadDynamically: seek failed\n");
     681               0 :       return LOAD_READ_ERROR;
     682                 :     }
     683                 : 
     684               0 :     if (0 != (php->p_flags & PF_X)) {
     685                 :       /* Load code segment. */
     686                 :       /*
     687                 :        * We make a copy of the code.  This is not ideal given that
     688                 :        * GioMemoryFileSnapshot and NaClGioShm already have a copy of
     689                 :        * the file in memory or mmapped.
     690                 :        * TODO(mseaborn): Reduce the amount of copying here.
     691                 :        */
     692               0 :       char *code_copy = malloc(php->p_filesz);
     693               0 :       if (NULL == code_copy) {
     694               0 :         NaClLog(1, "NaClElfImageLoadDynamically: malloc failed\n");
     695               0 :         return LOAD_NO_MEMORY;
     696                 :       }
     697               0 :       if ((Elf_Word) (*gfile->vtbl->Read)(gfile, code_copy, php->p_filesz)
     698                 :           != php->p_filesz) {
     699               0 :         free(code_copy);
     700               0 :         NaClLog(1, "NaClElfImageLoadDynamically: "
     701                 :                 "failed to read code segment\n");
     702               0 :         return LOAD_READ_ERROR;
     703                 :       }
     704               0 :       result = NaClTextDyncodeCreate(nap, (uint32_t) php->p_vaddr,
     705                 :                                      code_copy, (uint32_t) php->p_filesz);
     706               0 :       free(code_copy);
     707               0 :       if (0 != result) {
     708               0 :         NaClLog(1, "NaClElfImageLoadDynamically: "
     709                 :                 "failed to load code segment\n");
     710               0 :         return LOAD_UNLOADABLE;
     711                 :       }
     712                 :     } else {
     713                 :       /* Load data segment. */
     714               0 :       void *paddr = (void *) NaClUserToSys(nap, php->p_vaddr);
     715               0 :       size_t mapping_size = NaClRoundAllocPage(php->p_memsz);
     716                 :       /*
     717                 :        * Note that we do not used NACL_ABI_MAP_FIXED because we do not
     718                 :        * want to silently overwrite any existing mappings, such as the
     719                 :        * user app's data segment or the stack.  We detect overmapping
     720                 :        * when mmap chooses not to use the preferred address we supply.
     721                 :        * (Ideally mmap would provide a MAP_EXCL option for this
     722                 :        * instead.)
     723                 :        */
     724               0 :       result = NaClCommonSysMmapIntern(
     725                 :           nap, (void *) (uintptr_t) php->p_vaddr, mapping_size,
     726                 :           NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
     727                 :           NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE,
     728                 :           -1, 0);
     729               0 :       if ((int32_t) php->p_vaddr != result) {
     730               0 :         NaClLog(1, "NaClElfImageLoadDynamically: failed to map data segment\n");
     731               0 :         return LOAD_UNLOADABLE;
     732                 :       }
     733               0 :       if ((Elf_Word) (*gfile->vtbl->Read)(gfile, paddr, php->p_filesz)
     734                 :           != php->p_filesz) {
     735               0 :         NaClLog(1, "NaClElfImageLoadDynamically: "
     736                 :                 "failed to read data segment\n");
     737               0 :         return LOAD_READ_ERROR;
     738                 :       }
     739                 :       /*
     740                 :        * Note that we do not need to zero the BSS (the region from
     741                 :        * p_filesz to p_memsz) because it should already be zero
     742                 :        * filled.  This would not be the case if we were mapping the
     743                 :        * data segment from the file.
     744                 :        */
     745                 : 
     746               0 :       if (0 == (php->p_flags & PF_W)) {
     747                 :         /* Handle read-only data segment. */
     748               0 :         int rc = NaCl_mprotect(paddr, mapping_size, NACL_ABI_PROT_READ);
     749               0 :         if (0 != rc) {
     750               0 :           NaClLog(1, "NaClElfImageLoadDynamically: "
     751                 :                   "failed to mprotect read-only data segment\n");
     752               0 :           return LOAD_MPROTECT_FAIL;
     753                 :         }
     754                 : 
     755               0 :         NaClVmmapUpdate(&nap->mem_map,
     756                 :                         php->p_vaddr >> NACL_PAGESHIFT,
     757                 :                         mapping_size >> NACL_PAGESHIFT,
     758                 :                         PROT_READ,
     759                 :                         NULL,
     760                 :                         0  /* remove: false */);
     761                 :       }
     762                 :     }
     763                 :   }
     764               0 :   return LOAD_OK;
     765                 : }
     766                 : 
     767                 : 
     768              11 : void NaClElfImageDelete(struct NaClElfImage *image) {
     769              11 :   free(image);
     770              11 : }
     771                 : 
     772                 : 
     773               8 : uintptr_t NaClElfImageGetEntryPoint(struct NaClElfImage *image) {
     774               8 :   return image->ehdr.e_entry;
     775                 : }

Generated by: LCOV version 1.7