LCOV - code coverage report
Current view: directory - src/trusted/validator - ncfileutil.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 132 0 0.0 %
Date: 2014-09-25 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                 :  * ncfileutil.c - open an executable file. FOR TESTING ONLY.
       9                 :  */
      10                 : 
      11                 : #include "native_client/src/trusted/validator/ncfileutil.h"
      12                 : 
      13                 : #include "native_client/src/include/portability.h"
      14                 : 
      15                 : #include <stdarg.h>
      16                 : #include <stdio.h>
      17                 : #include <stdlib.h>
      18                 : #include <string.h>
      19                 : #include <assert.h>
      20                 : #include <errno.h>
      21                 : #include <fcntl.h>
      22                 : #include <sys/types.h>
      23                 : 
      24                 : #include "native_client/src/include/portability_io.h"
      25                 : 
      26                 : /* This module is intended for testing use only, not for production use */
      27                 : /* in sel_ldr. To prevent unintended production usage, define a symbol  */
      28                 : /* that will cause a load-time error for sel_ldr.                       */
      29                 : int gNaClValidateImage_foo = 0;
      30               0 : void NaClValidateImage(void) { gNaClValidateImage_foo += 1; }
      31                 : 
      32                 : static void NcLoadFilePrintError(const char* format, ...)
      33                 :     ATTRIBUTE_FORMAT_PRINTF(1, 2);
      34                 : 
      35                 : /* Define the default print error function to use for this module. */
      36               0 : static void NcLoadFilePrintError(const char* format, ...) {
      37                 :   va_list ap;
      38               0 :   va_start(ap, format);
      39               0 :   vfprintf(stderr, format, ap);
      40               0 :   va_end(ap);
      41               0 : }
      42                 : 
      43                 : /***********************************************************************/
      44                 : /* THIS ROUTINE IS FOR DEBUGGING/TESTING ONLY, NOT FOR SECURE RUNTIME  */
      45                 : /* ALL PAGES ARE LEFT WRITEABLE BY THIS LOADER.                        */
      46                 : /***********************************************************************/
      47                 : /* Loading a NC executable from a host file */
      48                 : static off_t readat(ncfile* ncf, const int fd,
      49               0 :                     void *buf, const off_t sz, const off_t at) {
      50                 :   /* TODO(karl) fix types for off_t and size_t so that the work for 64-bits */
      51               0 :   int sofar = 0;
      52                 :   int nread;
      53               0 :   char *cbuf = (char *) buf;
      54                 : 
      55               0 :   if (0 > lseek(fd, (long) at, SEEK_SET)) {
      56               0 :     ncf->error_fn("readat: lseek failed\n");
      57               0 :     return -1;
      58                 :   }
      59                 : 
      60                 :   /* TODO(robertm) Figure out if O_BINARY flag fixes this. */
      61                 :   /* Strangely this loop is needed on Windows. It seems the read()   */
      62                 :   /* implementation doesn't always return as many bytes as requested */
      63                 :   /* so you have to keep on trying.                                  */
      64                 :   do {
      65               0 :     nread = read(fd, &cbuf[sofar], sz - sofar);
      66               0 :     if (nread <= 0) {
      67               0 :       ncf->error_fn("readat: read failed\n");
      68               0 :       return -1;
      69                 :     }
      70               0 :     sofar += nread;
      71               0 :   } while (sz != sofar);
      72               0 :   return nread;
      73               0 : }
      74                 : 
      75               0 : static const char* GetEiClassName(unsigned char c) {
      76               0 :   if (c == ELFCLASS32) {
      77               0 :     return "(32 bit executable)";
      78               0 :   } else if (c == ELFCLASS64) {
      79               0 :     return "(64 bit executable)";
      80                 :   } else {
      81               0 :     return "(invalid class)";
      82                 :   }
      83               0 : }
      84                 : 
      85               0 : static int nc_load(ncfile *ncf, int fd) {
      86                 :   union {
      87                 :     Elf32_Ehdr h32;
      88                 : #if NACL_TARGET_SUBARCH == 64
      89                 :     Elf64_Ehdr h64;
      90                 : #endif
      91                 :   } h;
      92                 :   Elf_Half phnum;
      93                 :   Elf_Half shnum;
      94                 :   Elf_Off phoff;
      95                 :   Elf_Off shoff;
      96                 :   ssize_t nread;
      97                 :   Elf_Addr vmemlo, vmemhi;
      98                 :   size_t shsize, phsize;
      99                 :   int i;
     100                 : 
     101                 :   /* Read and check the ELF header */
     102               0 :   nread = readat(ncf, fd, &h, sizeof(h), 0);
     103               0 :   if (nread < 0 || (size_t) nread < sizeof(h)) {
     104               0 :     ncf->error_fn("nc_load(%s): could not read ELF header", ncf->fname);
     105               0 :     return -1;
     106                 :   }
     107                 : 
     108                 :   /* do a bunch of sanity checks */
     109               0 :   if (memcmp(h.h32.e_ident, ELFMAG, SELFMAG)) {
     110               0 :     ncf->error_fn("nc_load(%s): bad magic number", ncf->fname);
     111               0 :     return -1;
     112                 :   }
     113                 : 
     114                 : #if NACL_TARGET_SUBARCH == 64
     115                 :   if (h.h32.e_ident[EI_CLASS] == ELFCLASS64) {
     116                 :     if (h.h64.e_phoff > 0xffffffffU) {
     117                 :       ncf->error_fn("nc_load(%s): e_phoff overflows 32 bits\n", ncf->fname);
     118                 :       return -1;
     119                 :     }
     120                 :     if (h.h64.e_shoff > 0xffffffffU) {
     121                 :       ncf->error_fn("nc_load(%s): e_shoff overflows 32 bits\n", ncf->fname);
     122                 :       return -1;
     123                 :     }
     124                 :     phoff = (Elf32_Off) h.h64.e_phoff;
     125                 :     shoff = (Elf32_Off) h.h64.e_shoff;
     126                 :     phnum = h.h64.e_phnum;
     127                 :     shnum = h.h64.e_shnum;
     128                 :   } else
     129                 : #endif
     130                 :   {
     131               0 :     if (h.h32.e_ident[EI_CLASS] == ELFCLASS32) {
     132               0 :       phoff = h.h32.e_phoff;
     133               0 :       shoff = h.h32.e_shoff;
     134               0 :       phnum = h.h32.e_phnum;
     135               0 :       shnum = h.h32.e_shnum;
     136               0 :     } else {
     137                 :       ncf->error_fn("nc_load(%s): bad EI CLASS %d %s\n", ncf->fname,
     138                 :                     h.h32.e_ident[EI_CLASS],
     139               0 :                     GetEiClassName(h.h32.e_ident[EI_CLASS]));
     140               0 :       return -1;
     141                 :     }
     142                 :   }
     143                 : 
     144                 :   /* Read the program header table */
     145               0 :   if (phnum <= 0 || phnum > kMaxPhnum) {
     146                 :     ncf->error_fn("nc_load(%s): e_phnum %d > kMaxPhnum %d\n",
     147               0 :                   ncf->fname, phnum, kMaxPhnum);
     148               0 :     return -1;
     149                 :   }
     150               0 :   ncf->phnum = phnum;
     151               0 :   ncf->pheaders = (Elf_Phdr *)calloc(phnum, sizeof(Elf_Phdr));
     152               0 :   if (NULL == ncf->pheaders) {
     153                 :     ncf->error_fn("nc_load(%s): calloc(%d, %"NACL_PRIuS") failed\n",
     154               0 :                   ncf->fname, phnum, sizeof(Elf_Phdr));
     155               0 :     return -1;
     156                 :   }
     157               0 :   phsize = phnum * sizeof(*ncf->pheaders);
     158                 : #if NACL_TARGET_SUBARCH == 64
     159                 :   if (h.h32.e_ident[EI_CLASS] == ELFCLASS64) {
     160                 :     /*
     161                 :      * Read 64-bit program headers and convert them.
     162                 :      */
     163                 :     Elf64_Phdr phdr64[kMaxPhnum];
     164                 :     nread = readat(ncf, fd, phdr64, (off_t) (phnum * sizeof(phdr64[0])),
     165                 :                    (off_t) phoff);
     166                 :     if (nread < 0 || (size_t) nread < phsize) return -1;
     167                 :     for (i = 0; i < phnum; ++i) {
     168                 :       if (phdr64[i].p_offset > 0xffffffffU ||
     169                 :           phdr64[i].p_vaddr > 0xffffffffU ||
     170                 :           phdr64[i].p_paddr > 0xffffffffU ||
     171                 :           phdr64[i].p_filesz > 0xffffffffU ||
     172                 :           phdr64[i].p_memsz > 0xffffffffU ||
     173                 :           phdr64[i].p_align > 0xffffffffU) {
     174                 :         ncf->error_fn("nc_load(%s): phdr[%d] fields overflow 32 bits\n",
     175                 :                       ncf->fname, i);
     176                 :         return -1;
     177                 :       }
     178                 :       ncf->pheaders[i].p_type = phdr64[i].p_type;
     179                 :       ncf->pheaders[i].p_flags = phdr64[i].p_flags;
     180                 :       ncf->pheaders[i].p_offset = (Elf32_Off) phdr64[i].p_offset;
     181                 :       ncf->pheaders[i].p_vaddr = (Elf32_Addr) phdr64[i].p_vaddr;
     182                 :       ncf->pheaders[i].p_paddr = (Elf32_Addr) phdr64[i].p_paddr;
     183                 :       ncf->pheaders[i].p_filesz = (Elf32_Word) phdr64[i].p_filesz;
     184                 :       ncf->pheaders[i].p_memsz = (Elf32_Word) phdr64[i].p_memsz;
     185                 :       ncf->pheaders[i].p_align = (Elf32_Word) phdr64[i].p_align;
     186                 :     }
     187                 :   } else
     188                 : #endif
     189                 :   {
     190                 :     /* TODO(karl) Remove the cast to size_t, or verify size. */
     191               0 :     nread = readat(ncf, fd, ncf->pheaders, (off_t) phsize, (off_t) phoff);
     192               0 :     if (nread < 0 || (size_t) nread < phsize) return -1;
     193                 :   }
     194                 : 
     195                 :   /* Iterate through the program headers to find the virtual */
     196                 :   /* size of loaded text.                                    */
     197               0 :   vmemlo = MAX_ELF_ADDR;
     198               0 :   vmemhi = MIN_ELF_ADDR;
     199               0 :   for (i = 0; i < phnum; i++) {
     200               0 :     if (ncf->pheaders[i].p_type != PT_LOAD) continue;
     201               0 :     if (0 == (ncf->pheaders[i].p_flags & PF_X)) continue;
     202                 :     /* This is executable text. Check low and high addrs */
     203               0 :     if (vmemlo > ncf->pheaders[i].p_vaddr) vmemlo = ncf->pheaders[i].p_vaddr;
     204               0 :     if (vmemhi < ncf->pheaders[i].p_vaddr + ncf->pheaders[i].p_memsz) {
     205               0 :       vmemhi = ncf->pheaders[i].p_vaddr + ncf->pheaders[i].p_memsz;
     206                 :     }
     207               0 :   }
     208               0 :   ncf->size = vmemhi - vmemlo;
     209               0 :   ncf->vbase = vmemlo;
     210                 :   /* TODO(karl) Remove the cast to size_t, or verify size. */
     211               0 :   ncf->data = (uint8_t *)calloc(1, (size_t) ncf->size);
     212               0 :   if (NULL == ncf->data) {
     213                 :     ncf->error_fn("nc_load(%s): calloc(1, %d) failed\n",
     214               0 :                   ncf->fname, (int)ncf->size);
     215               0 :     return -1;
     216                 :   }
     217                 : 
     218                 :   /* Load program text segments */
     219               0 :   for (i = 0; i < phnum; i++) {
     220               0 :     const Elf_Phdr *p = &ncf->pheaders[i];
     221               0 :     if (p->p_type != PT_LOAD) continue;
     222               0 :     if (0 == (ncf->pheaders[i].p_flags & PF_X)) continue;
     223                 : 
     224                 :     /* TODO(karl) Remove the cast to off_t, or verify value in range. */
     225                 :     nread = readat(ncf, fd, &(ncf->data[p->p_vaddr - ncf->vbase]),
     226               0 :                    (off_t) p->p_filesz, (off_t) p->p_offset);
     227               0 :     if (nread < 0 || (size_t) nread < p->p_filesz) {
     228                 :       ncf->error_fn(
     229                 :           "nc_load(%s): could not read segment %d (%d < %"
     230                 :           NACL_PRIuElf_Xword")\n",
     231               0 :           ncf->fname, i, (int)nread, p->p_filesz);
     232               0 :       return -1;
     233                 :     }
     234               0 :   }
     235                 : 
     236                 :   /* load the section headers */
     237               0 :   ncf->shnum = shnum;
     238               0 :   shsize = ncf->shnum * sizeof(*ncf->sheaders);
     239               0 :   ncf->sheaders = (Elf_Shdr *)calloc(1, shsize);
     240               0 :   if (NULL == ncf->sheaders) {
     241                 :     ncf->error_fn("nc_load(%s): calloc(1, %"NACL_PRIuS") failed\n",
     242               0 :                   ncf->fname, shsize);
     243               0 :     return -1;
     244                 :   }
     245                 : #if NACL_TARGET_SUBARCH == 64
     246                 :   if (h.h32.e_ident[EI_CLASS] == ELFCLASS64) {
     247                 :     /*
     248                 :      * Read 64-bit section headers and convert them.
     249                 :      */
     250                 :     Elf64_Shdr *shdr64 = (Elf64_Shdr *)calloc(shnum, sizeof(shdr64[0]));
     251                 :     if (NULL == shdr64) {
     252                 :       ncf->error_fn(
     253                 :           "nc_load(%s): calloc(%"NACL_PRIdS", %"NACL_PRIdS") failed\n",
     254                 :           ncf->fname, (size_t) shnum, sizeof(shdr64[0]));
     255                 :       return -1;
     256                 :     }
     257                 :     shsize = ncf->shnum * sizeof(shdr64[0]);
     258                 :     nread = readat(ncf, fd, shdr64, (off_t) shsize, (off_t) shoff);
     259                 :     if (nread < 0 || (size_t) nread < shsize) {
     260                 :       ncf->error_fn("nc_load(%s): could not read section headers\n",
     261                 :                     ncf->fname);
     262                 :       return -1;
     263                 :     }
     264                 :     for (i = 0; i < shnum; ++i) {
     265                 :       if (shdr64[i].sh_flags > 0xffffffffU ||
     266                 :           shdr64[i].sh_size > 0xffffffffU ||
     267                 :           shdr64[i].sh_addralign > 0xffffffffU ||
     268                 :           shdr64[i].sh_entsize > 0xffffffffU) {
     269                 :         ncf->error_fn("nc_load(%s): shdr[%d] fields overflow 32 bits\n",
     270                 :                       ncf->fname, i);
     271                 :         return -1;
     272                 :       }
     273                 :       ncf->sheaders[i].sh_name = shdr64[i].sh_name;
     274                 :       ncf->sheaders[i].sh_type = shdr64[i].sh_type;
     275                 :       ncf->sheaders[i].sh_flags = (Elf32_Word) shdr64[i].sh_flags;
     276                 :       ncf->sheaders[i].sh_addr = (Elf32_Addr) shdr64[i].sh_addr;
     277                 :       ncf->sheaders[i].sh_offset = (Elf32_Off) shdr64[i].sh_offset;
     278                 :       ncf->sheaders[i].sh_size = (Elf32_Word) shdr64[i].sh_size;
     279                 :       ncf->sheaders[i].sh_link = shdr64[i].sh_link;
     280                 :       ncf->sheaders[i].sh_info = shdr64[i].sh_info;
     281                 :       ncf->sheaders[i].sh_addralign = (Elf32_Word) shdr64[i].sh_addralign;
     282                 :       ncf->sheaders[i].sh_entsize = (Elf32_Word) shdr64[i].sh_entsize;
     283                 :     }
     284                 :     free(shdr64);
     285                 :   } else
     286                 : #endif
     287                 :   {
     288                 :     /* TODO(karl) Remove the cast to size_t, or verify value in range. */
     289               0 :     nread = readat(ncf, fd, ncf->sheaders, (off_t) shsize, (off_t) shoff);
     290               0 :     if (nread < 0 || (size_t) nread < shsize) {
     291                 :       ncf->error_fn("nc_load(%s): could not read section headers\n",
     292               0 :                     ncf->fname);
     293               0 :       return -1;
     294                 :     }
     295                 :   }
     296                 : 
     297                 :   /* success! */
     298               0 :   return 0;
     299               0 : }
     300                 : 
     301                 : ncfile *nc_loadfile_depending(const char *filename,
     302               0 :                               nc_loadfile_error_fn error_fn) {
     303                 :   ncfile *ncf;
     304                 :   int fd;
     305               0 :   int rdflags = O_RDONLY | _O_BINARY;
     306               0 :   fd = OPEN(filename, rdflags);
     307               0 :   if (fd < 0) return NULL;
     308                 : 
     309                 :   /* Allocate the ncfile structure */
     310               0 :   ncf = calloc(1, sizeof(ncfile));
     311               0 :   if (ncf == NULL) return NULL;
     312               0 :   ncf->size = 0;
     313               0 :   ncf->data = NULL;
     314               0 :   ncf->fname = filename;
     315               0 :   if (error_fn == NULL) {
     316               0 :     ncf->error_fn = NcLoadFilePrintError;
     317               0 :   } else {
     318               0 :     ncf->error_fn = error_fn;
     319                 :   }
     320                 : 
     321               0 :   if (nc_load(ncf, fd) < 0) {
     322               0 :     close(fd);
     323               0 :     free(ncf);
     324               0 :     return NULL;
     325                 :   }
     326               0 :   close(fd);
     327               0 :   return ncf;
     328               0 : }
     329                 : 
     330               0 : ncfile *nc_loadfile(const char *filename) {
     331               0 :   return nc_loadfile_depending(filename, NULL);
     332               0 : }
     333                 : 
     334                 : ncfile *nc_loadfile_with_error_fn(const char *filename,
     335               0 :                                   nc_loadfile_error_fn error_fn) {
     336               0 :   return nc_loadfile_depending(filename, error_fn);
     337               0 : }
     338                 : 
     339                 : 
     340               0 : void nc_freefile(ncfile *ncf) {
     341               0 :   if (ncf->data != NULL) free(ncf->data);
     342               0 :   free(ncf);
     343               0 : }
     344                 : 
     345                 : /***********************************************************************/
     346                 : 
     347                 : void GetVBaseAndLimit(ncfile *ncf, NaClPcAddress *vbase,
     348               0 :                       NaClPcAddress *vlimit) {
     349                 :   int ii;
     350                 :   /* TODO(karl) - Define so constant applies to 64-bit pc address. */
     351               0 :   NaClPcAddress base = 0xffffffff;
     352               0 :   NaClPcAddress limit = 0;
     353                 : 
     354               0 :   for (ii = 0; ii < ncf->shnum; ii++) {
     355               0 :     if ((ncf->sheaders[ii].sh_flags & SHF_EXECINSTR) == SHF_EXECINSTR) {
     356               0 :       if (ncf->sheaders[ii].sh_addr < base) base = ncf->sheaders[ii].sh_addr;
     357               0 :       if (ncf->sheaders[ii].sh_addr + ncf->sheaders[ii].sh_size > limit)
     358               0 :         limit = ncf->sheaders[ii].sh_addr + ncf->sheaders[ii].sh_size;
     359                 :     }
     360               0 :   }
     361               0 :   *vbase = base;
     362               0 :   *vlimit = limit;
     363               0 : }

Generated by: LCOV version 1.7