LCOV - code coverage report
Current view: directory - src/trusted/service_runtime/linux - sel_memory.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 52 39 75.0 %
Date: 2012-02-16 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 Service Runtime memory allocation code
       9                 :  */
      10                 : 
      11                 : #include <sys/mman.h>
      12                 : #include <sys/stat.h>
      13                 : #include <sys/types.h>
      14                 : 
      15                 : #include <errno.h>
      16                 : #include <fcntl.h>
      17                 : #include <stdint.h>
      18                 : #include <stdio.h>
      19                 : #include <string.h>
      20                 : #include <unistd.h>
      21                 : 
      22                 : #include "native_client/src/include/nacl_platform.h"
      23                 : #include "native_client/src/include/portability.h"
      24                 : #include "native_client/src/shared/platform/nacl_exit.h"
      25                 : #include "native_client/src/shared/platform/nacl_global_secure_random.h"
      26                 : #include "native_client/src/shared/platform/nacl_log.h"
      27                 : #include "native_client/src/trusted/service_runtime/sel_memory.h"
      28                 : #include "native_client/src/trusted/service_runtime/nacl_config.h"
      29                 : #include "native_client/src/trusted/service_runtime/include/machine/_types.h"
      30                 : 
      31                 : /*
      32                 :  * When we're built into Chromium's "nacl_helper", its main will set this.
      33                 :  */
      34                 : void *g_nacl_prereserved_sandbox_addr = NULL;
      35                 : 
      36                 : /*
      37                 :  * Find sandbox memory pre-reserved by the nacl_helper in chrome. The
      38                 :  * nacl_helper, if present, reserves the bottom 1G of the address space
      39                 :  * for use by Native Client.
      40                 :  *
      41                 :  * NOTE: num_bytes is currently ignored. It should be 1GB on Linux and
      42                 :  * 1GB plus a few pages on ARM. TODO(bradchen): deal with num_bytes.
      43                 :  *
      44                 :  * Out parameter p should be either:
      45                 :  *   0: reserved memory was not found
      46                 :  *   less than 128K: indicates the bottom 1G was reserved.
      47                 :  */
      48                 : int   NaCl_find_prereserved_sandbox_memory(void   **p,
      49               0 :                                            size_t num_bytes) {
      50                 :   UNREFERENCED_PARAMETER(num_bytes);
      51                 : 
      52               0 :   NaClLog(2,
      53                 :           "NaCl_find_prereserved_sandbox_memory(, %#.8"NACL_PRIxPTR") => %p\n",
      54                 :           num_bytes, g_nacl_prereserved_sandbox_addr);
      55                 : 
      56               0 :   *p = g_nacl_prereserved_sandbox_addr;
      57               0 :   return g_nacl_prereserved_sandbox_addr != NULL;
      58                 : }
      59                 : 
      60                 : void NaCl_page_free(void     *p,
      61            1006 :                     size_t   size) {
      62            1006 :   if (p == 0 || size == 0)
      63               0 :     return;
      64            1006 :   if (munmap(p, size) != 0) {
      65               0 :     NaClLog(LOG_FATAL, "NaCl_page_free: munmap() failed");
      66                 :   }
      67                 : }
      68                 : 
      69                 : /*
      70                 :  * NaCl_page_alloc_intern_flags
      71                 :  */
      72                 : static
      73                 : int NaCl_page_alloc_intern_flags(void   **p,
      74                 :                                  size_t size,
      75            1010 :                                  int    map_flags) {
      76                 :   void *addr;
      77                 : 
      78            1010 :   map_flags |= MAP_PRIVATE | MAP_ANONYMOUS;
      79                 : 
      80            1010 :   NaClLog(4,
      81                 :           "sel_memory: NaCl_page_alloc_intern:"
      82                 :           " mmap(%p, %"NACL_PRIxS", %#x, %#x, %d, %"NACL_PRIdNACL_OFF64")\n",
      83                 :           *p, size, PROT_NONE, map_flags, -1,
      84                 :           (nacl_abi_off64_t) 0);
      85            1010 :   addr = mmap(*p, size, PROT_NONE, map_flags, -1, (off_t) 0);
      86            1010 :   if (MAP_FAILED == addr) {
      87               0 :     addr = NULL;
      88                 :   }
      89            1010 :   if (NULL != addr) {
      90            1010 :     *p = addr;
      91                 :   }
      92            1010 :   return (NULL == addr) ? -ENOMEM : 0;
      93                 : }
      94                 : 
      95                 : /*
      96                 :  * Note that NaCl_page_alloc does not allocate pages that satisify
      97                 :  * NaClIsAllocPageMultiple.  On linux/osx, the system does not impose
      98                 :  * any such restrictions, and we only need to enforce the restriction
      99                 :  * on NaCl app code to ensure that the app code is portable across all
     100                 :  * host OSes.
     101                 :  */
     102                 : static
     103                 : int NaCl_page_alloc_intern(void   **p,
     104            1007 :                            size_t size) {
     105            1007 :   int map_flags = 0;
     106                 : 
     107            1007 :   if (NULL != *p) {
     108               0 :     map_flags |= MAP_FIXED;
     109                 :   }
     110                 :  #if NACL_LINUX
     111                 :   /*
     112                 :    * Indicate to the kernel that we just want these pages allocated, not
     113                 :    * committed.  This is important for systems with relatively little RAM+swap.
     114                 :    * See bug 251.
     115                 :    */
     116                 :   map_flags |= MAP_NORESERVE;
     117                 : #elif NACL_OSX
     118                 :   /*
     119                 :    * TODO(cbiffle): Contrary to its name, this file is used by Mac OS X as well
     120                 :    * as Linux.  An equivalent fix may require this to stop, since we might have
     121                 :    * to drop to the xnu layer and use vm_allocate.
     122                 :    *
     123                 :    * Currently this code is not guaranteed to work for non-x86-32 Mac OS X.
     124                 :    */
     125                 : #else
     126                 : # error This file should be included only by Linux and (surprisingly) OS X.
     127                 : #endif
     128            1007 :   return NaCl_page_alloc_intern_flags(p, size, map_flags);
     129                 : }
     130                 : 
     131                 : /*
     132                 :  * Pick a "hint" address that is random.
     133                 :  */
     134                 : int NaCl_page_alloc_randomized(void   **p,
     135               3 :                                size_t size) {
     136                 :   uintptr_t       addr;
     137               3 :   int             neg_errno = -ENOMEM;  /* in case we change kNumTries to 0 */
     138                 :   int             tries;
     139               3 :   const int       kNumTries = 4;
     140                 :   /*
     141                 :    * linux permits 128 TB of user address space.
     142                 :    */
     143                 : 
     144               3 :   for (tries = 0; tries < kNumTries; ++tries) {
     145                 : #if NACL_HOST_WORDSIZE == 32
     146               3 :     addr = NaClGlobalSecureRngUint32();
     147               3 :     NaClLog(2, "NaCl_page_alloc_randomized: 0x%"NACL_PRIxPTR"\n", addr);
     148                 :     /* linux permits 3-4 GB of user address space */
     149               3 :     *p = (void *) (addr & ~((uintptr_t) NACL_MAP_PAGESIZE - 1)
     150                 :                    & ((~(uintptr_t) 0) >> 1));
     151                 : #elif NACL_HOST_WORDSIZE == 64
     152                 :     addr = NaClGlobalSecureRngUint32();
     153                 :     NaClLog(2, "NaCl_page_alloc_randomized: 0x%"NACL_PRIxPTR"\n", addr);
     154                 :     /*
     155                 :      * linux permits 128 TB of user address space, and we keep the low
     156                 :      * 16 bits free (64K alignment to match Windows), so we have
     157                 :      * 47-16=31 bits of entropy.
     158                 :      */
     159                 :     *p = (void *) ((addr << NACL_MAP_PAGESHIFT)  /* bits [47:16] are random */
     160                 :                    & ((((uintptr_t) 1) << 47) - 1));  /* now bits [46:16] */
     161                 : #else
     162                 : # error "where am i?"
     163                 : #endif
     164                 : 
     165               3 :     NaClLog(2, "NaCl_page_alloc_randomized: hint 0x%"NACL_PRIxPTR"\n",
     166                 :             (uintptr_t) *p);
     167               3 :     neg_errno = NaCl_page_alloc_intern_flags(p, size, 0);
     168               3 :     if (0 == neg_errno) {
     169               3 :       break;
     170                 :     }
     171                 :   }
     172               3 :   if (0 != neg_errno) {
     173               0 :     NaClLog(LOG_INFO,
     174                 :             "NaCl_page_alloc_randomized: failed (%d), dropping hints\n",
     175                 :             -neg_errno);
     176               0 :     *p = 0;
     177               0 :     neg_errno = NaCl_page_alloc_intern_flags(p, size, 0);
     178                 :   }
     179               3 :   return neg_errno;
     180                 : }
     181                 : 
     182                 : int NaCl_page_alloc(void   **p,
     183            1007 :                     size_t size) {
     184            1007 :   void *addr = NULL;
     185                 :   int rv;
     186                 : 
     187            1007 :   if (0 == (rv = NaCl_page_alloc_intern(&addr, size))) {
     188            1007 :     *p = addr;
     189                 :   }
     190                 : 
     191            1007 :   return rv;
     192                 : }
     193                 : 
     194                 : int NaCl_page_alloc_at_addr(void   **p,
     195               0 :                             size_t size) {
     196               0 :   return NaCl_page_alloc_intern(p, size);
     197                 : }
     198                 : 
     199                 : /*
     200                 : * This is critical to make the text region non-writable, and the data
     201                 : * region read/write but no exec.  Of course, some kernels do not
     202                 : * respect the lack of PROT_EXEC.
     203                 : */
     204                 : int NaCl_mprotect(void          *addr,
     205                 :                   size_t        len,
     206              31 :                   int           prot) {
     207              31 :   int  ret = mprotect(addr, len, prot);
     208                 : 
     209              31 :   return ret == -1 ? -errno : ret;
     210                 : }
     211                 : 
     212                 : 
     213                 : int NaCl_madvise(void           *start,
     214                 :                  size_t         length,
     215               3 :                  int            advice) {
     216               3 :   int ret = madvise(start, length, advice);
     217                 : 
     218                 :   /*
     219                 :    * MADV_DONTNEED and MADV_NORMAL are needed
     220                 :    */
     221               3 :   return ret == -1 ? -errno : ret;
     222                 : }

Generated by: LCOV version 1.7