Allocate two regions for data and code x86 segments, instead of using overlapping...
[nativeclient.git] / service_runtime / sel_addrspace.c
blob0b72eb63398290d4fe5a67e0a78506045c7e4a66
1 /*
2 * Copyright 2008, Google Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 /* NaCl Simple/secure ELF loader (NaCl SEL).
35 #include "native_client/include/portability.h"
36 #include "native_client/include/nacl_platform.h"
38 #include "native_client/service_runtime/nacl_log.h"
39 #include "native_client/service_runtime/sel_addrspace.h"
40 #include "native_client/service_runtime/sel_util.h"
41 #include "native_client/service_runtime/sel_memory.h"
44 NaClErrorCode NaClAllocAddrSpace(struct NaClApp *nap)
46 void *mem;
47 uintptr_t hole_start;
48 size_t hole_size;
49 uintptr_t stack_start;
51 NaClLog(2, "NaClAllocAddrSpace: calling NaCl_page_alloc(*,0x%x)\n",
52 (1U << nap->addr_bits));
53 if (NaCl_page_alloc(&mem,
54 (1U << nap->addr_bits) * 2) != 0) {
55 NaClLog(2, "NaClAllocAddrSpace: NaCl_page_alloc failed\n");
56 return LOAD_NO_MEMORY;
58 nap->data_mem_start = (uintptr_t) mem;
59 nap->code_mem_start = (uintptr_t) mem + (1U << nap->addr_bits);
60 nap->xlate_base = nap->data_mem_start;
61 NaClLog(2, "allocated memory at 0x%08x\n", mem);
63 hole_start = NaClRoundAllocPage(nap->data_end);
65 /* TODO: check for underflow? only trusted code can set stack_size */
66 stack_start = (1U << nap->addr_bits) - nap->stack_size;
67 stack_start = NaClTruncAllocPage(stack_start);
69 if (stack_start < hole_start) {
70 return LOAD_DATA_OVERLAPS_STACK_SECTION;
73 hole_size = stack_start - hole_start;
74 hole_size = NaClTruncAllocPage(hole_size);
77 * mprotect and madvise unused data space to "free" it up, but
78 * retain mapping so no other memory can be mapped into those
79 * addresses.
81 if (hole_size == 0) {
82 NaClLog(2, ("NaClAllocAddrSpace: hole between end of data and"
83 " the beginning of stack is zero size.\n"));
84 } else {
85 NaClLog(2,
86 "madvising 0x%08x, 0x%08x, PROT_NONE\n",
87 nap->data_mem_start + hole_start, hole_size);
88 if (NaCl_madvise((void *) (nap->data_mem_start + hole_start),
89 hole_size,
90 MADV_DONTNEED) != 0) {
91 return LOAD_MADVISE_FAIL;
94 NaClLog(2,
95 "mprotecting 0x%08x, 0x%08x, PROT_NONE\n",
96 nap->data_mem_start + hole_start, hole_size);
97 if (NaCl_mprotect((void *) (nap->data_mem_start + hole_start),
98 hole_size,
99 PROT_NONE) != 0) {
100 return LOAD_MPROTECT_FAIL;
104 return LOAD_OK;
108 * Apply memory protection to memory regions.
110 NaClErrorCode NaClMemoryProtection(struct NaClApp *nap)
112 uintptr_t start_addr;
113 uint32_t region_size;
114 int err;
116 start_addr = nap->code_mem_start;
118 * The first NACL_SYSCALL_START_ADDR bytes are mapped as PROT_NONE.
119 * This enables NULL pointer checking. Since NACL_SYSCALL_START_ADDR
120 * is a multiple of the page size, we don't need to round it to be so.
122 NaClLog(3, "NULL detection region start 0x%08x, size 0x%08x, end 0x%08x\n",
123 start_addr, NACL_SYSCALL_START_ADDR,
124 start_addr + NACL_SYSCALL_START_ADDR);
125 if ((err = NaCl_mprotect((void *) start_addr,
126 NACL_SYSCALL_START_ADDR,
127 PROT_NONE)) != 0) {
128 NaClLog(LOG_ERROR, ("NaClMemoryProtection:"
129 " NaCl_mprotect(0x%08x, 0x%08x, 0x%x) failed,"
130 " error %d (NULL pointer guard page)\n"),
131 (uintptr_t) start_addr, NACL_SYSCALL_START_ADDR, PROT_NONE,
132 err);
133 return LOAD_MPROTECT_FAIL;
135 if (!NaClVmmapAdd(&nap->mem_map,
136 (start_addr - nap->code_mem_start) >> NACL_PAGESHIFT,
137 NACL_SYSCALL_START_ADDR >> NACL_PAGESHIFT,
138 PROT_NONE,
139 (struct NaClMemObj *) NULL)) {
140 NaClLog(LOG_ERROR, ("NaClMemoryProtection: NaClVmmapAdd failed"
141 " (NULL pointer guard page)\n"));
142 return LOAD_MPROTECT_FAIL;
145 start_addr = nap->code_mem_start + NACL_SYSCALL_START_ADDR;
147 * The next pages up to NACL_TRAMPOLINE_SIZE are the trampolines.
148 * Immediately following that is the loaded text section.
149 * These are collectively marked as PROT_READ | PROT_EXEC.
151 region_size = NaClRoundPage(NACL_TRAMPOLINE_SIZE - NACL_SYSCALL_START_ADDR
152 + nap->text_region_bytes);
153 NaClLog(3, "Trampoline/text region start 0x%08x, size 0x%08x, end 0x%08x\n",
154 start_addr, region_size,
155 start_addr + region_size);
156 if ((err = NaCl_mprotect((void *) start_addr,
157 region_size,
158 PROT_READ | PROT_EXEC)) != 0) {
159 NaClLog(LOG_ERROR, ("NaClMemoryProtection:"
160 " NaCl_mprotect(0x%08x, 0x%08x, 0x%x) failed,"
161 " error %d (trampoline)\n"),
162 (uintptr_t) start_addr, region_size, PROT_READ | PROT_EXEC,
163 err);
164 return LOAD_MPROTECT_FAIL;
166 if (!NaClVmmapAdd(&nap->mem_map,
167 (start_addr - nap->code_mem_start) >> NACL_PAGESHIFT,
168 region_size >> NACL_PAGESHIFT,
169 PROT_READ | PROT_EXEC,
170 (struct NaClMemObj *) NULL)) {
171 NaClLog(LOG_ERROR, ("NaClMemoryProtection: NaClVmmapAdd failed"
172 " (trampoline)\n"));
173 return LOAD_MPROTECT_FAIL;
176 start_addr = nap->data_mem_start + NACL_SYSCALL_START_ADDR;
177 start_addr = NaClRoundPage(start_addr + region_size);
179 * data_end is max virtual addr seen, so start_addr <= data_end
180 * must hold.
183 region_size = NaClRoundPage(NaClRoundAllocPage(nap->data_end)
184 + nap->data_mem_start - start_addr);
185 NaClLog(3, "RW data region start 0x%08x, size 0x%08x, end 0x%08x\n",
186 start_addr, region_size,
187 start_addr + region_size);
188 if ((err = NaCl_mprotect((void *) start_addr,
189 region_size,
190 PROT_READ | PROT_WRITE)) != 0) {
191 NaClLog(LOG_ERROR, ("NaClMemoryProtection:"
192 " NaCl_mprotect(0x%08x, 0x%08x, 0x%x) failed,"
193 " error %d (data)\n"),
194 (uintptr_t) start_addr, region_size, PROT_READ | PROT_WRITE,
195 err);
196 return LOAD_MPROTECT_FAIL;
198 if (!NaClVmmapAdd(&nap->mem_map,
199 (start_addr - nap->data_mem_start) >> NACL_PAGESHIFT,
200 region_size >> NACL_PAGESHIFT,
201 PROT_READ | PROT_WRITE,
202 (struct NaClMemObj *) NULL)) {
203 NaClLog(LOG_ERROR, ("NaClMemoryProtection: NaClVmmapAdd failed"
204 " (data)\n"));
205 return LOAD_MPROTECT_FAIL;
208 /* stack is read/write but not execute */
209 region_size = nap->stack_size;
210 start_addr = (nap->data_mem_start
211 + NaClTruncAllocPage((1U << nap->addr_bits)
212 - nap->stack_size));
213 NaClLog(3, "RW stack region start 0x%08x, size 0x%08x, end 0x%08x\n",
214 start_addr, region_size,
215 start_addr + region_size);
216 if ((err = NaCl_mprotect((void *) start_addr,
217 NaClRoundAllocPage(nap->stack_size),
218 PROT_READ | PROT_WRITE)) != 0) {
219 NaClLog(LOG_ERROR, ("NaClMemoryProtection:"
220 " NaCl_mprotect(0x%08x, 0x%08x, 0x%x) failed,"
221 " error %d (stack)\n"),
222 (uintptr_t) start_addr, region_size, PROT_READ | PROT_WRITE,
223 err);
224 return LOAD_MPROTECT_FAIL;
227 if (!NaClVmmapAdd(&nap->mem_map,
228 (start_addr - nap->data_mem_start) >> NACL_PAGESHIFT,
229 nap->stack_size >> NACL_PAGESHIFT,
230 PROT_READ | PROT_WRITE,
231 (struct NaClMemObj *) NULL)) {
232 NaClLog(LOG_ERROR, ("NaClMemoryProtection: NaClVmmapAdd failed"
233 " (stack)\n"));
234 return LOAD_MPROTECT_FAIL;
236 return LOAD_OK;