104dbd64a8bfc6f0d08731066a9917e942480592
[platform/framework/web/crosswalk.git] / src / native_client / src / trusted / service_runtime / mmap_test.c
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 static void InitThread(struct NaClApp *nap, struct NaClAppThread *natp) {
38   memset(natp, 0xff, sizeof(*natp));
39
40   natp->nap = nap;
41 }
42
43 void CheckLowerMappings(struct NaClVmmap *mem_map) {
44   ASSERT(mem_map->nvalid >= 4);
45   /* Zero page. */
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);
55 }
56
57 #if NACL_ARCH(NACL_BUILD_ARCH) == NACL_x86 && NACL_BUILD_SUBARCH == 64
58 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   CheckMapping(addr, expected_size, VM_PROT_NONE, SM_EMPTY);
65 #else
66 # error "Unrecognized OS"
67 #endif
68 }
69 #endif
70
71 int main(int argc, char **argv) {
72   char *nacl_file;
73   struct NaClApp state;
74   struct NaClApp *nap = &state;
75   struct NaClAppThread nat, *natp = &nat;
76   int errcode;
77   uint32_t initial_addr;
78   uint32_t addr;
79   struct NaClVmmap *mem_map;
80   struct NaClVmmapEntry *ent;
81   char *nacl_verbosity = getenv("NACLVERBOSITY");
82
83   NaClHandleBootstrapArgs(&argc, &argv);
84
85   if (argc < 2) {
86     printf("No nexe file!\n\nFAIL\n");
87   }
88   nacl_file = argv[1];
89
90   NaClAllModulesInit();
91
92   NaClLogSetVerbosity((NULL == nacl_verbosity)
93                       ? 0
94                       : strtol(nacl_verbosity, (char **) 0, 0));
95
96   errcode = NaClAppCtor(&state);
97   ASSERT_NE(errcode, 0);
98   errcode = NaClAppLoadFileFromFilename(nap, nacl_file);
99   ASSERT_EQ(errcode, LOAD_OK);
100
101   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   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);
117
118   /* Allocate range */
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,
122                            -1, 0);
123   printf("addr=0x%"NACL_PRIx32"\n", addr);
124   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   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   printf("addr=0x%"NACL_PRIx32"\n", addr);
143   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   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   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   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   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,
189             NACL_PAGES_PER_MAP);
190
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);
195
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,
199             NACL_PAGES_PER_MAP);
200
201   /*
202    * Undo effects of previous mmaps
203    */
204   errcode = NaClSysMunmap(natp,
205                           (void *) (uintptr_t) (initial_addr
206                                                 - NACL_MAP_PAGESIZE),
207                           NACL_MAP_PAGESIZE * 4);
208   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   ASSERT_EQ(mem_map->nvalid, 5);
218   CheckLowerMappings(mem_map);
219
220
221   /* Allocate range */
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,
225                            -1, 0);
226   printf("addr=0x%"NACL_PRIx32"\n", addr);
227   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   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   printf("addr=0x%"NACL_PRIx32"\n", addr);
248   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   NaClVmmapMakeSorted(mem_map);
262   ASSERT_EQ(mem_map->nvalid, 8);
263   CheckLowerMappings(mem_map);
264
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);
269
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);
274
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);
279
280
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,
285                                     NACL_ABI_PROT_READ);
286   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   NaClVmmapMakeSorted(mem_map);
302   ASSERT_EQ(mem_map->nvalid, 10);
303   CheckLowerMappings(mem_map);
304
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);
309
310   ASSERT_EQ(mem_map->vmentry[5]->npages,
311             1 * NACL_PAGES_PER_MAP);
312   ASSERT_EQ(mem_map->vmentry[5]->prot,
313             NACL_ABI_PROT_READ);
314
315   ASSERT_EQ(mem_map->vmentry[6]->npages,
316             3 * NACL_PAGES_PER_MAP);
317   ASSERT_EQ(mem_map->vmentry[6]->prot,
318             NACL_ABI_PROT_READ);
319
320   ASSERT_EQ(mem_map->vmentry[7]->npages,
321             1 * NACL_PAGES_PER_MAP);
322   ASSERT_EQ(mem_map->vmentry[7]->prot,
323             NACL_ABI_PROT_READ);
324
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);
329
330
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,
335                                     NACL_ABI_PROT_NONE);
336   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   NaClVmmapMakeSorted(mem_map);
352   ASSERT_EQ(mem_map->nvalid, 10);
353   CheckLowerMappings(mem_map);
354
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);
359
360   ASSERT_EQ(mem_map->vmentry[5]->npages,
361             1 * NACL_PAGES_PER_MAP);
362   ASSERT_EQ(mem_map->vmentry[5]->prot,
363             NACL_ABI_PROT_READ);
364
365   ASSERT_EQ(mem_map->vmentry[6]->npages,
366             3 * NACL_PAGES_PER_MAP);
367   ASSERT_EQ(mem_map->vmentry[6]->prot,
368             NACL_ABI_PROT_NONE);
369
370   ASSERT_EQ(mem_map->vmentry[7]->npages,
371             1 * NACL_PAGES_PER_MAP);
372   ASSERT_EQ(mem_map->vmentry[7]->prot,
373             NACL_ABI_PROT_READ);
374
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);
379
380
381   /*
382    * Undo effects of previous mmaps
383    */
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);
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   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   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);
411
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,
416                            -1, 0);
417   ASSERT_EQ((int) addr, -NACL_ABI_EINVAL);
418
419   errcode = NaClSysMunmap(natp, (void *) (uintptr_t) initial_addr, 0);
420   ASSERT_EQ(errcode, -NACL_ABI_EINVAL);
421
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,
426                            -1, 0);
427   printf("addr=0x%"NACL_PRIx32"\n", addr);
428   initial_addr = addr;
429   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   printf("addr=0x%"NACL_PRIx32"\n", addr);
437   ASSERT_EQ(addr, initial_addr + NACL_MAP_PAGESIZE);
438
439   errcode = NaClSysMprotectInternal(nap, initial_addr,
440                                     2 * NACL_MAP_PAGESIZE,
441                                     NACL_ABI_PROT_READ);
442   ASSERT_EQ(errcode, 0);
443
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);
448
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 <<
452                                                      NACL_PAGESHIFT),
453                                     ent->npages * NACL_MAP_PAGESIZE,
454                                     NACL_ABI_PROT_WRITE);
455   ASSERT_EQ(errcode, -NACL_ABI_EACCES);
456
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);
460 #endif
461
462   NaClAddrSpaceFree(nap);
463
464   printf("PASS\n");
465   return 0;
466 }