1 /*
2  * Copyright (c) 2013 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 <fcntl.h>
8 #include <limits.h>
9 #include <stdio.h>
10 #include <string.h>
11 
12 #include <windows.h>
13 #include <io.h>
14 
15 #include "native_client/src/include/portability.h"
16 #include "native_client/src/include/nacl_compiler_annotations.h"
17 #include "native_client/src/include/nacl_macros.h"
18 
19 #include "native_client/src/shared/platform/nacl_check.h"
20 #include "native_client/src/shared/platform/nacl_host_desc.h"
21 #include "native_client/src/shared/platform/nacl_log.h"
22 #include "native_client/src/shared/platform/platform_init.h"
23 #include "native_client/src/trusted/desc/nacl_desc_effector.h"
24 #include "native_client/src/trusted/desc/nacl_desc_effector_trusted_mem.h"
25 #include "native_client/src/trusted/service_runtime/include/bits/mman.h"
26 #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
27 #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
28 
29 /* bool */
TryToMap(struct NaClHostDesc * hd,size_t map_bytes,int prot,int flags,int expected_errno)30 int TryToMap(struct NaClHostDesc *hd, size_t map_bytes, int prot, int flags,
31              int expected_errno) {
32   uintptr_t addr;
33 
34   addr = NaClHostDescMap(hd,
35                          NaClDescEffectorTrustedMem(),
36                          NULL,
37                          map_bytes,
38                          prot,
39                          flags,
40                          0);
41   if (0 == expected_errno) {
42     if ((uintptr_t) -4095 < addr) {
43       NaClLog(LOG_ERROR, "NaClHostDescMap returned errno %d\n", -(int) addr);
44       return 0;
45     }
46     NaClHostDescUnmapUnsafe((void *) addr, map_bytes);
47     return 1;
48   } else {
49     if ((uintptr_t) -4095 < addr) {
50       if (expected_errno != -(int) addr) {
51         NaClLog(LOG_ERROR, "NaClHostDescMap returned errno %d, expected %d\n",
52                 -(int) addr, expected_errno);
53       }
54     } else {
55       NaClLog(LOG_ERROR, "NaClHostDescMap succeeded, expected errno %d\n",
56               expected_errno);
57       NaClHostDescUnmapUnsafe((void *) addr, map_bytes);
58     }
59     return expected_errno == -(int) addr;
60   }
61 }
62 
WriteTestData(HANDLE hFile,size_t file_size)63 void WriteTestData(HANDLE hFile, size_t file_size) {
64   char buffer[4096];
65   size_t to_write;
66   size_t write_request;
67   DWORD written;
68 
69   memset(buffer, 0, sizeof buffer);
70   for (to_write = file_size; to_write > 0; to_write -= written) {
71     write_request = sizeof buffer;
72     if (write_request > to_write) {
73       write_request = to_write;
74     }
75     written = 0;
76     CHECK(WriteFile(hFile, buffer, (DWORD) write_request, &written, NULL));
77   }
78 }
79 
80 struct FileCreationArgs {
81   char const *file_type_description;
82   DWORD desired_access;
83   DWORD share_mode;
84   DWORD flags_and_attributes;
85   size_t file_size;
86 };
87 
88 /* bool */
CreateTestFile(char const * path,struct FileCreationArgs * args)89 HANDLE CreateTestFile(char const *path, struct FileCreationArgs *args) {
90   HANDLE h;
91 
92   NaClLog(1,
93           "CreateFile(%s, %d, %d, NULL, OPEN_EXISTING, %d, NULL),"
94           " size 0x%"NACL_PRIxS"\n",
95           path, args->desired_access, args->share_mode,
96           args->flags_and_attributes,
97           args->file_size);
98   h = CreateFileA(path,
99                   GENERIC_WRITE,
100                   0,
101                   NULL,
102                   CREATE_ALWAYS,
103                   args->flags_and_attributes,
104                   NULL);
105   if (INVALID_HANDLE_VALUE == h) {
106     DWORD err = GetLastError();
107     NaClLog(2, "CreateTestFile for %s failed, error %d\n", path, err);
108     return INVALID_HANDLE_VALUE;
109   }
110   WriteTestData(h, args->file_size);
111   if (!CloseHandle(h)) {
112     DWORD err = GetLastError();
113     NaClLog(LOG_WARNING, "CloseHandle for %s failed, error %d\n", path, err);
114   }
115   h = CreateFileA(path,
116                   args->desired_access,
117                   args->share_mode,
118                   NULL,
119                   OPEN_EXISTING,
120                   args->flags_and_attributes,
121                   NULL);
122   /* h might be INVALID_HANDLE_VALUE */
123   return h;
124 }
125 
AttemptToDeleteTestFile(char const * path)126 void AttemptToDeleteTestFile(char const *path) {
127   DWORD attr;
128 
129   attr = GetFileAttributesA(path);
130   CHECK(INVALID_FILE_ATTRIBUTES != attr);
131   if (0 != (attr & FILE_ATTRIBUTE_READONLY)) {
132     attr &= ~FILE_ATTRIBUTE_READONLY;
133     CHECK(SetFileAttributesA(path, attr));
134   }
135   if (!DeleteFileA(path)) {
136     DWORD err = GetLastError();
137     NaClLog(LOG_WARNING, "DeleteFileA failed, error %d\n", err);
138   }
139 }
140 
141 struct FileCreationArgs g_normal_rwx_file = {
142   "Normal file, GENERIC_(READ|WRITE|EXECUTE), FILE_SHARE_ALL, NORMAL",
143   GENERIC_READ|GENERIC_WRITE|GENERIC_EXECUTE,
144   FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
145   FILE_ATTRIBUTE_NORMAL,
146   2 << 16,
147 };
148 
149 struct FileCreationArgs g_normal_rw_file = {
150   "Normal file, GENERIC_(READ|WRITE), FILE_SHARE_ALL, NORMAL",
151   GENERIC_READ|GENERIC_WRITE,
152   FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
153   FILE_ATTRIBUTE_NORMAL,
154   2 << 16,
155 };
156 
157 struct FileCreationArgs g_normal_r_file = {
158   "Normal file, GENERIC_READ, FILE_SHARE_ALL, NORMAL",
159   GENERIC_READ,
160   FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
161   FILE_ATTRIBUTE_NORMAL,
162   2 << 16,
163 };
164 
165 struct FileCreationArgs g_readonly_rwx_file = {
166   "Readonly file, GENERIC_(READ|WRITE|EXECUTE), FILE_SHARE_ALL, READONLY",
167   GENERIC_READ|GENERIC_WRITE|GENERIC_EXECUTE,
168   FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
169   FILE_ATTRIBUTE_READONLY,
170   2 << 16,
171 };
172 struct FileCreationArgs g_readonly_rw_file = {
173   "Readonly file, GENERIC_(READ|WRITE), FILE_SHARE_ALL, READONLY",
174   GENERIC_READ|GENERIC_WRITE,
175   FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
176   FILE_ATTRIBUTE_READONLY,
177   2 << 16,
178 };
179 
180 struct FileCreationArgs g_readonly_r_file = {
181   "Readonly file, GENERIC_READ, FILE_SHARE_ALL, READONLY",
182   GENERIC_READ,
183   FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
184   FILE_ATTRIBUTE_READONLY,
185   2 << 16,
186 };
187 
188 struct TestParam {
189   char const *test_info;
190   struct FileCreationArgs *file_type;
191   size_t map_bytes;
192   int prot;
193   int map_flags;
194   int oflags;
195   int posix_flags;
196   int expected_open_error;  /* GetLastError */
197   int expected_mmap_errno;
198 } tests[] = {
199   {
200     "Mapping normal rwx file, PROT_ALL, PRIVATE",
201     &g_normal_rwx_file,
202     1 << 16,
203     NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE | NACL_ABI_PROT_EXEC,
204     NACL_ABI_MAP_PRIVATE,
205     _O_RDWR | _O_BINARY,
206     NACL_ABI_O_RDWR,
207     /* expected_open_error= */ ERROR_SUCCESS,
208     /* expected_mmap_errno= */ 0,
209   }, {
210     "Mapping normal rw file, PROT_ALL, PRIVATE",
211     &g_normal_rw_file,
212     1 << 16,
213     NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE | NACL_ABI_PROT_EXEC,
214     NACL_ABI_MAP_PRIVATE,
215     _O_RDWR | _O_BINARY,
216     NACL_ABI_O_RDWR,
217     /* expected_open_error= */ ERROR_SUCCESS,
218     /* expected_mmap_errno= */ NACL_ABI_EACCES,
219   }, {
220     "Mapping normal rw file, PROT_(READ|WRITE), PRIVATE",
221     &g_normal_rw_file,
222     1 << 16,
223     NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
224     NACL_ABI_MAP_PRIVATE,
225     _O_RDWR | _O_BINARY,
226     NACL_ABI_O_RDWR,
227     /* expected_open_error= */ ERROR_SUCCESS,
228     /* expected_mmap_errno= */ 0,
229   }, {
230     "Mapping normal ro file, PROT_READ, PRIVATE",
231     &g_normal_r_file,
232     1 << 16,
233     NACL_ABI_PROT_READ,
234     NACL_ABI_MAP_PRIVATE,
235     _O_RDONLY | _O_BINARY,
236     NACL_ABI_O_RDONLY,
237     /* expected_open_error= */ ERROR_SUCCESS,
238     /* expected_mmap_errno= */ 0,
239   }, {
240     "Mapping normal ro file, PROT_(READ|WRITE), PRIVATE",
241     &g_normal_r_file,
242     1 << 16,
243     NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
244     NACL_ABI_MAP_PRIVATE,
245     _O_RDONLY | _O_BINARY,
246     NACL_ABI_O_RDONLY,
247     /* expected_open_error= */ ERROR_SUCCESS,
248     /* expected_mmap_errno= */ 0,
249   }, {
250     "Mapping normal rwx file, PROT_ALL, SHARED",
251     &g_normal_rwx_file,
252     1 << 16,
253     NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE | NACL_ABI_PROT_EXEC,
254     NACL_ABI_MAP_SHARED,
255     _O_RDWR | _O_BINARY,
256     NACL_ABI_O_RDWR,
257     /* expected_open_error= */ ERROR_SUCCESS,
258     /* expected_mmap_errno= */ 0,
259   }, {
260     "Mapping normal rw file, PROT_(READ|WRITE), SHARED",
261     &g_normal_rw_file,
262     1 << 16,
263     NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
264     NACL_ABI_MAP_SHARED,
265     _O_RDWR | _O_BINARY,
266     NACL_ABI_O_RDWR,
267     /* expected_open_error= */ ERROR_SUCCESS,
268     /* expected_mmap_errno= */ 0,
269   }, {
270     "Mapping normal ro file, PROT_READ, SHARED",
271     &g_normal_r_file,
272     1 << 16,
273     NACL_ABI_PROT_READ,
274     NACL_ABI_MAP_SHARED,
275     _O_RDONLY | _O_BINARY,
276     NACL_ABI_O_RDONLY,
277     /* expected_open_error= */ ERROR_SUCCESS,
278     /* expected_mmap_errno= */ 0,
279   }, {
280     "Mapping normal ro file, PROT_(READ|WRITE), SHARED",
281     &g_normal_r_file,
282     1 << 16,
283     NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
284     NACL_ABI_MAP_SHARED,
285     _O_RDONLY | _O_BINARY,
286     NACL_ABI_O_RDONLY,
287     /* expected_open_error= */ ERROR_SUCCESS,
288     /* expected_mmap_errno= */ NACL_ABI_EACCES,
289   }, {
290     "Mapping ro rwx file, PROT_ALL, PRIVATE",
291     &g_readonly_rwx_file,
292     1 << 16,
293     NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE | NACL_ABI_PROT_EXEC,
294     NACL_ABI_MAP_PRIVATE,
295     _O_RDWR | _O_BINARY,
296     NACL_ABI_O_RDWR,
297     /* expected_open_error= */ ERROR_ACCESS_DENIED,
298     /* expected_mmap_errno= */ 0,
299   }, {
300     "Mapping ro rw file, PROT_ALL, PRIVATE",
301     &g_readonly_rw_file,
302     1 << 16,
303     NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE | NACL_ABI_PROT_EXEC,
304     NACL_ABI_MAP_PRIVATE,
305     _O_RDWR | _O_BINARY,
306     NACL_ABI_O_RDWR,
307     /* expected_open_error= */ ERROR_ACCESS_DENIED,
308     /* expected_mmap_errno= */ 0,
309   }, {
310     "Mapping ro rw file, PROT_(READ|WRITE), PRIVATE",
311     &g_readonly_rw_file,
312     1 << 16,
313     NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
314     NACL_ABI_MAP_PRIVATE,
315     _O_RDWR | _O_BINARY,
316     NACL_ABI_O_RDWR,
317     /* expected_open_error= */ ERROR_ACCESS_DENIED,
318     /* expected_mmap_errno= */ 0,
319   }, {
320     "Mapping ro rw file, PROT_READ, PRIVATE",
321     &g_readonly_rw_file,
322     1 << 16,
323     NACL_ABI_PROT_READ,
324     NACL_ABI_MAP_PRIVATE,
325     _O_RDONLY | _O_BINARY,
326     NACL_ABI_O_RDONLY,
327     /* expected_open_error= */ ERROR_ACCESS_DENIED,
328     /* expected_mmap_errno= */ 0,
329   }, {
330     "Mapping ro ro file, PROT_READ, PRIVATE",
331     &g_readonly_r_file,
332     1 << 16,
333     NACL_ABI_PROT_READ,
334     NACL_ABI_MAP_PRIVATE,
335     _O_RDONLY | _O_BINARY,
336     NACL_ABI_O_RDONLY,
337     /* expected_open_error= */ ERROR_SUCCESS,
338     /* expected_mmap_errno= */ 0,
339   }, {
340     "Mapping ro ro file, PROT_(READ|WRITE), PRIVATE",
341     &g_readonly_r_file,
342     1 << 16,
343     NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
344     NACL_ABI_MAP_PRIVATE,
345     _O_RDONLY | _O_BINARY,
346     NACL_ABI_O_RDONLY,
347     /* expected_open_error= */ ERROR_SUCCESS,
348     /* expected_mmap_errno= */ 0,
349   }, {
350     "Mapping ro rwx file, PROT_ALL, SHARED",
351     &g_readonly_rwx_file,
352     1 << 16,
353     NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE | NACL_ABI_PROT_EXEC,
354     NACL_ABI_MAP_SHARED,
355     _O_RDWR | _O_BINARY,
356     NACL_ABI_O_RDWR,
357     /* expected_open_error= */ ERROR_ACCESS_DENIED,
358     /* expected_mmap_errno= */ 0,
359   }, {
360     "Mapping ro rw file, PROT_(READ|WRITE), SHARED",
361     &g_readonly_rw_file,
362     1 << 16,
363     NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
364     NACL_ABI_MAP_SHARED,
365     _O_RDWR | _O_BINARY,
366     NACL_ABI_O_RDWR,
367     /* expected_open_error= */ ERROR_ACCESS_DENIED,
368     /* expected_mmap_errno= */ 0,
369   }, {
370     "Mapping ro ro file, PROT_READ, SHARED",
371     &g_readonly_rw_file,
372     1 << 16,
373     NACL_ABI_PROT_READ,
374     NACL_ABI_MAP_SHARED,
375     _O_RDONLY | _O_BINARY,
376     NACL_ABI_O_RDONLY,
377     /* expected_open_error= */ ERROR_ACCESS_DENIED,
378     /* expected_mmap_errno= */ 0,
379   }, {
380     "Mapping ro ro file, PROT_READ, SHARED",
381     &g_readonly_r_file,
382     1 << 16,
383     NACL_ABI_PROT_READ,
384     NACL_ABI_MAP_SHARED,
385     _O_RDONLY | _O_BINARY,
386     NACL_ABI_O_RDONLY,
387     /* expected_open_error= */ ERROR_SUCCESS,
388     /* expected_mmap_errno= */ 0,
389   }, {
390     "Mapping ro ro file, PROT_(READ|WRITE), SHARED",
391     &g_readonly_r_file,
392     1 << 16,
393     NACL_ABI_PROT_READ | NACL_ABI_PROT_WRITE,
394     NACL_ABI_MAP_SHARED,
395     _O_RDONLY | _O_BINARY,
396     NACL_ABI_O_RDONLY,
397     /* expected_open_error= */ 0,
398     /* expected_mmap_errno= */ NACL_ABI_EACCES,
399   }, {
400     "LIE: Mapping normal r pretend rw file, PROT_READ, PRIVATE",
401     &g_normal_r_file,
402     1 << 16,
403     NACL_ABI_PROT_READ,
404     NACL_ABI_MAP_PRIVATE,
405     _O_RDWR | _O_BINARY,
406     NACL_ABI_O_RDWR,
407     /* expected_open_error= */ ERROR_SUCCESS,
408     /* expected_mmap_errno= */ NACL_ABI_EACCES,
409   },
410 };
411 
412 /*
413  * It is the responsibility of the invoking environment to delete the
414  * file passed as command-line argument.  See the build.scons file.
415  */
main(int ac,char ** av)416 int main(int ac, char **av) {
417   char const *test_dir_name = "/tmp/nacl_host_desc_mmap_win_test";
418   struct NaClHostDesc hd;
419   int test_passed;
420   size_t error_count;
421   size_t ix;
422   int opt;
423   int num_runs = 1;
424   int test_run;
425   HANDLE h;
426   int d;
427 
428   while (EOF != (opt = getopt(ac, av, "c:t:"))) {
429     switch (opt) {
430       case 'c':
431         num_runs = atoi(optarg);
432         break;
433       case 't':
434         test_dir_name = optarg;
435         break;
436       default:
437         fprintf(stderr,
438                 "Usage: nacl_host_desc_mmap_win_test [-c run_count]\n"
439                 "                                    [-t test_temp_dir]\n");
440         exit(1);
441     }
442   }
443 
444   NaClPlatformInit();
445 
446   error_count = 0;
447   for (test_run = 0; test_run < num_runs; ++test_run) {
448     printf("Test run %d\n\n", test_run);
449     for (ix = 0; ix < NACL_ARRAY_SIZE(tests); ++ix) {
450       char test_file_name[PATH_MAX];
451       _snprintf_s(test_file_name, sizeof test_file_name, _TRUNCATE,
452                   "%s/f%d.%"NACL_PRIuS, test_dir_name, test_run, ix);
453       printf("%s\n", tests[ix].test_info);
454       printf("-- %s\n", tests[ix].file_type->file_type_description);
455 
456       h = CreateTestFile(test_file_name, tests[ix].file_type);
457       if (ERROR_SUCCESS == tests[ix].expected_open_error) {
458         if (INVALID_HANDLE_VALUE == h) {
459           DWORD err = GetLastError();
460           NaClLog(LOG_ERROR,
461                   "CreateTestFile for %s failed, error %d\n",
462                   test_file_name, err);
463           printf("FAILED\n");
464           ++error_count;
465           continue;
466         }
467 
468         d = _open_osfhandle((intptr_t) h, tests[ix].oflags);
469         NaClHostDescPosixTake(&hd, d, tests[ix].posix_flags);
470         test_passed = TryToMap(&hd, tests[ix].map_bytes, tests[ix].prot,
471                                tests[ix].map_flags,
472                                tests[ix].expected_mmap_errno);
473         error_count += !test_passed;
474         printf("%s\n", test_passed ? "PASSED" : "FAILED");
475 
476         CHECK(0 == NaClHostDescClose(&hd));
477         AttemptToDeleteTestFile(test_file_name);
478       } else {
479         if (INVALID_HANDLE_VALUE == h) {
480           DWORD err = GetLastError();
481           if (err != tests[ix].expected_open_error) {
482             NaClLog(LOG_ERROR,
483                     "Expected CreateTestFile for %s to failed with"
484                     " error %d, but got error %d\n",
485                     test_file_name, err, tests[ix].expected_open_error);
486             printf("FAILED\n");
487             ++error_count;
488           } else {
489             printf("PASSED (open failed)\n");
490           }
491           continue;
492         } else {
493           NaClLog(LOG_ERROR,
494                   "Expected CreateTestFile for %s to fail with error %d,"
495                   " but succeeded instead!\n",
496                   test_file_name,
497                   tests[ix].expected_open_error);
498           (void) CloseHandle(h);
499           AttemptToDeleteTestFile(test_file_name);
500           printf("FAILED\n");
501           ++error_count;
502           continue;
503         }
504       }
505     }
506   }
507 
508   printf("Total of %d error%s.\n", error_count, (error_count == 1) ? "" : "s");
509 
510   NaClPlatformFini();
511 
512   /* we ignore the 2^32 or 2^64 total errors case */
513   return (error_count > 255) ? 255 : error_count;
514 }
515