Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / native_client / src / trusted / service_runtime / posix / sel_memory.c
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 void NaClPageFree(void *p, size_t size) {
32   if (p == 0 || size == 0)
33     return;
34   if (munmap(p, size) != 0) {
35     NaClLog(LOG_FATAL, "NaClPageFree: munmap() failed");
36   }
37 }
38
39 static int NaClPageAllocInternalFlags(void **p, size_t size, int map_flags) {
40   void *addr;
41
42   map_flags |= MAP_PRIVATE | MAP_ANONYMOUS;
43
44   addr = mmap(*p, size, PROT_NONE, map_flags, -1, (off_t) 0);
45   if (MAP_FAILED == addr) {
46     addr = NULL;
47   }
48   if (NULL != addr) {
49     *p = addr;
50   }
51   return (NULL == addr) ? -ENOMEM : 0;
52 }
53
54 /*
55  * Note that NaClPageAlloc does not allocate pages that satisify
56  * NaClIsAllocPageMultiple.  On linux/osx, the system does not impose
57  * any such restrictions, and we only need to enforce the restriction
58  * on NaCl app code to ensure that the app code is portable across all
59  * host OSes.
60  */
61 static int NaClPageAllocInternal(void **p, size_t size) {
62   int map_flags = 0;
63
64   if (NULL != *p) {
65     map_flags |= MAP_FIXED;
66   }
67  #if NACL_LINUX
68   /*
69    * Indicate to the kernel that we just want these pages allocated, not
70    * committed.  This is important for systems with relatively little RAM+swap.
71    * See bug 251.
72    */
73   map_flags |= MAP_NORESERVE;
74 #elif NACL_OSX
75   /*
76    * TODO(cbiffle): This file is used by Mac OS X as well as Linux.
77    * An equivalent fix may require this to stop, since we might have
78    * to drop to the xnu layer and use vm_allocate.
79    *
80    * Currently this code is not guaranteed to work for non-x86-32 Mac OS X.
81    */
82 #else
83 # error This file should be included only by Linux and (surprisingly) OS X.
84 #endif
85   return NaClPageAllocInternalFlags(p, size, map_flags);
86 }
87
88 /*
89  * Pick a "hint" address that is random.
90  */
91 int NaClPageAllocRandomized(void **p, size_t size) {
92   uintptr_t       addr;
93   int             neg_errno = -ENOMEM;  /* in case we change kNumTries to 0 */
94   int             tries;
95   const int       kNumTries = 4;
96   /*
97    * linux permits 128 TB of user address space.
98    */
99
100   for (tries = 0; tries < kNumTries; ++tries) {
101 #if NACL_HOST_WORDSIZE == 32
102     addr = NaClGlobalSecureRngUint32();
103     NaClLog(2, "NaClPageAllocRandomized: 0x%"NACL_PRIxPTR"\n", addr);
104     /* linux permits 3-4 GB of user address space */
105     *p = (void *) (addr & ~((uintptr_t) NACL_MAP_PAGESIZE - 1)
106                    & ((~(uintptr_t) 0) >> 1));
107 #elif NACL_HOST_WORDSIZE == 64
108     addr = NaClGlobalSecureRngUint32();
109     NaClLog(2, "NaClPageAllocRandomized: 0x%"NACL_PRIxPTR"\n", addr);
110     /*
111      * linux permits 128 TB of user address space, and we keep the low
112      * 16 bits free (64K alignment to match Windows), so we have
113      * 47-16=31 bits of entropy.
114      */
115     *p = (void *) ((addr << NACL_MAP_PAGESHIFT)  /* bits [47:16] are random */
116                    & ((((uintptr_t) 1) << 47) - 1));  /* now bits [46:16] */
117 #else
118 # error "where am i?"
119 #endif
120
121     NaClLog(2, "NaClPageAllocRandomized: hint 0x%"NACL_PRIxPTR"\n",
122             (uintptr_t) *p);
123     neg_errno = NaClPageAllocInternalFlags(p, size, 0);
124     if (0 == neg_errno) {
125       break;
126     }
127   }
128   if (0 != neg_errno) {
129     NaClLog(LOG_INFO,
130             "NaClPageAllocRandomized: failed (%d), dropping hints\n",
131             -neg_errno);
132     *p = 0;
133     neg_errno = NaClPageAllocInternalFlags(p, size, 0);
134   }
135   return neg_errno;
136 }
137
138 int NaClPageAlloc(void **p, size_t size) {
139   void *addr = NULL;
140   int rv;
141
142   if (0 == (rv = NaClPageAllocInternal(&addr, size))) {
143     *p = addr;
144   }
145
146   return rv;
147 }
148
149 int NaClPageAllocAtAddr(void **p, size_t size) {
150   return NaClPageAllocInternal(p, size);
151 }
152
153 /*
154 * This is critical to make the text region non-writable, and the data
155 * region read/write but no exec.  Of course, some kernels do not
156 * respect the lack of PROT_EXEC.
157 */
158 int NaClMprotect(void *addr, size_t len, int prot) {
159   int  ret = mprotect(addr, len, prot);
160
161   return ret == -1 ? -errno : ret;
162 }
163
164
165 int NaClMadvise(void *start, size_t length, int advice) {
166   int ret = madvise(start, length, advice);
167
168   /*
169    * MADV_DONTNEED and MADV_NORMAL are needed
170    */
171   return ret == -1 ? -errno : ret;
172 }