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 : #include "native_client/src/include/portability.h"
8 :
9 : #include <stdio.h>
10 : #include <string.h>
11 : #if NACL_LINUX
12 : # include <sys/mman.h>
13 : #elif NACL_OSX
14 : # include <mach/mach.h>
15 : #endif
16 :
17 : #include "native_client/src/shared/platform/nacl_log.h"
18 :
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"
22 :
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"
31 :
32 : /*
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.
36 : */
37 1 : static void InitThread(struct NaClApp *nap, struct NaClAppThread *natp) {
38 3 : memset(natp, 0xff, sizeof(*natp));
39 :
40 1 : natp->nap = nap;
41 1 : }
42 :
43 7 : void CheckLowerMappings(struct NaClVmmap *mem_map) {
44 21 : ASSERT(mem_map->nvalid >= 4);
45 : /* Zero page. */
46 21 : ASSERT_EQ(mem_map->vmentry[0]->prot, NACL_ABI_PROT_NONE);
47 : /* Trampolines and static code. */
48 21 : ASSERT_EQ(mem_map->vmentry[1]->prot,
49 : NACL_ABI_PROT_READ | NACL_ABI_PROT_EXEC);
50 : /* Read-only data segment. */
51 21 : ASSERT_EQ(mem_map->vmentry[2]->prot, NACL_ABI_PROT_READ);
52 : /* Writable data segment. */
53 21 : ASSERT_EQ(mem_map->vmentry[3]->prot,
54 : NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE);
55 7 : }
56 :
57 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64
58 2 : void CheckForGuardRegion(uintptr_t addr, size_t expected_size) {
59 : #if NACL_WINDOWS
60 : CheckGuardMapping(addr, expected_size, MEM_RESERVE, 0, MEM_PRIVATE);
61 : #elif NACL_LINUX
62 : CheckMapping(addr, expected_size, PROT_NONE, MAP_PRIVATE);
63 : #elif NACL_OSX
64 2 : CheckMapping(addr, expected_size, VM_PROT_NONE, SM_EMPTY);
65 : #else
66 : # error "Unrecognized OS"
67 : #endif
68 2 : }
69 : #endif
70 :
71 1 : int main(int argc, char **argv) {
72 1 : char *nacl_file;
73 1 : struct NaClApp state;
74 1 : struct NaClApp *nap = &state;
75 1 : struct NaClAppThread nat, *natp = &nat;
76 1 : int errcode;
77 1 : uint32_t initial_addr;
78 1 : uint32_t addr;
79 1 : struct NaClVmmap *mem_map;
80 1 : struct NaClVmmapEntry *ent;
81 1 : char *nacl_verbosity = getenv("NACLVERBOSITY");
82 :
83 1 : NaClHandleBootstrapArgs(&argc, &argv);
84 :
85 1 : if (argc < 2) {
86 0 : printf("No nexe file!\n\nFAIL\n");
87 0 : }
88 1 : nacl_file = argv[1];
89 :
90 1 : NaClAllModulesInit();
91 :
92 3 : NaClLogSetVerbosity((NULL == nacl_verbosity)
93 : ? 0
94 1 : : strtol(nacl_verbosity, (char **) 0, 0));
95 :
96 1 : errcode = NaClAppCtor(&state);
97 3 : ASSERT_NE(errcode, 0);
98 1 : errcode = NaClAppLoadFileFromFilename(nap, nacl_file);
99 3 : ASSERT_EQ(errcode, LOAD_OK);
100 :
101 1 : InitThread(&state, natp);
102 :
103 : /*
104 : * Initial mappings:
105 : * 0. -- Zero page
106 : * 1. rx Static code segment
107 : * 2. r Read-only data segment
108 : * 3. rw Writable data segment
109 : * 4. rw Stack
110 : * There is no dynamic code area in this case.
111 : */
112 1 : NaClAppPrintDetails(&state, NaClLogGetGio());
113 : /* Check the initial mappings. */
114 1 : mem_map = &state.mem_map;
115 3 : ASSERT_EQ(mem_map->nvalid, 5);
116 1 : CheckLowerMappings(mem_map);
117 :
118 : /* Allocate range */
119 1 : 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,
122 : -1, 0);
123 1 : printf("addr=0x%"NACL_PRIx32"\n", addr);
124 1 : initial_addr = addr;
125 : /*
126 : * The mappings have changed to become:
127 : * 0. -- Zero page
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)
132 : * 5. rw Stack
133 : */
134 :
135 : /* Map to overwrite the start of the previously allocated range */
136 1 : 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,
141 : -1, 0);
142 1 : printf("addr=0x%"NACL_PRIx32"\n", addr);
143 3 : ASSERT_EQ(addr, initial_addr);
144 : /*
145 : * The mappings have changed to become:
146 : * 0. -- Zero page
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)
152 : * 6. rw Stack
153 : */
154 :
155 : /* Allocate new page */
156 1 : 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,
159 : -1, 0);
160 1 : printf("addr=0x%"NACL_PRIx32"\n", addr);
161 : /*
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
165 : * didn't change.
166 : */
167 3 : ASSERT_EQ_MSG(addr, initial_addr - NACL_MAP_PAGESIZE,
168 : "Allocation strategy changed!");
169 : /*
170 : * The mappings have changed to become:
171 : * 0. -- Zero page
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
178 : * 7. rw Stack
179 : */
180 :
181 1 : NaClVmmapMakeSorted(mem_map);
182 3 : ASSERT_EQ(mem_map->nvalid, 8);
183 1 : CheckLowerMappings(mem_map);
184 1 : NaClVmmapDebug(mem_map, "After allocations");
185 : /* Skip mappings 0, 1, 2 and 3. */
186 3 : ASSERT_EQ(mem_map->vmentry[4]->page_num,
187 : (initial_addr - NACL_MAP_PAGESIZE) >> NACL_PAGESHIFT);
188 3 : ASSERT_EQ(mem_map->vmentry[4]->npages,
189 : NACL_PAGES_PER_MAP);
190 :
191 3 : ASSERT_EQ(mem_map->vmentry[5]->page_num,
192 : initial_addr >> NACL_PAGESHIFT);
193 3 : ASSERT_EQ(mem_map->vmentry[5]->npages,
194 : 2 * NACL_PAGES_PER_MAP);
195 :
196 3 : ASSERT_EQ(mem_map->vmentry[6]->page_num,
197 : (initial_addr + 2 * NACL_MAP_PAGESIZE) >> NACL_PAGESHIFT);
198 3 : ASSERT_EQ(mem_map->vmentry[6]->npages,
199 : NACL_PAGES_PER_MAP);
200 :
201 : /*
202 : * Undo effects of previous mmaps
203 : */
204 1 : errcode = NaClSysMunmap(natp,
205 : (void *) (uintptr_t) (initial_addr
206 : - NACL_MAP_PAGESIZE),
207 : NACL_MAP_PAGESIZE * 4);
208 3 : ASSERT_EQ(errcode, 0);
209 : /*
210 : * Mappings return to being:
211 : * 0. -- Zero page
212 : * 1. rx Static code segment
213 : * 2. r Read-only data segment
214 : * 3. rw Writable data segment
215 : * 4. rw Stack
216 : */
217 3 : ASSERT_EQ(mem_map->nvalid, 5);
218 1 : CheckLowerMappings(mem_map);
219 :
220 :
221 : /* Allocate range */
222 1 : 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,
225 : -1, 0);
226 1 : printf("addr=0x%"NACL_PRIx32"\n", addr);
227 1 : initial_addr = addr;
228 : /*
229 : * The mappings have changed to become:
230 : * 0. -- Zero page
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)
235 : * 5. rw Stack
236 : */
237 :
238 : /* Map into middle of previously allocated range */
239 1 : 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,
246 : -1, 0);
247 1 : printf("addr=0x%"NACL_PRIx32"\n", addr);
248 3 : ASSERT_EQ(addr, initial_addr + NACL_MAP_PAGESIZE * 2);
249 : /*
250 : * The mappings have changed to become:
251 : * 0. -- Zero page
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)
258 : * 7. rw Stack
259 : */
260 :
261 1 : NaClVmmapMakeSorted(mem_map);
262 3 : ASSERT_EQ(mem_map->nvalid, 8);
263 1 : CheckLowerMappings(mem_map);
264 :
265 3 : ASSERT_EQ(mem_map->vmentry[4]->page_num,
266 : initial_addr >> NACL_PAGESHIFT);
267 3 : ASSERT_EQ(mem_map->vmentry[4]->npages,
268 : 2 * NACL_PAGES_PER_MAP);
269 :
270 3 : ASSERT_EQ(mem_map->vmentry[5]->page_num,
271 : (initial_addr + 2 * NACL_MAP_PAGESIZE) >> NACL_PAGESHIFT);
272 3 : ASSERT_EQ(mem_map->vmentry[5]->npages,
273 : 3 * NACL_PAGES_PER_MAP);
274 :
275 3 : ASSERT_EQ(mem_map->vmentry[6]->page_num,
276 : (initial_addr + 5 * NACL_MAP_PAGESIZE) >> NACL_PAGESHIFT);
277 3 : ASSERT_EQ(mem_map->vmentry[6]->npages,
278 : 4 * NACL_PAGES_PER_MAP);
279 :
280 :
281 : /* Change the memory protection of previously allocated range */
282 1 : errcode = NaClSysMprotectInternal(nap, (initial_addr
283 : + 1 * NACL_MAP_PAGESIZE),
284 : 5 * NACL_MAP_PAGESIZE,
285 : NACL_ABI_PROT_READ);
286 3 : ASSERT_EQ(errcode, 0);
287 : /*
288 : * The mappings have changed to become:
289 : * 0. -- Zero page
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)
298 : * 9. rw Stack
299 : */
300 :
301 1 : NaClVmmapMakeSorted(mem_map);
302 3 : ASSERT_EQ(mem_map->nvalid, 10);
303 1 : CheckLowerMappings(mem_map);
304 :
305 3 : ASSERT_EQ(mem_map->vmentry[4]->npages,
306 : 1 * NACL_PAGES_PER_MAP);
307 3 : ASSERT_EQ(mem_map->vmentry[4]->prot,
308 : NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE);
309 :
310 3 : ASSERT_EQ(mem_map->vmentry[5]->npages,
311 : 1 * NACL_PAGES_PER_MAP);
312 3 : ASSERT_EQ(mem_map->vmentry[5]->prot,
313 : NACL_ABI_PROT_READ);
314 :
315 3 : ASSERT_EQ(mem_map->vmentry[6]->npages,
316 : 3 * NACL_PAGES_PER_MAP);
317 3 : ASSERT_EQ(mem_map->vmentry[6]->prot,
318 : NACL_ABI_PROT_READ);
319 :
320 3 : ASSERT_EQ(mem_map->vmentry[7]->npages,
321 : 1 * NACL_PAGES_PER_MAP);
322 3 : ASSERT_EQ(mem_map->vmentry[7]->prot,
323 : NACL_ABI_PROT_READ);
324 :
325 3 : ASSERT_EQ(mem_map->vmentry[8]->npages,
326 : 3 * NACL_PAGES_PER_MAP);
327 3 : ASSERT_EQ(mem_map->vmentry[8]->prot,
328 : NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE);
329 :
330 :
331 : /* Change the memory protection of previously allocated range */
332 1 : errcode = NaClSysMprotectInternal(nap, (initial_addr
333 : + 2 * NACL_MAP_PAGESIZE),
334 : 3 * NACL_MAP_PAGESIZE,
335 : NACL_ABI_PROT_NONE);
336 3 : ASSERT_EQ(errcode, 0);
337 : /*
338 : * The mappings have changed to become:
339 : * 0. -- Zero page
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)
348 : * 9. rw Stack
349 : */
350 :
351 1 : NaClVmmapMakeSorted(mem_map);
352 3 : ASSERT_EQ(mem_map->nvalid, 10);
353 1 : CheckLowerMappings(mem_map);
354 :
355 3 : ASSERT_EQ(mem_map->vmentry[4]->npages,
356 : 1 * NACL_PAGES_PER_MAP);
357 3 : ASSERT_EQ(mem_map->vmentry[4]->prot,
358 : NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE);
359 :
360 3 : ASSERT_EQ(mem_map->vmentry[5]->npages,
361 : 1 * NACL_PAGES_PER_MAP);
362 3 : ASSERT_EQ(mem_map->vmentry[5]->prot,
363 : NACL_ABI_PROT_READ);
364 :
365 3 : ASSERT_EQ(mem_map->vmentry[6]->npages,
366 : 3 * NACL_PAGES_PER_MAP);
367 3 : ASSERT_EQ(mem_map->vmentry[6]->prot,
368 : NACL_ABI_PROT_NONE);
369 :
370 3 : ASSERT_EQ(mem_map->vmentry[7]->npages,
371 : 1 * NACL_PAGES_PER_MAP);
372 3 : ASSERT_EQ(mem_map->vmentry[7]->prot,
373 : NACL_ABI_PROT_READ);
374 :
375 3 : ASSERT_EQ(mem_map->vmentry[8]->npages,
376 : 3 * NACL_PAGES_PER_MAP);
377 3 : ASSERT_EQ(mem_map->vmentry[8]->prot,
378 : NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE);
379 :
380 :
381 : /*
382 : * Undo effects of previous mmaps
383 : */
384 1 : errcode = NaClSysMunmap(natp, (void *) (uintptr_t) initial_addr,
385 : 9 * NACL_MAP_PAGESIZE);
386 3 : ASSERT_EQ(errcode, 0);
387 3 : ASSERT_EQ(mem_map->nvalid, 5);
388 1 : CheckLowerMappings(mem_map);
389 : /*
390 : * Mappings return to being:
391 : * 0. -- Zero page
392 : * 1. rx Static code segment
393 : * 2. r Read-only data segment
394 : * 3. rw Writable data segment
395 : * 4. rw Stack
396 : */
397 :
398 : /*
399 : * Check use of hint.
400 : */
401 1 : addr = NaClSysMmapIntern(nap, (void *) (uintptr_t) initial_addr,
402 : NACL_MAP_PAGESIZE,
403 : NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
404 : NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE,
405 : -1, 0);
406 3 : ASSERT_LE(addr, 0xffff0000u);
407 1 : printf("addr=0x%"NACL_PRIx32"\n", addr);
408 3 : ASSERT_LE_MSG(initial_addr, addr, "returned address not at or above hint");
409 1 : errcode = NaClSysMunmap(natp, (void *) (uintptr_t) addr, NACL_MAP_PAGESIZE);
410 3 : ASSERT_EQ(errcode, 0);
411 :
412 : /* Check handling of zero-sized mappings. */
413 1 : addr = NaClSysMmapIntern(nap, 0, 0,
414 : NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
415 : NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE,
416 : -1, 0);
417 3 : ASSERT_EQ((int) addr, -NACL_ABI_EINVAL);
418 :
419 1 : errcode = NaClSysMunmap(natp, (void *) (uintptr_t) initial_addr, 0);
420 3 : ASSERT_EQ(errcode, -NACL_ABI_EINVAL);
421 :
422 : /* Check changing the memory protection of neighbouring mmaps */
423 1 : 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,
426 : -1, 0);
427 1 : printf("addr=0x%"NACL_PRIx32"\n", addr);
428 1 : initial_addr = addr;
429 1 : addr = NaClSysMmapIntern(nap, (void *) (uintptr_t) (initial_addr +
430 : NACL_MAP_PAGESIZE),
431 : NACL_MAP_PAGESIZE,
432 : NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
433 : NACL_ABI_MAP_ANONYMOUS | NACL_ABI_MAP_PRIVATE
434 : | NACL_ABI_MAP_FIXED,
435 : -1, 0);
436 1 : printf("addr=0x%"NACL_PRIx32"\n", addr);
437 3 : ASSERT_EQ(addr, initial_addr + NACL_MAP_PAGESIZE);
438 :
439 1 : errcode = NaClSysMprotectInternal(nap, initial_addr,
440 : 2 * NACL_MAP_PAGESIZE,
441 : NACL_ABI_PROT_READ);
442 3 : ASSERT_EQ(errcode, 0);
443 :
444 : /* Undo effects of previous mmaps */
445 1 : errcode = NaClSysMunmap(natp, (void *) (uintptr_t) initial_addr,
446 : 2 * NACL_MAP_PAGESIZE);
447 3 : ASSERT_EQ(errcode, 0);
448 :
449 : /* Check that we cannot make the read-only data segment writable */
450 1 : ent = mem_map->vmentry[2];
451 1 : errcode = NaClSysMprotectInternal(nap, (uint32_t) (ent->page_num <<
452 : NACL_PAGESHIFT),
453 : ent->npages * NACL_MAP_PAGESIZE,
454 : NACL_ABI_PROT_WRITE);
455 3 : ASSERT_EQ(errcode, -NACL_ABI_EACCES);
456 :
457 : #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64
458 1 : CheckForGuardRegion(nap->mem_start - ((size_t) 40 << 30), (size_t) 40 << 30);
459 1 : CheckForGuardRegion(nap->mem_start + ((size_t) 4 << 30), (size_t) 40 << 30);
460 : #endif
461 :
462 1 : NaClAddrSpaceFree(nap);
463 :
464 1 : printf("PASS\n");
465 1 : return 0;
466 : }
|