1 : /*
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.
5 : */
6 :
7 : /*
8 : * NaCl Simple/secure ELF loader (NaCl SEL).
9 : */
10 :
11 : #include <errno.h>
12 :
13 : #include "native_client/src/include/nacl_platform.h"
14 : #include "native_client/src/include/portability.h"
15 : #include "native_client/src/shared/platform/nacl_log.h"
16 : #include "native_client/src/trusted/service_runtime/sel_addrspace.h"
17 : #include "native_client/src/trusted/service_runtime/sel_ldr.h"
18 : #include "native_client/src/trusted/service_runtime/sel_memory.h"
19 : #include "native_client/src/trusted/service_runtime/sel_util.h"
20 :
21 : #include "native_client/src/trusted/service_runtime/include/bits/mman.h"
22 :
23 280 : NaClErrorCode NaClAllocAddrSpaceAslr(struct NaClApp *nap,
24 280 : enum NaClAslrMode aslr_mode) {
25 280 : void *mem;
26 280 : int rv;
27 280 : uintptr_t hole_start;
28 280 : size_t hole_size;
29 280 : uintptr_t stack_start;
30 :
31 280 : NaClLog(2,
32 : "NaClAllocAddrSpace: calling NaClAllocateSpace(*,0x%016"
33 : NACL_PRIxS")\n",
34 : ((size_t) 1 << nap->addr_bits));
35 :
36 280 : rv = NaClAllocateSpaceAslr(&mem, (uintptr_t) 1U << nap->addr_bits,
37 : aslr_mode);
38 280 : if (LOAD_OK != rv) {
39 0 : return rv;
40 : }
41 :
42 280 : nap->mem_start = (uintptr_t) mem;
43 : /*
44 : * The following should not be NaClLog(2, ...) because logging with
45 : * any detail level higher than LOG_INFO is disabled in the release
46 : * builds. This was to reduce logging overhead, so as to eliminate
47 : * at least a function call as well as possibly a TLS/TSD read if
48 : * module-specific logging verbosity level comparisons are needed.
49 : */
50 280 : NaClLog(LOG_INFO,
51 : ("Native Client module will be loaded at"
52 : " base address 0x%016"NACL_PRIxPTR"\n"),
53 : nap->mem_start);
54 :
55 280 : hole_start = NaClRoundAllocPage(nap->data_end);
56 :
57 280 : if (nap->stack_size >= ((uintptr_t) 1U) << nap->addr_bits) {
58 0 : NaClLog(LOG_FATAL, "NaClAllocAddrSpace: stack too large!");
59 0 : }
60 280 : stack_start = (((uintptr_t) 1U) << nap->addr_bits) - nap->stack_size;
61 280 : stack_start = NaClTruncAllocPage(stack_start);
62 :
63 280 : if (stack_start < hole_start) {
64 1 : return LOAD_DATA_OVERLAPS_STACK_SECTION;
65 : }
66 :
67 279 : hole_size = stack_start - hole_start;
68 279 : hole_size = NaClTruncAllocPage(hole_size);
69 :
70 : /*
71 : * mprotect and madvise unused data space to "free" it up, but
72 : * retain mapping so no other memory can be mapped into those
73 : * addresses.
74 : */
75 279 : if (hole_size == 0) {
76 0 : NaClLog(2, ("NaClAllocAddrSpace: hole between end of data and"
77 : " the beginning of stack is zero size.\n"));
78 0 : } else {
79 279 : NaClLog(2,
80 : ("madvising 0x%08"NACL_PRIxPTR", 0x%08"NACL_PRIxS
81 : ", MADV_DONTNEED\n"),
82 : nap->mem_start + hole_start, hole_size);
83 279 : if (0 != NaClMadvise((void *) (nap->mem_start + hole_start),
84 : hole_size,
85 : MADV_DONTNEED)) {
86 0 : NaClLog(1, "madvise, errno %d\n", errno);
87 0 : return LOAD_MADVISE_FAIL;
88 : }
89 279 : NaClLog(2,
90 : "mprotecting 0x%08"NACL_PRIxPTR", 0x%08"NACL_PRIxS", PROT_NONE\n",
91 : nap->mem_start + hole_start, hole_size);
92 279 : if (0 != NaClMprotect((void *) (nap->mem_start + hole_start),
93 : hole_size,
94 : PROT_NONE)) {
95 0 : NaClLog(1, "mprotect, errno %d\n", errno);
96 0 : return LOAD_MPROTECT_FAIL;
97 : }
98 : }
99 :
100 279 : return LOAD_OK;
101 280 : }
102 :
103 11 : NaClErrorCode NaClAllocAddrSpace(struct NaClApp *nap) {
104 11 : return NaClAllocAddrSpaceAslr(nap, 1);
105 : }
106 :
107 : /*
108 : * Apply memory protection to memory regions.
109 : */
110 265 : NaClErrorCode NaClMemoryProtection(struct NaClApp *nap) {
111 265 : uintptr_t start_addr;
112 265 : size_t region_size;
113 265 : int err;
114 :
115 : /*
116 : * The first NACL_SYSCALL_START_ADDR bytes are mapped as PROT_NONE.
117 : * This enables NULL pointer checking, and provides additional protection
118 : * against addr16/data16 prefixed operations being used for attacks.
119 : */
120 :
121 265 : NaClLog(3, "Protecting guard pages for 0x%08"NACL_PRIxPTR"\n",
122 : nap->mem_start);
123 : /* Add the zero page to the mmap */
124 265 : NaClVmmapAdd(&nap->mem_map,
125 : 0,
126 : NACL_SYSCALL_START_ADDR >> NACL_PAGESHIFT,
127 : PROT_NONE,
128 : NACL_ABI_MAP_PRIVATE,
129 : NULL,
130 : 0,
131 : 0);
132 :
133 265 : start_addr = nap->mem_start + NACL_SYSCALL_START_ADDR;
134 : /*
135 : * The next pages up to NACL_TRAMPOLINE_END are the trampolines.
136 : * Immediately following that is the loaded text section.
137 : * These are collectively marked as PROT_READ | PROT_EXEC.
138 : */
139 265 : region_size = NaClRoundPage(nap->static_text_end - NACL_SYSCALL_START_ADDR);
140 265 : NaClLog(3,
141 : ("Trampoline/text region start 0x%08"NACL_PRIxPTR","
142 : " size 0x%08"NACL_PRIxS", end 0x%08"NACL_PRIxPTR"\n"),
143 : start_addr, region_size,
144 : start_addr + region_size);
145 265 : if (0 != (err = NaClMprotect((void *) start_addr,
146 : region_size,
147 : PROT_READ | PROT_EXEC))) {
148 0 : NaClLog(LOG_ERROR,
149 : ("NaClMemoryProtection: "
150 : "NaClMprotect(0x%08"NACL_PRIxPTR", "
151 : "0x%08"NACL_PRIxS", 0x%x) failed, "
152 : "error %d (trampoline + code)\n"),
153 : start_addr, region_size, PROT_READ | PROT_EXEC,
154 : err);
155 0 : return LOAD_MPROTECT_FAIL;
156 : }
157 530 : NaClVmmapAdd(&nap->mem_map,
158 265 : NaClSysToUser(nap, start_addr) >> NACL_PAGESHIFT,
159 : region_size >> NACL_PAGESHIFT,
160 : NACL_ABI_PROT_READ | NACL_ABI_PROT_EXEC,
161 : NACL_ABI_MAP_PRIVATE,
162 : NULL,
163 : 0,
164 : 0);
165 :
166 265 : start_addr = NaClUserToSys(nap, nap->dynamic_text_start);
167 265 : region_size = nap->dynamic_text_end - nap->dynamic_text_start;
168 265 : NaClLog(3,
169 : ("shm txt region start 0x%08"NACL_PRIxPTR", size 0x%08"NACL_PRIxS","
170 : " end 0x%08"NACL_PRIxPTR"\n"),
171 : start_addr, region_size,
172 : start_addr + region_size);
173 265 : if (0 != region_size) {
174 : /*
175 : * Page protections for this region have already been set up by
176 : * nacl_text.c.
177 : *
178 : * We record the mapping for consistency with other fixed
179 : * mappings, but the record is not actually used. Overmapping is
180 : * prevented by a separate range check, which is done by
181 : * NaClSysCommonAddrRangeContainsExecutablePages_mu().
182 : */
183 518 : NaClVmmapAdd(&nap->mem_map,
184 259 : NaClSysToUser(nap, start_addr) >> NACL_PAGESHIFT,
185 : region_size >> NACL_PAGESHIFT,
186 : NACL_ABI_PROT_READ | NACL_ABI_PROT_EXEC,
187 : NACL_ABI_MAP_PRIVATE,
188 : nap->text_shm,
189 : 0,
190 : region_size);
191 259 : }
192 :
193 265 : if (0 != nap->rodata_start) {
194 261 : uintptr_t rodata_end;
195 : /*
196 : * TODO(mseaborn): Could reduce the number of cases by ensuring
197 : * that nap->data_start is always non-zero, even if
198 : * nap->rodata_start == nap->data_start == nap->break_addr.
199 : */
200 261 : if (0 != nap->data_start) {
201 251 : rodata_end = NaClTruncAllocPage(nap->data_start);
202 251 : }
203 : else {
204 10 : rodata_end = nap->break_addr;
205 : }
206 :
207 261 : start_addr = NaClUserToSys(nap, nap->rodata_start);
208 522 : region_size = NaClRoundPage(NaClRoundAllocPage(rodata_end)
209 261 : - NaClSysToUser(nap, start_addr));
210 261 : NaClLog(3,
211 : ("RO data region start 0x%08"NACL_PRIxPTR", size 0x%08"NACL_PRIxS","
212 : " end 0x%08"NACL_PRIxPTR"\n"),
213 : start_addr, region_size,
214 : start_addr + region_size);
215 261 : if (0 != (err = NaClMprotect((void *) start_addr,
216 : region_size,
217 : PROT_READ))) {
218 0 : NaClLog(LOG_ERROR,
219 : ("NaClMemoryProtection: "
220 : "NaClMprotect(0x%08"NACL_PRIxPTR", "
221 : "0x%08"NACL_PRIxS", 0x%x) failed, "
222 : "error %d (rodata)\n"),
223 : start_addr, region_size, PROT_READ,
224 : err);
225 0 : return LOAD_MPROTECT_FAIL;
226 : }
227 522 : NaClVmmapAdd(&nap->mem_map,
228 261 : NaClSysToUser(nap, start_addr) >> NACL_PAGESHIFT,
229 : region_size >> NACL_PAGESHIFT,
230 : NACL_ABI_PROT_READ,
231 : NACL_ABI_MAP_PRIVATE,
232 : NULL,
233 : 0,
234 : 0);
235 261 : }
236 :
237 : /*
238 : * data_end is max virtual addr seen, so start_addr <= data_end
239 : * must hold.
240 : */
241 :
242 265 : if (0 != nap->data_start) {
243 251 : start_addr = NaClUserToSys(nap, NaClTruncAllocPage(nap->data_start));
244 502 : region_size = NaClRoundPage(NaClRoundAllocPage(nap->data_end)
245 251 : - NaClSysToUser(nap, start_addr));
246 251 : NaClLog(3,
247 : ("RW data region start 0x%08"NACL_PRIxPTR", size 0x%08"NACL_PRIxS","
248 : " end 0x%08"NACL_PRIxPTR"\n"),
249 : start_addr, region_size,
250 : start_addr + region_size);
251 251 : if (0 != (err = NaClMprotect((void *) start_addr,
252 : region_size,
253 : PROT_READ | PROT_WRITE))) {
254 0 : NaClLog(LOG_ERROR,
255 : ("NaClMemoryProtection: "
256 : "NaClMprotect(0x%08"NACL_PRIxPTR", "
257 : "0x%08"NACL_PRIxS", 0x%x) failed, "
258 : "error %d (data)\n"),
259 : start_addr, region_size, PROT_READ | PROT_WRITE,
260 : err);
261 0 : return LOAD_MPROTECT_FAIL;
262 : }
263 502 : NaClVmmapAdd(&nap->mem_map,
264 251 : NaClSysToUser(nap, start_addr) >> NACL_PAGESHIFT,
265 : region_size >> NACL_PAGESHIFT,
266 : NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
267 : NACL_ABI_MAP_PRIVATE,
268 : NULL,
269 : 0,
270 : 0);
271 251 : }
272 :
273 : /* stack is read/write but not execute */
274 265 : region_size = nap->stack_size;
275 530 : start_addr = NaClUserToSys(nap,
276 265 : NaClTruncAllocPage(
277 : ((uintptr_t) 1U << nap->addr_bits)
278 : - nap->stack_size));
279 265 : NaClLog(3,
280 : ("RW stack region start 0x%08"NACL_PRIxPTR", size 0x%08"NACL_PRIxS","
281 : " end 0x%08"NACL_PRIxPTR"\n"),
282 : start_addr, region_size,
283 : start_addr + region_size);
284 530 : if (0 != (err = NaClMprotect((void *) start_addr,
285 265 : NaClRoundAllocPage(nap->stack_size),
286 : PROT_READ | PROT_WRITE))) {
287 0 : NaClLog(LOG_ERROR,
288 : ("NaClMemoryProtection: "
289 : "NaClMprotect(0x%08"NACL_PRIxPTR", "
290 : "0x%08"NACL_PRIxS", 0x%x) failed, "
291 : "error %d (stack)\n"),
292 : start_addr, region_size, PROT_READ | PROT_WRITE,
293 : err);
294 0 : return LOAD_MPROTECT_FAIL;
295 : }
296 :
297 530 : NaClVmmapAdd(&nap->mem_map,
298 265 : NaClSysToUser(nap, start_addr) >> NACL_PAGESHIFT,
299 : nap->stack_size >> NACL_PAGESHIFT,
300 : NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
301 : NACL_ABI_MAP_PRIVATE,
302 : NULL,
303 : 0,
304 : 0);
305 265 : return LOAD_OK;
306 265 : }
307 :
308 0 : NaClErrorCode NaClAllocateSpace(void **mem, size_t addrsp_size) {
309 0 : return NaClAllocateSpaceAslr(mem, addrsp_size, 1);
310 : }
|