Allow a read-only data PT_LOAD segment at the start of the executable, containing...
[nativeclient.git] / service_runtime / sel_addrspace.c
blob98384f35ad28231c011c7499969cf1d686147859
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 int split_code_and_data = 1;
59 nap->data_mem_start = (uintptr_t) mem;
60 if (split_code_and_data)
61 nap->code_mem_start = (uintptr_t) mem + (1U << nap->addr_bits);
62 else
63 nap->code_mem_start = (uintptr_t) mem;
64 nap->xlate_base = nap->data_mem_start;
65 NaClLog(2, "allocated memory at 0x%08x\n", mem);
67 hole_start = NaClRoundAllocPage(nap->data_end);
69 /* TODO: check for underflow? only trusted code can set stack_size */
70 stack_start = (1U << nap->addr_bits) - nap->stack_size;
71 stack_start = NaClTruncAllocPage(stack_start);
73 if (stack_start < hole_start) {
74 return LOAD_DATA_OVERLAPS_STACK_SECTION;
77 hole_size = stack_start - hole_start;
78 hole_size = NaClTruncAllocPage(hole_size);
81 * mprotect and madvise unused data space to "free" it up, but
82 * retain mapping so no other memory can be mapped into those
83 * addresses.
85 if (hole_size == 0) {
86 NaClLog(2, ("NaClAllocAddrSpace: hole between end of data and"
87 " the beginning of stack is zero size.\n"));
88 } else {
89 NaClLog(2,
90 "madvising 0x%08x, 0x%08x, PROT_NONE\n",
91 nap->data_mem_start + hole_start, hole_size);
92 if (NaCl_madvise((void *) (nap->data_mem_start + hole_start),
93 hole_size,
94 MADV_DONTNEED) != 0) {
95 return LOAD_MADVISE_FAIL;
98 NaClLog(2,
99 "mprotecting 0x%08x, 0x%08x, PROT_NONE\n",
100 nap->data_mem_start + hole_start, hole_size);
101 if (NaCl_mprotect((void *) (nap->data_mem_start + hole_start),
102 hole_size,
103 PROT_NONE) != 0) {
104 return LOAD_MPROTECT_FAIL;
108 return LOAD_OK;
112 * Apply memory protection to memory regions.
114 NaClErrorCode NaClMemoryProtection(struct NaClApp *nap)
116 uintptr_t start_addr;
117 uint32_t region_size;
118 int err;
120 start_addr = nap->code_mem_start;
122 * The first NACL_SYSCALL_START_ADDR bytes are mapped as PROT_NONE.
123 * This enables NULL pointer checking. Since NACL_SYSCALL_START_ADDR
124 * is a multiple of the page size, we don't need to round it to be so.
126 NaClLog(3, "NULL detection region start 0x%08x, size 0x%08x, end 0x%08x\n",
127 start_addr, NACL_SYSCALL_START_ADDR,
128 start_addr + NACL_SYSCALL_START_ADDR);
129 if ((err = NaCl_mprotect((void *) start_addr,
130 NACL_SYSCALL_START_ADDR,
131 PROT_NONE)) != 0) {
132 NaClLog(LOG_ERROR, ("NaClMemoryProtection:"
133 " NaCl_mprotect(0x%08x, 0x%08x, 0x%x) failed,"
134 " error %d (NULL pointer guard page)\n"),
135 (uintptr_t) start_addr, NACL_SYSCALL_START_ADDR, PROT_NONE,
136 err);
137 return LOAD_MPROTECT_FAIL;
139 if (!NaClVmmapAdd(&nap->mem_map,
140 (start_addr - nap->code_mem_start) >> NACL_PAGESHIFT,
141 NACL_SYSCALL_START_ADDR >> NACL_PAGESHIFT,
142 PROT_NONE,
143 (struct NaClMemObj *) NULL)) {
144 NaClLog(LOG_ERROR, ("NaClMemoryProtection: NaClVmmapAdd failed"
145 " (NULL pointer guard page)\n"));
146 return LOAD_MPROTECT_FAIL;
149 start_addr = nap->code_mem_start + NACL_SYSCALL_START_ADDR;
151 * The next pages up to NACL_TRAMPOLINE_SIZE are the trampolines.
152 * Immediately following that is the loaded text section.
153 * These are collectively marked as PROT_READ | PROT_EXEC.
155 region_size = NaClRoundPage(- NACL_SYSCALL_START_ADDR
156 + nap->text_region_end);
157 NaClLog(3, "Trampoline/text region start 0x%08x, size 0x%08x, end 0x%08x\n",
158 start_addr, region_size,
159 start_addr + region_size);
160 if ((err = NaCl_mprotect((void *) start_addr,
161 region_size,
162 PROT_READ | PROT_EXEC)) != 0) {
163 NaClLog(LOG_ERROR, ("NaClMemoryProtection:"
164 " NaCl_mprotect(0x%08x, 0x%08x, 0x%x) failed,"
165 " error %d (trampoline)\n"),
166 (uintptr_t) start_addr, region_size, PROT_READ | PROT_EXEC,
167 err);
168 return LOAD_MPROTECT_FAIL;
170 if (!NaClVmmapAdd(&nap->mem_map,
171 (start_addr - nap->code_mem_start) >> NACL_PAGESHIFT,
172 region_size >> NACL_PAGESHIFT,
173 PROT_READ | PROT_EXEC,
174 (struct NaClMemObj *) NULL)) {
175 NaClLog(LOG_ERROR, ("NaClMemoryProtection: NaClVmmapAdd failed"
176 " (trampoline)\n"));
177 return LOAD_MPROTECT_FAIL;
180 start_addr = nap->data_mem_start + NACL_SYSCALL_START_ADDR;
181 start_addr = NaClRoundPage(start_addr + region_size);
183 * data_end is max virtual addr seen, so start_addr <= data_end
184 * must hold.
187 region_size = NaClRoundPage(NaClRoundAllocPage(nap->data_end)
188 + nap->data_mem_start - start_addr);
189 NaClLog(3, "RW data region start 0x%08x, size 0x%08x, end 0x%08x\n",
190 start_addr, region_size,
191 start_addr + region_size);
192 if ((err = NaCl_mprotect((void *) start_addr,
193 region_size,
194 PROT_READ | PROT_WRITE)) != 0) {
195 NaClLog(LOG_ERROR, ("NaClMemoryProtection:"
196 " NaCl_mprotect(0x%08x, 0x%08x, 0x%x) failed,"
197 " error %d (data)\n"),
198 (uintptr_t) start_addr, region_size, PROT_READ | PROT_WRITE,
199 err);
200 return LOAD_MPROTECT_FAIL;
202 if (!NaClVmmapAdd(&nap->mem_map,
203 (start_addr - nap->data_mem_start) >> NACL_PAGESHIFT,
204 region_size >> NACL_PAGESHIFT,
205 PROT_READ | PROT_WRITE,
206 (struct NaClMemObj *) NULL)) {
207 NaClLog(LOG_ERROR, ("NaClMemoryProtection: NaClVmmapAdd failed"
208 " (data)\n"));
209 return LOAD_MPROTECT_FAIL;
212 /* stack is read/write but not execute */
213 region_size = nap->stack_size;
214 start_addr = (nap->data_mem_start
215 + NaClTruncAllocPage((1U << nap->addr_bits)
216 - nap->stack_size));
217 NaClLog(3, "RW stack region start 0x%08x, size 0x%08x, end 0x%08x\n",
218 start_addr, region_size,
219 start_addr + region_size);
220 if ((err = NaCl_mprotect((void *) start_addr,
221 NaClRoundAllocPage(nap->stack_size),
222 PROT_READ | PROT_WRITE)) != 0) {
223 NaClLog(LOG_ERROR, ("NaClMemoryProtection:"
224 " NaCl_mprotect(0x%08x, 0x%08x, 0x%x) failed,"
225 " error %d (stack)\n"),
226 (uintptr_t) start_addr, region_size, PROT_READ | PROT_WRITE,
227 err);
228 return LOAD_MPROTECT_FAIL;
231 if (!NaClVmmapAdd(&nap->mem_map,
232 (start_addr - nap->data_mem_start) >> NACL_PAGESHIFT,
233 nap->stack_size >> NACL_PAGESHIFT,
234 PROT_READ | PROT_WRITE,
235 (struct NaClMemObj *) NULL)) {
236 NaClLog(LOG_ERROR, ("NaClMemoryProtection: NaClVmmapAdd failed"
237 " (stack)\n"));
238 return LOAD_MPROTECT_FAIL;
240 return LOAD_OK;