2 * Copyright 2008, Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
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
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
)
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
);
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
86 NaClLog(2, ("NaClAllocAddrSpace: hole between end of data and"
87 " the beginning of stack is zero size.\n"));
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
),
94 MADV_DONTNEED
) != 0) {
95 return LOAD_MADVISE_FAIL
;
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
),
104 return LOAD_MPROTECT_FAIL
;
112 * Apply memory protection to memory regions.
114 NaClErrorCode
NaClMemoryProtection(struct NaClApp
*nap
)
116 uintptr_t start_addr
;
117 uint32_t region_size
;
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
,
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
,
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
,
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
,
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
,
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"
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
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
,
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
,
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"
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
)
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
,
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"
238 return LOAD_MPROTECT_FAIL
;