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