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
)) != 0) {
55 NaClLog(2, "NaClAllocAddrSpace: NaCl_page_alloc failed\n");
56 return LOAD_NO_MEMORY
;
58 nap
->mem_start
= (uintptr_t) mem
;
59 nap
->xlate_base
= nap
->mem_start
;
60 NaClLog(2, "allocated memory at 0x%08x\n", nap
->mem_start
);
62 hole_start
= NaClRoundAllocPage(nap
->data_end
);
64 /* TODO: check for underflow? only trusted code can set stack_size */
65 stack_start
= (1U << nap
->addr_bits
) - nap
->stack_size
;
66 stack_start
= NaClTruncAllocPage(stack_start
);
68 if (stack_start
< hole_start
) {
69 return LOAD_DATA_OVERLAPS_STACK_SECTION
;
72 hole_size
= stack_start
- hole_start
;
73 hole_size
= NaClTruncAllocPage(hole_size
);
76 * mprotect and madvise unused data space to "free" it up, but
77 * retain mapping so no other memory can be mapped into those
81 NaClLog(2, ("NaClAllocAddrSpace: hole between end of data and"
82 " the beginning of stack is zero size.\n"));
85 "madvising 0x%08x, 0x%08x, PROT_NONE\n",
86 nap
->mem_start
+ hole_start
, hole_size
);
87 if (NaCl_madvise((void *) (nap
->mem_start
+ hole_start
),
89 MADV_DONTNEED
) != 0) {
90 return LOAD_MADVISE_FAIL
;
94 "mprotecting 0x%08x, 0x%08x, PROT_NONE\n",
95 nap
->mem_start
+ hole_start
, hole_size
);
96 if (NaCl_mprotect((void *) (nap
->mem_start
+ hole_start
),
99 return LOAD_MPROTECT_FAIL
;
107 * Apply memory protection to memory regions.
109 NaClErrorCode
NaClMemoryProtection(struct NaClApp
*nap
)
111 uintptr_t start_addr
;
112 uint32_t region_size
;
115 start_addr
= nap
->mem_start
;
117 * The first NACL_SYSCALL_START_ADDR bytes are mapped as PROT_NONE.
118 * This enables NULL pointer checking. Since NACL_SYSCALL_START_ADDR
119 * is a multiple of the page size, we don't need to round it to be so.
121 NaClLog(3, "NULL detection region start 0x%08x, size 0x%08x, end 0x%08x\n",
122 start_addr
, NACL_SYSCALL_START_ADDR
,
123 start_addr
+ NACL_SYSCALL_START_ADDR
);
124 if ((err
= NaCl_mprotect((void *) start_addr
,
125 NACL_SYSCALL_START_ADDR
,
127 NaClLog(LOG_ERROR
, ("NaClMemoryProtection:"
128 " NaCl_mprotect(0x%08x, 0x%08x, 0x%x) failed,"
129 " error %d (NULL pointer guard page)\n"),
130 (uintptr_t) start_addr
, NACL_SYSCALL_START_ADDR
, PROT_NONE
,
132 return LOAD_MPROTECT_FAIL
;
134 if (!NaClVmmapAdd(&nap
->mem_map
,
135 (start_addr
- nap
->mem_start
) >> NACL_PAGESHIFT
,
136 NACL_SYSCALL_START_ADDR
>> NACL_PAGESHIFT
,
138 (struct NaClMemObj
*) NULL
)) {
139 NaClLog(LOG_ERROR
, ("NaClMemoryProtection: NaClVmmapAdd failed"
140 " (NULL pointer guard page)\n"));
141 return LOAD_MPROTECT_FAIL
;
144 start_addr
= nap
->mem_start
+ NACL_SYSCALL_START_ADDR
;
146 * The next pages up to NACL_TRAMPOLINE_SIZE are the trampolines.
147 * Immediately following that is the loaded text section.
148 * These are collectively marked as PROT_READ | PROT_EXEC.
150 region_size
= NaClRoundPage(NACL_TRAMPOLINE_SIZE
- NACL_SYSCALL_START_ADDR
151 + nap
->text_region_bytes
);
152 NaClLog(3, "Trampoline/text region start 0x%08x, size 0x%08x, end 0x%08x\n",
153 start_addr
, region_size
,
154 start_addr
+ region_size
);
155 if ((err
= NaCl_mprotect((void *) start_addr
,
157 PROT_READ
| PROT_EXEC
)) != 0) {
158 NaClLog(LOG_ERROR
, ("NaClMemoryProtection:"
159 " NaCl_mprotect(0x%08x, 0x%08x, 0x%x) failed,"
160 " error %d (trampoline)\n"),
161 (uintptr_t) start_addr
, region_size
, PROT_READ
| PROT_EXEC
,
163 return LOAD_MPROTECT_FAIL
;
165 if (!NaClVmmapAdd(&nap
->mem_map
,
166 (start_addr
- nap
->mem_start
) >> NACL_PAGESHIFT
,
167 region_size
>> NACL_PAGESHIFT
,
168 PROT_READ
| PROT_EXEC
,
169 (struct NaClMemObj
*) NULL
)) {
170 NaClLog(LOG_ERROR
, ("NaClMemoryProtection: NaClVmmapAdd failed"
172 return LOAD_MPROTECT_FAIL
;
175 start_addr
= NaClRoundPage(start_addr
+ region_size
);
177 * data_end is max virtual addr seen, so start_addr <= data_end
181 region_size
= NaClRoundPage(NaClRoundAllocPage(nap
->data_end
)
182 + nap
->mem_start
- start_addr
);
183 NaClLog(3, "RW data region start 0x%08x, size 0x%08x, end 0x%08x\n",
184 start_addr
, region_size
,
185 start_addr
+ region_size
);
186 if ((err
= NaCl_mprotect((void *) start_addr
,
188 PROT_READ
| PROT_WRITE
)) != 0) {
189 NaClLog(LOG_ERROR
, ("NaClMemoryProtection:"
190 " NaCl_mprotect(0x%08x, 0x%08x, 0x%x) failed,"
191 " error %d (data)\n"),
192 (uintptr_t) start_addr
, region_size
, PROT_READ
| PROT_WRITE
,
194 return LOAD_MPROTECT_FAIL
;
196 if (!NaClVmmapAdd(&nap
->mem_map
,
197 (start_addr
- nap
->mem_start
) >> NACL_PAGESHIFT
,
198 region_size
>> NACL_PAGESHIFT
,
199 PROT_READ
| PROT_WRITE
,
200 (struct NaClMemObj
*) NULL
)) {
201 NaClLog(LOG_ERROR
, ("NaClMemoryProtection: NaClVmmapAdd failed"
203 return LOAD_MPROTECT_FAIL
;
206 /* stack is read/write but not execute */
207 region_size
= nap
->stack_size
;
208 start_addr
= (nap
->mem_start
209 + NaClTruncAllocPage((1U << nap
->addr_bits
)
211 NaClLog(3, "RW stack region start 0x%08x, size 0x%08x, end 0x%08x\n",
212 start_addr
, region_size
,
213 start_addr
+ region_size
);
214 if ((err
= NaCl_mprotect((void *) start_addr
,
215 NaClRoundAllocPage(nap
->stack_size
),
216 PROT_READ
| PROT_WRITE
)) != 0) {
217 NaClLog(LOG_ERROR
, ("NaClMemoryProtection:"
218 " NaCl_mprotect(0x%08x, 0x%08x, 0x%x) failed,"
219 " error %d (stack)\n"),
220 (uintptr_t) start_addr
, region_size
, PROT_READ
| PROT_WRITE
,
222 return LOAD_MPROTECT_FAIL
;
225 if (!NaClVmmapAdd(&nap
->mem_map
,
226 (start_addr
- nap
->mem_start
) >> NACL_PAGESHIFT
,
227 nap
->stack_size
>> NACL_PAGESHIFT
,
228 PROT_READ
| PROT_WRITE
,
229 (struct NaClMemObj
*) NULL
)) {
230 NaClLog(LOG_ERROR
, ("NaClMemoryProtection: NaClVmmapAdd failed"
232 return LOAD_MPROTECT_FAIL
;