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.
7 #include "native_client/src/include/portability.h"
12 # include <sys/mman.h>
14 # include <mach/mach.h>
17 #include "native_client/src/shared/platform/nacl_log.h"
19 #include "native_client/src/trusted/service_runtime/include/bits/mman.h"
20 #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
21 #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
23 #include "native_client/src/include/nacl_assert.h"
24 #include "native_client/src/trusted/service_runtime/load_file.h"
25 #include "native_client/src/trusted/service_runtime/mmap_test_check.h"
26 #include "native_client/src/trusted/service_runtime/nacl_all_modules.h"
27 #include "native_client/src/trusted/service_runtime/nacl_app_thread.h"
28 #include "native_client/src/trusted/service_runtime/sel_addrspace.h"
29 #include "native_client/src/trusted/service_runtime/sel_ldr.h"
30 #include "native_client/src/trusted/service_runtime/sys_memory.h"
33 * Perform some minimal initialisation of the NaClAppThread based on
34 * what we need for the test. Reusing NaClAppThreadMake() here is
35 * difficult because it launches an untrusted thread.
37 static void InitThread(struct NaClApp *nap, struct NaClAppThread *natp) {
38 memset(natp, 0xff, sizeof(*natp));
43 void CheckLowerMappings(struct NaClVmmap *mem_map) {
44 ASSERT(mem_map->nvalid >= 4);
46 ASSERT_EQ(mem_map->vmentry[0]->prot, NACL_ABI_PROT_NONE);
47 /* Trampolines and static code. */
48 ASSERT_EQ(mem_map->vmentry[1]->prot,
49 NACL_ABI_PROT_READ | NACL_ABI_PROT_EXEC);
50 /* Read-only data segment. */
51 ASSERT_EQ(mem_map->vmentry[2]->prot, NACL_ABI_PROT_READ);
52 /* Writable data segment. */
53 ASSERT_EQ(mem_map->vmentry[3]->prot,
54 NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE);
57 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64
58 void CheckForGuardRegion(uintptr_t addr, size_t expected_size) {
60 CheckGuardMapping(addr, expected_size, MEM_RESERVE, 0, MEM_PRIVATE);
62 CheckMapping(addr, expected_size, PROT_NONE, MAP_PRIVATE);
64 CheckMapping(addr, expected_size, VM_PROT_NONE, SM_EMPTY);
66 # error "Unrecognized OS"
71 int main(int argc, char **argv) {
74 struct NaClApp *nap = &state;
75 struct NaClAppThread nat, *natp = &nat;
77 uint32_t initial_addr;
79 struct NaClVmmap *mem_map;
80 struct NaClVmmapEntry *ent;
81 char *nacl_verbosity = getenv("NACLVERBOSITY");
83 NaClHandleBootstrapArgs(&argc, &argv);
86 printf("No nexe file!\n\nFAIL\n");
92 NaClLogSetVerbosity((NULL == nacl_verbosity)
94 : strtol(nacl_verbosity, (char **) 0, 0));
96 errcode = NaClAppCtor(&state);
97 ASSERT_NE(errcode, 0);
98 errcode = NaClAppLoadFileFromFilename(nap, nacl_file);
99 ASSERT_EQ(errcode, LOAD_OK);
101 InitThread(&state, natp);
106 * 1. rx Static code segment
107 * 2. r Read-only data segment
108 * 3. rw Writable data segment
110 * There is no dynamic code area in this case.
112 NaClAppPrintDetails(&state, NaClLogGetGio());
113 /* Check the initial mappings. */
114 mem_map = &state.mem_map;
115 ASSERT_EQ(mem_map->nvalid, 5);
116 CheckLowerMappings(mem_map);
119 addr = NaClSysMmapIntern(nap, 0, 3 * NACL_MAP_PAGESIZE,
120 NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
121 NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE,
123 printf("addr=0x%"NACL_PRIx32"\n", addr);
126 * The mappings have changed to become:
128 * 1. rx Static code segment
129 * 2. r Read-only data segment
130 * 3. rw Writable data segment
131 * 4. rw mmap()'d anonymous, 3 pages (new)
135 /* Map to overwrite the start of the previously allocated range */
136 addr = NaClSysMmapIntern(nap, (void *) (uintptr_t) initial_addr,
137 2 * NACL_MAP_PAGESIZE,
138 NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
139 NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE
140 | NACL_ABI_MAP_FIXED,
142 printf("addr=0x%"NACL_PRIx32"\n", addr);
143 ASSERT_EQ(addr, initial_addr);
145 * The mappings have changed to become:
147 * 1. rx Static code segment
148 * 2. r Read-only data segment
149 * 3. rw Writable data segment
150 * 4. rw mmap()'d anonymous, 2 pages (new)
151 * 5. rw mmap()'d anonymous, 1 pages (previous)
155 /* Allocate new page */
156 addr = NaClSysMmapIntern(nap, 0, NACL_MAP_PAGESIZE,
157 NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
158 NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE,
160 printf("addr=0x%"NACL_PRIx32"\n", addr);
162 * Our allocation strategy is to scan down from stack. This is an
163 * implementation detail and not part of the guaranteed semantics,
164 * but it is good to test that what we expect of our implementation
167 ASSERT_EQ_MSG(addr, initial_addr - NACL_MAP_PAGESIZE,
168 "Allocation strategy changed!");
170 * The mappings have changed to become:
172 * 1. rx Static code segment
173 * 2. r Read-only data segment
174 * 3. rw Writable data segment
175 * 4. rw mmap()'d anonymous, 1 pages (new)
176 * 5. rw mmap()'d anonymous, 2 pages
177 * 6. rw mmap()'d anonymous, 1 pages
181 NaClVmmapMakeSorted(mem_map);
182 ASSERT_EQ(mem_map->nvalid, 8);
183 CheckLowerMappings(mem_map);
184 NaClVmmapDebug(mem_map, "After allocations");
185 /* Skip mappings 0, 1, 2 and 3. */
186 ASSERT_EQ(mem_map->vmentry[4]->page_num,
187 (initial_addr - NACL_MAP_PAGESIZE) >> NACL_PAGESHIFT);
188 ASSERT_EQ(mem_map->vmentry[4]->npages,
191 ASSERT_EQ(mem_map->vmentry[5]->page_num,
192 initial_addr >> NACL_PAGESHIFT);
193 ASSERT_EQ(mem_map->vmentry[5]->npages,
194 2 * NACL_PAGES_PER_MAP);
196 ASSERT_EQ(mem_map->vmentry[6]->page_num,
197 (initial_addr + 2 * NACL_MAP_PAGESIZE) >> NACL_PAGESHIFT);
198 ASSERT_EQ(mem_map->vmentry[6]->npages,
202 * Undo effects of previous mmaps
204 errcode = NaClSysMunmap(natp,
205 (void *) (uintptr_t) (initial_addr
206 - NACL_MAP_PAGESIZE),
207 NACL_MAP_PAGESIZE * 4);
208 ASSERT_EQ(errcode, 0);
210 * Mappings return to being:
212 * 1. rx Static code segment
213 * 2. r Read-only data segment
214 * 3. rw Writable data segment
217 ASSERT_EQ(mem_map->nvalid, 5);
218 CheckLowerMappings(mem_map);
222 addr = NaClSysMmapIntern(nap, 0, 9 * NACL_MAP_PAGESIZE,
223 NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
224 NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE,
226 printf("addr=0x%"NACL_PRIx32"\n", addr);
229 * The mappings have changed to become:
231 * 1. rx Static code segment
232 * 2. r Read-only data segment
233 * 3. rw Writable data segment
234 * 4. rw mmap()'d anonymous, 9 pages (new)
238 /* Map into middle of previously allocated range */
239 addr = NaClSysMmapIntern(nap,
240 (void *) (uintptr_t) (initial_addr
241 + 2 * NACL_MAP_PAGESIZE),
242 3 * NACL_MAP_PAGESIZE,
243 NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
244 NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE
245 | NACL_ABI_MAP_FIXED,
247 printf("addr=0x%"NACL_PRIx32"\n", addr);
248 ASSERT_EQ(addr, initial_addr + NACL_MAP_PAGESIZE * 2);
250 * The mappings have changed to become:
252 * 1. rx Static code segment
253 * 2. r Read-only data segment
254 * 3. rw Writable data segment
255 * 4. rw mmap()'d anonymous, 2 pages (previous)
256 * 5. rw mmap()'d anonymous, 3 pages (new)
257 * 6. rw mmap()'d anonymous, 4 pages (previous)
261 NaClVmmapMakeSorted(mem_map);
262 ASSERT_EQ(mem_map->nvalid, 8);
263 CheckLowerMappings(mem_map);
265 ASSERT_EQ(mem_map->vmentry[4]->page_num,
266 initial_addr >> NACL_PAGESHIFT);
267 ASSERT_EQ(mem_map->vmentry[4]->npages,
268 2 * NACL_PAGES_PER_MAP);
270 ASSERT_EQ(mem_map->vmentry[5]->page_num,
271 (initial_addr + 2 * NACL_MAP_PAGESIZE) >> NACL_PAGESHIFT);
272 ASSERT_EQ(mem_map->vmentry[5]->npages,
273 3 * NACL_PAGES_PER_MAP);
275 ASSERT_EQ(mem_map->vmentry[6]->page_num,
276 (initial_addr + 5 * NACL_MAP_PAGESIZE) >> NACL_PAGESHIFT);
277 ASSERT_EQ(mem_map->vmentry[6]->npages,
278 4 * NACL_PAGES_PER_MAP);
281 /* Change the memory protection of previously allocated range */
282 errcode = NaClSysMprotectInternal(nap, (initial_addr
283 + 1 * NACL_MAP_PAGESIZE),
284 5 * NACL_MAP_PAGESIZE,
286 ASSERT_EQ(errcode, 0);
288 * The mappings have changed to become:
290 * 1. rx Static code segment
291 * 2. r Read-only data segment
292 * 3. rw Writable data segment
293 * 4. rw mmap()'d anonymous, 1 pages (previous)
294 * 5. r mmap()'d anonymous, 1 pages (new)
295 * 6. r mmap()'d anonymous, 3 pages (new)
296 * 7. r mmap()'d anonymous, 1 pages (new)
297 * 8. rw mmap()'d anonymous, 3 pages (previous)
301 NaClVmmapMakeSorted(mem_map);
302 ASSERT_EQ(mem_map->nvalid, 10);
303 CheckLowerMappings(mem_map);
305 ASSERT_EQ(mem_map->vmentry[4]->npages,
306 1 * NACL_PAGES_PER_MAP);
307 ASSERT_EQ(mem_map->vmentry[4]->prot,
308 NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE);
310 ASSERT_EQ(mem_map->vmentry[5]->npages,
311 1 * NACL_PAGES_PER_MAP);
312 ASSERT_EQ(mem_map->vmentry[5]->prot,
315 ASSERT_EQ(mem_map->vmentry[6]->npages,
316 3 * NACL_PAGES_PER_MAP);
317 ASSERT_EQ(mem_map->vmentry[6]->prot,
320 ASSERT_EQ(mem_map->vmentry[7]->npages,
321 1 * NACL_PAGES_PER_MAP);
322 ASSERT_EQ(mem_map->vmentry[7]->prot,
325 ASSERT_EQ(mem_map->vmentry[8]->npages,
326 3 * NACL_PAGES_PER_MAP);
327 ASSERT_EQ(mem_map->vmentry[8]->prot,
328 NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE);
331 /* Change the memory protection of previously allocated range */
332 errcode = NaClSysMprotectInternal(nap, (initial_addr
333 + 2 * NACL_MAP_PAGESIZE),
334 3 * NACL_MAP_PAGESIZE,
336 ASSERT_EQ(errcode, 0);
338 * The mappings have changed to become:
340 * 1. rx Static code segment
341 * 2. r Read-only data segment
342 * 3. rw Writable data segment
343 * 4. rw mmap()'d anonymous, 1 pages (previous)
344 * 5. r mmap()'d anonymous, 1 pages (previous)
345 * 6. -- mmap()'d anonymous, 3 pages (new)
346 * 7. r mmap()'d anonymous, 1 pages (previous)
347 * 8. rw mmap()'d anonymous, 3 pages (previous)
351 NaClVmmapMakeSorted(mem_map);
352 ASSERT_EQ(mem_map->nvalid, 10);
353 CheckLowerMappings(mem_map);
355 ASSERT_EQ(mem_map->vmentry[4]->npages,
356 1 * NACL_PAGES_PER_MAP);
357 ASSERT_EQ(mem_map->vmentry[4]->prot,
358 NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE);
360 ASSERT_EQ(mem_map->vmentry[5]->npages,
361 1 * NACL_PAGES_PER_MAP);
362 ASSERT_EQ(mem_map->vmentry[5]->prot,
365 ASSERT_EQ(mem_map->vmentry[6]->npages,
366 3 * NACL_PAGES_PER_MAP);
367 ASSERT_EQ(mem_map->vmentry[6]->prot,
370 ASSERT_EQ(mem_map->vmentry[7]->npages,
371 1 * NACL_PAGES_PER_MAP);
372 ASSERT_EQ(mem_map->vmentry[7]->prot,
375 ASSERT_EQ(mem_map->vmentry[8]->npages,
376 3 * NACL_PAGES_PER_MAP);
377 ASSERT_EQ(mem_map->vmentry[8]->prot,
378 NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE);
382 * Undo effects of previous mmaps
384 errcode = NaClSysMunmap(natp, (void *) (uintptr_t) initial_addr,
385 9 * NACL_MAP_PAGESIZE);
386 ASSERT_EQ(errcode, 0);
387 ASSERT_EQ(mem_map->nvalid, 5);
388 CheckLowerMappings(mem_map);
390 * Mappings return to being:
392 * 1. rx Static code segment
393 * 2. r Read-only data segment
394 * 3. rw Writable data segment
401 addr = NaClSysMmapIntern(nap, (void *) (uintptr_t) initial_addr,
403 NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
404 NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE,
406 ASSERT_LE(addr, 0xffff0000u);
407 printf("addr=0x%"NACL_PRIx32"\n", addr);
408 ASSERT_LE_MSG(initial_addr, addr, "returned address not at or above hint");
409 errcode = NaClSysMunmap(natp, (void *) (uintptr_t) addr, NACL_MAP_PAGESIZE);
410 ASSERT_EQ(errcode, 0);
412 /* Check handling of zero-sized mappings. */
413 addr = NaClSysMmapIntern(nap, 0, 0,
414 NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
415 NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE,
417 ASSERT_EQ((int) addr, -NACL_ABI_EINVAL);
419 errcode = NaClSysMunmap(natp, (void *) (uintptr_t) initial_addr, 0);
420 ASSERT_EQ(errcode, -NACL_ABI_EINVAL);
422 /* Check changing the memory protection of neighbouring mmaps */
423 addr = NaClSysMmapIntern(nap, 0, NACL_MAP_PAGESIZE,
424 NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
425 NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE,
427 printf("addr=0x%"NACL_PRIx32"\n", addr);
429 addr = NaClSysMmapIntern(nap, (void *) (uintptr_t) (initial_addr +
432 NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
433 NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE
434 | NACL_ABI_MAP_FIXED,
436 printf("addr=0x%"NACL_PRIx32"\n", addr);
437 ASSERT_EQ(addr, initial_addr + NACL_MAP_PAGESIZE);
439 errcode = NaClSysMprotectInternal(nap, initial_addr,
440 2 * NACL_MAP_PAGESIZE,
442 ASSERT_EQ(errcode, 0);
444 /* Undo effects of previous mmaps */
445 errcode = NaClSysMunmap(natp, (void *) (uintptr_t) initial_addr,
446 2 * NACL_MAP_PAGESIZE);
447 ASSERT_EQ(errcode, 0);
449 /* Check that we cannot make the read-only data segment writable */
450 ent = mem_map->vmentry[2];
451 errcode = NaClSysMprotectInternal(nap, (uint32_t) (ent->page_num <<
453 ent->npages * NACL_MAP_PAGESIZE,
454 NACL_ABI_PROT_WRITE);
455 ASSERT_EQ(errcode, -NACL_ABI_EACCES);
457 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64
458 CheckForGuardRegion(nap->mem_start - ((size_t) 40 << 30), (size_t) 40 << 30);
459 CheckForGuardRegion(nap->mem_start + ((size_t) 4 << 30), (size_t) 40 << 30);
462 NaClAddrSpaceFree(nap);