LCOV - code coverage report
Current view: directory - src/trusted/service_runtime - sel_addrspace.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 80 54 67.5 %
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 Simple/secure ELF loader (NaCl SEL).
       9                 :  */
      10                 : 
      11                 : #include <errno.h>
      12                 : 
      13                 : #include "native_client/src/include/nacl_platform.h"
      14                 : #include "native_client/src/include/portability.h"
      15                 : #include "native_client/src/shared/platform/nacl_log.h"
      16                 : #include "native_client/src/trusted/service_runtime/sel_addrspace.h"
      17                 : #include "native_client/src/trusted/service_runtime/sel_ldr.h"
      18                 : #include "native_client/src/trusted/service_runtime/sel_memory.h"
      19                 : #include "native_client/src/trusted/service_runtime/sel_util.h"
      20                 : 
      21                 : 
      22               4 : NaClErrorCode NaClAllocAddrSpace(struct NaClApp *nap) {
      23                 :   void        *mem;
      24                 :   int         rv;
      25                 :   uintptr_t   hole_start;
      26                 :   size_t      hole_size;
      27                 :   uintptr_t   stack_start;
      28                 : 
      29               4 :   NaClLog(2,
      30                 :           "NaClAllocAddrSpace: calling NaClAllocateSpace(*,0x%016"
      31                 :           NACL_PRIxS")\n",
      32                 :           ((size_t) 1 << nap->addr_bits));
      33                 : 
      34               4 :   rv = NaClAllocateSpace(&mem, (uintptr_t) 1U << nap->addr_bits);
      35               4 :   if (LOAD_OK != rv) {
      36               0 :     return rv;
      37                 :   }
      38                 : 
      39               4 :   nap->mem_start = (uintptr_t) mem;
      40                 :   /*
      41                 :    * The following should not be NaClLog(2, ...) because logging with
      42                 :    * any detail level higher than LOG_INFO is disabled in the release
      43                 :    * builds.  This was to reduce logging overhead, so as to eliminate
      44                 :    * at least a function call as well as possibly a TLS/TSD read if
      45                 :    * module-specific logging verbosity level comparisons are needed.
      46                 :    */
      47               4 :   NaClLog(LOG_INFO,
      48                 :           ("Native Client module will be loaded at"
      49                 :            " base address 0x%016"NACL_PRIxPTR"\n"),
      50                 :           nap->mem_start);
      51                 : 
      52               4 :   hole_start = NaClRoundAllocPage(nap->data_end);
      53                 : 
      54               4 :   if (nap->stack_size >= ((uintptr_t) 1U) << nap->addr_bits) {
      55               0 :     NaClLog(LOG_FATAL, "NaClAllocAddrSpace: stack too large!");
      56                 :   }
      57               4 :   stack_start = (((uintptr_t) 1U) << nap->addr_bits) - nap->stack_size;
      58               4 :   stack_start = NaClTruncAllocPage(stack_start);
      59                 : 
      60               4 :   if (stack_start < hole_start) {
      61               1 :     return LOAD_DATA_OVERLAPS_STACK_SECTION;
      62                 :   }
      63                 : 
      64               3 :   hole_size = stack_start - hole_start;
      65               3 :   hole_size = NaClTruncAllocPage(hole_size);
      66                 : 
      67                 :   /*
      68                 :    * mprotect and madvise unused data space to "free" it up, but
      69                 :    * retain mapping so no other memory can be mapped into those
      70                 :    * addresses.
      71                 :    */
      72               3 :   if (hole_size == 0) {
      73               0 :     NaClLog(2, ("NaClAllocAddrSpace: hole between end of data and"
      74                 :                 " the beginning of stack is zero size.\n"));
      75                 :   } else {
      76               3 :     NaClLog(2,
      77                 :             ("madvising 0x%08"NACL_PRIxPTR", 0x%08"NACL_PRIxS
      78                 :              ", MADV_DONTNEED\n"),
      79                 :             nap->mem_start + hole_start, hole_size);
      80               3 :     if (0 != NaCl_madvise((void *) (nap->mem_start + hole_start),
      81                 :                           hole_size,
      82                 :                           MADV_DONTNEED)) {
      83               0 :       NaClLog(1, "madvise, errno %d\n", errno);
      84               0 :       return LOAD_MADVISE_FAIL;
      85                 :     }
      86               3 :     NaClLog(2,
      87                 :             "mprotecting 0x%08"NACL_PRIxPTR", 0x%08"NACL_PRIxS", PROT_NONE\n",
      88                 :             nap->mem_start + hole_start, hole_size);
      89               3 :     if (0 != NaCl_mprotect((void *) (nap->mem_start + hole_start),
      90                 :                            hole_size,
      91                 :                            PROT_NONE)) {
      92               0 :       NaClLog(1, "mprotect, errno %d\n", errno);
      93               0 :       return LOAD_MPROTECT_FAIL;
      94                 :     }
      95                 :   }
      96                 : 
      97               3 :   return LOAD_OK;
      98                 : }
      99                 : 
     100                 : 
     101                 : /*
     102                 :  * Apply memory protection to memory regions.
     103                 :  */
     104               3 : NaClErrorCode NaClMemoryProtection(struct NaClApp *nap) {
     105                 :   uintptr_t start_addr;
     106                 :   size_t    region_size;
     107                 :   int       err;
     108                 : 
     109                 :   /*
     110                 :    * The first NACL_SYSCALL_START_ADDR bytes are mapped as PROT_NONE.
     111                 :    * This enables NULL pointer checking, and provides additional protection
     112                 :    * against addr16/data16 prefixed operations being used for attacks.
     113                 :    *
     114                 :    * NaClMprotectGuards also sets up guard pages outside of the
     115                 :    * virtual address space of the NaClApp -- for the ARM and x86-64
     116                 :    * where data sandboxing only sandbox memory writes and not reads,
     117                 :    * we need to ensure that certain addressing modes that might
     118                 :    * otherwise allow the NaCl app to write outside its address space
     119                 :    * (given how we using masking / base registers to implement data
     120                 :    * write sandboxing) won't affect the trusted data structures.
     121                 :    */
     122                 : 
     123               3 :   NaClLog(3, "Protecting guard pages for 0x%08"NACL_PRIxPTR"\n",
     124                 :           nap->mem_start);
     125               3 :   err = NaClMprotectGuards(nap);
     126               3 :   if (err != LOAD_OK) return err;
     127                 : 
     128               3 :   start_addr = nap->mem_start + NACL_SYSCALL_START_ADDR;
     129                 :   /*
     130                 :    * The next pages up to NACL_TRAMPOLINE_END are the trampolines.
     131                 :    * Immediately following that is the loaded text section.
     132                 :    * These are collectively marked as PROT_READ | PROT_EXEC.
     133                 :    */
     134               3 :   region_size = NaClRoundPage(nap->static_text_end - NACL_SYSCALL_START_ADDR);
     135               3 :   NaClLog(3,
     136                 :           ("Trampoline/text region start 0x%08"NACL_PRIxPTR","
     137                 :            " size 0x%08"NACL_PRIxS", end 0x%08"NACL_PRIxPTR"\n"),
     138                 :           start_addr, region_size,
     139                 :           start_addr + region_size);
     140               3 :   if (0 != (err = NaCl_mprotect((void *) start_addr,
     141                 :                                 region_size,
     142                 :                                 PROT_READ | PROT_EXEC))) {
     143               0 :     NaClLog(LOG_ERROR,
     144                 :             ("NaClMemoryProtection: "
     145                 :              "NaCl_mprotect(0x%08"NACL_PRIxPTR", "
     146                 :              "0x%08"NACL_PRIxS", 0x%x) failed, "
     147                 :              "error %d (trampoline)\n"),
     148                 :             start_addr, region_size, PROT_READ | PROT_EXEC,
     149                 :             err);
     150               0 :     return LOAD_MPROTECT_FAIL;
     151                 :   }
     152               3 :   if (!NaClVmmapAdd(&nap->mem_map,
     153                 :                     NaClSysToUser(nap, start_addr) >> NACL_PAGESHIFT,
     154                 :                     region_size >> NACL_PAGESHIFT,
     155                 :                     PROT_READ | PROT_EXEC,
     156                 :                     NULL)) {
     157               0 :     NaClLog(LOG_ERROR, ("NaClMemoryProtection: NaClVmmapAdd failed"
     158                 :                         " (trampoline)\n"));
     159               0 :     return LOAD_MPROTECT_FAIL;
     160                 :   }
     161                 : 
     162               3 :   start_addr = NaClUserToSys(nap, nap->dynamic_text_start);
     163               3 :   region_size = nap->dynamic_text_end - nap->dynamic_text_start;
     164               3 :   NaClLog(3,
     165                 :           ("shm txt region start 0x%08"NACL_PRIxPTR", size 0x%08"NACL_PRIxS","
     166                 :            " end 0x%08"NACL_PRIxPTR"\n"),
     167                 :           start_addr, region_size,
     168                 :           start_addr + region_size);
     169               3 :   if (0 != region_size) {
     170                 :     /*
     171                 :      * Page protections for this region have already been set up by
     172                 :      * nacl_text.c.
     173                 :      *
     174                 :      * We record the mapping for consistency with other fixed
     175                 :      * mappings, but the record is not actually used.  Overmapping is
     176                 :      * prevented by a separate range check, which is done by
     177                 :      * NaClSysCommonAddrRangeContainsExecutablePages_mu().
     178                 :      */
     179               3 :     if (!NaClVmmapAdd(&nap->mem_map,
     180                 :                       NaClSysToUser(nap, start_addr) >> NACL_PAGESHIFT,
     181                 :                       region_size >> NACL_PAGESHIFT,
     182                 :                       PROT_READ | PROT_EXEC,
     183                 :                       NaClMemObjMake(nap->text_shm,
     184                 :                                      region_size,
     185                 :                                      0))) {
     186               0 :       NaClLog(LOG_ERROR, ("NaClMemoryProtection: NaClVmmapAdd failed"
     187                 :                           " (data)\n"));
     188               0 :       return LOAD_MPROTECT_FAIL;
     189                 :     }
     190                 :   }
     191                 : 
     192               3 :   if (0 != nap->rodata_start) {
     193                 :     uintptr_t rodata_end;
     194                 :     /*
     195                 :      * TODO(mseaborn): Could reduce the number of cases by ensuring
     196                 :      * that nap->data_start is always non-zero, even if
     197                 :      * nap->rodata_start == nap->data_start == nap->break_addr.
     198                 :      */
     199               3 :     if (0 != nap->data_start) {
     200               3 :       rodata_end = nap->data_start;
     201                 :     }
     202                 :     else {
     203               0 :       rodata_end = nap->break_addr;
     204                 :     }
     205                 : 
     206               3 :     start_addr = NaClUserToSys(nap, nap->rodata_start);
     207               3 :     region_size = NaClRoundPage(NaClRoundAllocPage(rodata_end)
     208                 :                                 - NaClSysToUser(nap, start_addr));
     209               3 :     NaClLog(3,
     210                 :             ("RO data region start 0x%08"NACL_PRIxPTR", size 0x%08"NACL_PRIxS","
     211                 :              " end 0x%08"NACL_PRIxPTR"\n"),
     212                 :             start_addr, region_size,
     213                 :             start_addr + region_size);
     214               3 :     if (0 != (err = NaCl_mprotect((void *) start_addr,
     215                 :                                   region_size,
     216                 :                                   PROT_READ))) {
     217               0 :       NaClLog(LOG_ERROR,
     218                 :               ("NaClMemoryProtection: "
     219                 :                "NaCl_mprotect(0x%08"NACL_PRIxPTR", "
     220                 :                "0x%08"NACL_PRIxS", 0x%x) failed, "
     221                 :                "error %d (data)\n"),
     222                 :               start_addr, region_size, PROT_READ,
     223                 :               err);
     224               0 :       return LOAD_MPROTECT_FAIL;
     225                 :     }
     226               3 :     if (!NaClVmmapAdd(&nap->mem_map,
     227                 :                       NaClSysToUser(nap, start_addr) >> NACL_PAGESHIFT,
     228                 :                       region_size >> NACL_PAGESHIFT,
     229                 :                       PROT_READ,
     230                 :                       (struct NaClMemObj *) NULL)) {
     231               0 :       NaClLog(LOG_ERROR, ("NaClMemoryProtection: NaClVmmapAdd failed"
     232                 :                           " (data)\n"));
     233               0 :       return LOAD_MPROTECT_FAIL;
     234                 :     }
     235                 :   }
     236                 : 
     237                 :   /*
     238                 :    * data_end is max virtual addr seen, so start_addr <= data_end
     239                 :    * must hold.
     240                 :    */
     241                 : 
     242               3 :   if (0 != nap->data_start) {
     243               3 :     start_addr = NaClUserToSys(nap, nap->data_start);
     244               3 :     region_size = NaClRoundPage(NaClRoundAllocPage(nap->data_end)
     245                 :                                 - NaClSysToUser(nap, start_addr));
     246               3 :     NaClLog(3,
     247                 :             ("RW data region start 0x%08"NACL_PRIxPTR", size 0x%08"NACL_PRIxS","
     248                 :              " end 0x%08"NACL_PRIxPTR"\n"),
     249                 :             start_addr, region_size,
     250                 :             start_addr + region_size);
     251               3 :     if (0 != (err = NaCl_mprotect((void *) start_addr,
     252                 :                                   region_size,
     253                 :                                   PROT_READ | PROT_WRITE))) {
     254               0 :       NaClLog(LOG_ERROR,
     255                 :               ("NaClMemoryProtection: "
     256                 :                "NaCl_mprotect(0x%08"NACL_PRIxPTR", "
     257                 :                "0x%08"NACL_PRIxS", 0x%x) failed, "
     258                 :                "error %d (data)\n"),
     259                 :               start_addr, region_size, PROT_READ | PROT_WRITE,
     260                 :               err);
     261               0 :       return LOAD_MPROTECT_FAIL;
     262                 :     }
     263               3 :     if (!NaClVmmapAdd(&nap->mem_map,
     264                 :                       NaClSysToUser(nap, start_addr) >> NACL_PAGESHIFT,
     265                 :                       region_size >> NACL_PAGESHIFT,
     266                 :                       PROT_READ | PROT_WRITE,
     267                 :                       (struct NaClMemObj *) NULL)) {
     268               0 :       NaClLog(LOG_ERROR, ("NaClMemoryProtection: NaClVmmapAdd failed"
     269                 :                           " (data)\n"));
     270               0 :       return LOAD_MPROTECT_FAIL;
     271                 :     }
     272                 :   }
     273                 : 
     274                 :   /* stack is read/write but not execute */
     275               3 :   region_size = nap->stack_size;
     276               3 :   start_addr = NaClUserToSys(nap,
     277                 :                              NaClTruncAllocPage(
     278                 :                                  ((uintptr_t) 1U << nap->addr_bits)
     279                 :                                  - nap->stack_size));
     280               3 :   NaClLog(3,
     281                 :           ("RW stack region start 0x%08"NACL_PRIxPTR", size 0x%08"NACL_PRIxS","
     282                 :            " end 0x%08"NACL_PRIxPTR"\n"),
     283                 :           start_addr, region_size,
     284                 :           start_addr + region_size);
     285               3 :   if (0 != (err = NaCl_mprotect((void *) start_addr,
     286                 :                                 NaClRoundAllocPage(nap->stack_size),
     287                 :                                 PROT_READ | PROT_WRITE))) {
     288               0 :     NaClLog(LOG_ERROR,
     289                 :             ("NaClMemoryProtection: "
     290                 :              "NaCl_mprotect(0x%08"NACL_PRIxPTR", "
     291                 :              "0x%08"NACL_PRIxS", 0x%x) failed, "
     292                 :              "error %d (stack)\n"),
     293                 :             start_addr, region_size, PROT_READ | PROT_WRITE,
     294                 :             err);
     295               0 :     return LOAD_MPROTECT_FAIL;
     296                 :   }
     297                 : 
     298               3 :   if (!NaClVmmapAdd(&nap->mem_map,
     299                 :                     NaClSysToUser(nap, start_addr) >> NACL_PAGESHIFT,
     300                 :                     nap->stack_size >> NACL_PAGESHIFT,
     301                 :                     PROT_READ | PROT_WRITE,
     302                 :                     (struct NaClMemObj *) NULL)) {
     303               0 :     NaClLog(LOG_ERROR, ("NaClMemoryProtection: NaClVmmapAdd failed"
     304                 :                         " (stack)\n"));
     305               0 :     return LOAD_MPROTECT_FAIL;
     306                 :   }
     307               3 :   return LOAD_OK;
     308                 : }

Generated by: LCOV version 1.7