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.
8 * NaCl Service Runtime memory allocation code
13 #include <sys/types.h>
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"
31 void NaClPageFree(void *p, size_t size) {
32 if (p == 0 || size == 0)
34 if (munmap(p, size) != 0) {
35 NaClLog(LOG_FATAL, "NaClPageFree: munmap() failed");
39 static int NaClPageAllocInternalFlags(void **p, size_t size, int map_flags) {
42 map_flags |= MAP_PRIVATE | MAP_ANONYMOUS;
44 addr = mmap(*p, size, PROT_NONE, map_flags, -1, (off_t) 0);
45 if (MAP_FAILED == addr) {
51 return (NULL == addr) ? -ENOMEM : 0;
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
61 static int NaClPageAllocInternal(void **p, size_t size) {
65 map_flags |= MAP_FIXED;
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.
73 map_flags |= MAP_NORESERVE;
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.
80 * Currently this code is not guaranteed to work for non-x86-32 Mac OS X.
83 # error This file should be included only by Linux and (surprisingly) OS X.
85 return NaClPageAllocInternalFlags(p, size, map_flags);
89 * Pick a "hint" address that is random.
91 int NaClPageAllocRandomized(void **p, size_t size) {
93 int neg_errno = -ENOMEM; /* in case we change kNumTries to 0 */
95 const int kNumTries = 4;
97 * linux permits 128 TB of user address space.
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);
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.
115 *p = (void *) ((addr << NACL_MAP_PAGESHIFT) /* bits [47:16] are random */
116 & ((((uintptr_t) 1) << 47) - 1)); /* now bits [46:16] */
118 # error "where am i?"
121 NaClLog(2, "NaClPageAllocRandomized: hint 0x%"NACL_PRIxPTR"\n",
123 neg_errno = NaClPageAllocInternalFlags(p, size, 0);
124 if (0 == neg_errno) {
128 if (0 != neg_errno) {
130 "NaClPageAllocRandomized: failed (%d), dropping hints\n",
133 neg_errno = NaClPageAllocInternalFlags(p, size, 0);
138 int NaClPageAlloc(void **p, size_t size) {
142 if (0 == (rv = NaClPageAllocInternal(&addr, size))) {
149 int NaClPageAllocAtAddr(void **p, size_t size) {
150 return NaClPageAllocInternal(p, size);
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.
158 int NaClMprotect(void *addr, size_t len, int prot) {
159 int ret = mprotect(addr, len, prot);
161 return ret == -1 ? -errno : ret;
165 int NaClMadvise(void *start, size_t length, int advice) {
166 int ret = madvise(start, length, advice);
169 * MADV_DONTNEED and MADV_NORMAL are needed
171 return ret == -1 ? -errno : ret;