master
c 608 lines 15.9 KB
Raw
1 /*++
2
3 Copyright (c) Microsoft. All rights reserved.
4
5 Module Name:
6
7 mprotect.c
8
9 Abstract:
10
11 This file contains test cases for mprotect().
12
13 --*/
14
15 #include "lxtcommon.h"
16 #include "unittests.h"
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <sys/mman.h>
21 #include <sched.h>
22 #include <signal.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <sys/ioctl.h>
26 #include <sys/syscall.h>
27 #include <fcntl.h>
28 #include <errno.h>
29 #include <time.h>
30
31 #define LXT_NAME "mprotect"
32 #define MAPPING_PAGE_SIZE 4096
33 #define MAX_BUF_SIZE 256
34 #define PROCFS_MNT "/proc"
35
36 int MprotectMainVariation(PLXT_ARGS Args);
37
38 int MunmapMainVariation(PLXT_ARGS Args);
39
40 int MsyncMainVariation(PLXT_ARGS Args);
41
42 int MadviseMainVariation(PLXT_ARGS Args);
43
44 int MremapMainVariation(PLXT_ARGS Args);
45
46 int MprotectStackVariation(PLXT_ARGS Args);
47
48 static const LXT_VARIATION g_LxtVariations[] = {
49 {"mprotect main variation", MprotectMainVariation},
50 {"munmap main variation", MunmapMainVariation},
51 {"msync main variation", MsyncMainVariation},
52 {"madvise main variation", MadviseMainVariation},
53 {"mremap main variation", MremapMainVariation},
54 {"mprotect stack variation", MprotectStackVariation},
55 };
56
57 int MprotectMainVariation(PLXT_ARGS Args)
58 {
59 int Result;
60 int ROFileDescriptor;
61 int RWFileDescriptor;
62 char FileBuffer[3 * MAPPING_PAGE_SIZE];
63 char* ROMapping;
64 char* RWMapping;
65 int MapSize;
66 char* RemappedMemory;
67
68 MapSize = sizeof(FileBuffer);
69
70 ROFileDescriptor = open("/data/mprotect_test.bin", O_RDONLY | O_CREAT | O_TRUNC, S_IRWXU);
71
72 if (ROFileDescriptor == -1)
73 {
74 Result = errno;
75 LxtLogError("Could not create test file! %d", Result);
76 goto ErrorExit;
77 }
78
79 RWFileDescriptor = open("/data/mprotect_test.bin", O_RDWR);
80
81 if (RWFileDescriptor == -1)
82 {
83 Result = errno;
84 LxtLogError("Could not create test file! %d", Result);
85 goto ErrorExit;
86 }
87
88 write(RWFileDescriptor, FileBuffer, MapSize);
89
90 ROMapping = mmap(NULL, MapSize, PROT_READ, MAP_SHARED, ROFileDescriptor, 0);
91
92 if (ROMapping == MAP_FAILED)
93 {
94 Result = errno;
95 LxtLogError("ROMapping allocation failed! %d", Result);
96 goto ErrorExit;
97 }
98
99 LxtLogInfo("ROMapping: %p", ROMapping);
100
101 RWMapping = mmap(NULL, MapSize, PROT_READ, MAP_SHARED, RWFileDescriptor, 0);
102
103 if (RWMapping == MAP_FAILED)
104 {
105 Result = errno;
106 LxtLogError("ROMapping allocation failed! %d", Result);
107 goto ErrorExit;
108 }
109
110 LxtLogInfo("RWMapping: %p", RWMapping);
111
112 //
113 // Checking behavior of mprotect with zero size mappings.
114 //
115
116 LxtLogInfo("Checking mprotect behavior with zero size mappings") LxtCheckErrno(mprotect(NULL, 0, PROT_WRITE));
117 LxtCheckErrno(mprotect(NULL, 0, 0xDEADBEEF));
118 LxtCheckErrno(mprotect(RWMapping, 0, 0xDEADBEEF));
119 LxtCheckErrno(mprotect(ROMapping, 0, PROT_WRITE));
120 LxtCheckErrno(mprotect(ROMapping, 0, PROT_READ));
121 LxtCheckErrno(mprotect(RWMapping, 0, PROT_WRITE));
122 LxtCheckErrno(mprotect(RWMapping, 0, PROT_READ));
123
124 //
125 // Check behavior of mprotect with a bad address.
126 //
127
128 LxtLogInfo("Checking mprotect behavior with a bad address") LxtCheckErrnoFailure(mprotect(NULL, MAPPING_PAGE_SIZE, PROT_WRITE), ENOMEM);
129 LxtCheckErrnoFailure(mprotect(RWMapping + 300, MAPPING_PAGE_SIZE, PROT_WRITE), EINVAL);
130
131 //
132 // Check behavior with bad protection flags.
133 //
134
135 LxtLogInfo("Checking mprotect behavior with bad protection flags")
136 LxtCheckErrnoFailure(mprotect(RWMapping, MAPPING_PAGE_SIZE, 0xDEADBEEF), EINVAL);
137
138 //
139 // Checking mprotect on non-zero size mappings.
140 //
141
142 Result = mprotect(RWMapping, MAPPING_PAGE_SIZE, PROT_WRITE);
143
144 if (Result == -1)
145 {
146 Result = errno;
147 LxtLogError("Protection change failed unexpectedly! %d", Result);
148 goto ErrorExit;
149 }
150
151 LxtLogInfo("RWMapping protection succeeded");
152
153 Result = mprotect(ROMapping, MAPPING_PAGE_SIZE, PROT_WRITE);
154
155 if (Result != -1)
156 {
157 LxtLogError("Protection change on RO file succeeded unexpectedly!");
158 goto ErrorExit;
159 }
160
161 Result = errno;
162 if (Result != EACCES)
163 {
164 LxtLogError("RO protection change failed but not with EACCES! %d", Result);
165 goto ErrorExit;
166 }
167
168 LxtLogInfo("ROMapping protection failed as expected");
169
170 RemappedMemory = mremap(ROMapping, MAPPING_PAGE_SIZE, 2 * MAPPING_PAGE_SIZE, MREMAP_MAYMOVE);
171
172 if (RemappedMemory == MAP_FAILED)
173 {
174 Result = errno;
175 LxtLogError("Remap on RO file failed unexpectedly! %d!", Result);
176 goto ErrorExit;
177 }
178
179 LxtLogInfo("Remapping succeeded");
180
181 RemappedMemory = mremap(RWMapping, MAPPING_PAGE_SIZE, 2 * MAPPING_PAGE_SIZE, MREMAP_MAYMOVE);
182
183 if (RemappedMemory == MAP_FAILED)
184 {
185 Result = errno;
186 LxtLogError("Remap on RO file failed unexpectedly! %d!", Result);
187 goto ErrorExit;
188 }
189
190 LxtLogInfo("Remapping succeeded");
191 LxtLogPassed("Success!");
192 Result = 0;
193
194 ErrorExit:
195
196 return Result;
197 }
198
199 int MunmapMainVariation(PLXT_ARGS Args)
200 {
201 char FileBuffer[3 * MAPPING_PAGE_SIZE];
202 int MapSize;
203 int Result;
204 int RWFileDescriptor;
205 char* RWMapping;
206
207 //
208 // Create a file and write garbage data to it.
209 //
210
211 MapSize = sizeof(FileBuffer);
212 RWFileDescriptor = open("/data/mprotect_test.bin", O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);
213
214 if (RWFileDescriptor == -1)
215 {
216 Result = errno;
217 LxtLogError("Could not create test file! %d", Result);
218 goto ErrorExit;
219 }
220
221 write(RWFileDescriptor, FileBuffer, MapSize);
222
223 //
224 // Map a memory segment that will be backed by the file.
225 //
226
227 RWMapping = mmap(NULL, MapSize, PROT_READ, MAP_SHARED, RWFileDescriptor, 0);
228
229 if (RWMapping == MAP_FAILED)
230 {
231 Result = errno;
232 LxtLogError("ROMapping allocation failed! %d", Result);
233 goto ErrorExit;
234 }
235
236 LxtLogInfo("RWMapping: %p", RWMapping);
237
238 //
239 // Check different variations of bad arguments with munmap.
240 //
241
242 LxtLogInfo("Checking munmap with bad arguments");
243 LxtCheckErrnoFailure(munmap(NULL, 0), EINVAL);
244 LxtCheckErrnoFailure(munmap(RWMapping, 0), EINVAL);
245 LxtCheckErrnoFailure(munmap(RWMapping + 300, MapSize), EINVAL);
246 LxtCheckErrno(munmap(NULL, MapSize));
247
248 //
249 // Unmap the memory mapping.
250 //
251
252 LxtLogInfo("Unmapping the mapping");
253 LxtCheckErrno(munmap(RWMapping, MapSize));
254
255 //
256 // All tests passed at this point.
257 //
258
259 LxtLogPassed("Success!") Result = 0;
260
261 ErrorExit:
262 if (RWFileDescriptor >= 0)
263 {
264 if (LxtClose(RWFileDescriptor) < 0)
265 {
266 LxtLogInfo("Failed to close test file at the end of the test");
267 }
268 }
269
270 return Result;
271 }
272
273 int MsyncMainVariation(PLXT_ARGS Args)
274 {
275 char FileBuffer[3 * MAPPING_PAGE_SIZE];
276 int MapSize;
277 int Result;
278 int RWFileDescriptor;
279 char* RWMapping;
280
281 //
282 // Create a file and write garbage data to it.
283 //
284
285 MapSize = sizeof(FileBuffer);
286 RWFileDescriptor = open("/data/mprotect_test.bin", O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);
287
288 if (RWFileDescriptor == -1)
289 {
290 Result = errno;
291 LxtLogError("Could not create test file! %d", Result);
292 goto ErrorExit;
293 }
294
295 write(RWFileDescriptor, FileBuffer, MapSize);
296
297 //
298 // Map a memory segment that will be backed by the file.
299 //
300
301 RWMapping = mmap(NULL, MapSize, PROT_READ | PROT_WRITE, MAP_SHARED, RWFileDescriptor, 0);
302
303 if (RWMapping == MAP_FAILED)
304 {
305 Result = errno;
306 LxtLogError("ROMapping allocation failed! %d", Result);
307 goto ErrorExit;
308 }
309
310 LxtLogInfo("RWMapping: %p", RWMapping);
311
312 //
313 // Read the first byte from the file, increment it and write it back.
314 //
315
316 *RWMapping = *RWMapping + 1;
317
318 //
319 // Checking behavior of msync with zero length.
320 //
321
322 LxtLogInfo("Checking msync behavior with zero length") LxtCheckErrno(msync(NULL, 0, MS_SYNC));
323 LxtCheckErrno(msync(RWMapping, 0, MS_SYNC));
324 LxtCheckErrnoFailure(msync(NULL, 0, 0xDEADBEEF), EINVAL);
325 LxtCheckErrnoFailure(msync(RWMapping, 0, 0xDEADBEEF), EINVAL);
326
327 //
328 // Check behavior of mprotect with a bad address.
329 //
330
331 LxtLogInfo("Checking msync behavior with a bad address") LxtCheckErrnoFailure(msync(NULL, MAPPING_PAGE_SIZE, MS_SYNC), ENOMEM);
332 LxtCheckErrnoFailure(msync(RWMapping + 300, MAPPING_PAGE_SIZE, MS_SYNC), EINVAL);
333
334 //
335 // Check behavior of msync with bad flags.
336 //
337
338 LxtLogInfo("Checking msync behavior with bad protection flags")
339 LxtCheckErrnoFailure(msync(RWMapping, MAPPING_PAGE_SIZE, 0xDEADBEEF), EINVAL);
340
341 //
342 // Sync the changes.
343 //
344
345 LxtLogInfo("Sync the changes to the file");
346 LxtCheckErrno(msync(RWMapping, MAPPING_PAGE_SIZE, MS_SYNC));
347
348 //
349 // All tests passed at this point.
350 //
351
352 LxtLogPassed("Success!") Result = 0;
353
354 ErrorExit:
355 if (RWFileDescriptor >= 0)
356 {
357 if (LxtClose(RWFileDescriptor) < 0)
358 {
359 LxtLogInfo("Failed to close test file at the end of the test");
360 }
361 }
362
363 return Result;
364 }
365
366 int MadviseMainVariation(PLXT_ARGS Args)
367 {
368 char FileBuffer[3 * MAPPING_PAGE_SIZE];
369 int MapSize;
370 int Result;
371 int RWFileDescriptor;
372 char* RWMapping;
373 char DummyByte;
374
375 //
376 // Create a file and write garbage data to it.
377 //
378
379 MapSize = sizeof(FileBuffer);
380 RWFileDescriptor = open("/data/mprotect_test.bin", O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);
381
382 if (RWFileDescriptor == -1)
383 {
384 Result = errno;
385 LxtLogError("Could not create test file! %d", Result);
386 goto ErrorExit;
387 }
388
389 write(RWFileDescriptor, FileBuffer, MapSize);
390
391 //
392 // Map a memory segment that will be backed by the file.
393 //
394
395 RWMapping = mmap(NULL, MapSize, PROT_READ | PROT_WRITE, MAP_SHARED, RWFileDescriptor, 0);
396
397 if (RWMapping == MAP_FAILED)
398 {
399 Result = errno;
400 LxtLogError("ROMapping allocation failed! %d", Result);
401 goto ErrorExit;
402 }
403
404 LxtLogInfo("RWMapping: %p", RWMapping);
405
406 //
407 // Checking behavior of mremap with zero length.
408 //
409
410 LxtLogInfo("Checking madvise behavior with zero length") LxtCheckErrno(madvise(NULL, 0, MADV_RANDOM));
411 LxtCheckErrno(madvise(RWMapping, 0, MADV_RANDOM));
412 LxtCheckErrnoFailure(madvise(NULL, 0, 0xDEADBEEF), EINVAL);
413 LxtCheckErrnoFailure(madvise(RWMapping, 0, 0xDEADBEEF), EINVAL);
414
415 //
416 // Check behavior of madvise with a bad address.
417 //
418
419 LxtLogInfo("Checking madvise behavior with a bad address") LxtCheckErrnoFailure(madvise(NULL, MAPPING_PAGE_SIZE, MADV_RANDOM), ENOMEM);
420 LxtCheckErrnoFailure(madvise(RWMapping + 300, MAPPING_PAGE_SIZE, MADV_RANDOM), EINVAL);
421
422 //
423 // Check behavior of madvise with bad flags.
424 //
425
426 LxtLogInfo("Checking madvise behavior with bad protection flags")
427 LxtCheckErrnoFailure(madvise(RWMapping, MAPPING_PAGE_SIZE, 0xDEADBEEF), EINVAL);
428
429 //
430 // Advise the kernel on access partners.
431 //
432
433 LxtLogInfo("Advise the kernel on access patterns.");
434 LxtCheckErrno(madvise(RWMapping, MAPPING_PAGE_SIZE, MADV_RANDOM));
435
436 //
437 // All tests passed at this point.
438 //
439
440 LxtLogPassed("Success!") Result = 0;
441
442 ErrorExit:
443 if (RWFileDescriptor >= 0)
444 {
445 if (LxtClose(RWFileDescriptor) < 0)
446 {
447 LxtLogInfo("Failed to close test file at the end of the test");
448 }
449 }
450
451 return Result;
452 }
453
454 int MremapMainVariation(PLXT_ARGS Args)
455 {
456 char FileBuffer[3 * MAPPING_PAGE_SIZE];
457 int MapSize;
458 char* RemappedMemory;
459 int Result;
460 int RWFileDescriptor;
461 char* RWMapping;
462 char DummyByte;
463
464 //
465 // Create a file and write garbage data to it.
466 //
467
468 MapSize = sizeof(FileBuffer);
469 RWFileDescriptor = open("/data/mprotect_test.bin", O_CREAT | O_TRUNC | O_RDWR, S_IRWXU);
470
471 if (RWFileDescriptor == -1)
472 {
473 Result = errno;
474 LxtLogError("Could not create test file! %d", Result);
475 goto ErrorExit;
476 }
477
478 write(RWFileDescriptor, FileBuffer, MapSize);
479
480 //
481 // Map a memory segment that will be backed by the file.
482 //
483
484 RWMapping = mmap(NULL, MapSize, PROT_READ | PROT_WRITE, MAP_SHARED, RWFileDescriptor, 0);
485
486 if (RWMapping == MAP_FAILED)
487 {
488 Result = errno;
489 LxtLogError("ROMapping allocation failed! %d", Result);
490 goto ErrorExit;
491 }
492
493 LxtLogInfo("RWMapping: %p", RWMapping);
494
495 //
496 // Checking behavior of mremap with bad arguments.
497 //
498
499 LxtLogInfo("Checking mremap behavior with bad arguments");
500
501 #pragma GCC diagnostic push
502 #pragma GCC diagnostic ignored "-Wpointer-to-int-cast"
503
504 LxtCheckErrnoFailure((int)mremap(NULL, MAPPING_PAGE_SIZE, 2 * MAPPING_PAGE_SIZE, MREMAP_MAYMOVE), EFAULT);
505
506 LxtCheckErrnoFailure((int)mremap(RWMapping, MAPPING_PAGE_SIZE, 2 * MAPPING_PAGE_SIZE, 0xDEADBEEF), EINVAL);
507
508 LxtCheckErrnoFailure((int)mremap(RWMapping, MAPPING_PAGE_SIZE, 0, 0xDEADBEEF), EINVAL);
509
510 LxtCheckErrnoFailure((int)mremap(NULL, 0, 2 * MAPPING_PAGE_SIZE, MREMAP_MAYMOVE), EFAULT);
511
512 LxtCheckErrnoFailure((int)mremap(NULL, 0, 0, 0xDEADBEEF), EINVAL);
513
514 LxtCheckErrnoFailure((int)mremap(NULL, 0, 2 * MAPPING_PAGE_SIZE, 0xDEADBEEF), EINVAL);
515
516 LxtCheckErrnoFailure((int)mremap(RWMapping, 0, 0, MREMAP_MAYMOVE), EINVAL);
517
518 LxtCheckErrnoFailure((int)mremap(NULL, 0, 0, MREMAP_MAYMOVE), EINVAL);
519
520 LxtCheckErrnoFailure((int)mremap(NULL, MAPPING_PAGE_SIZE, 2 * MAPPING_PAGE_SIZE, 0xDEADBEEF), EINVAL);
521
522 LxtCheckErrnoFailure((int)mremap(RWMapping + 300, MAPPING_PAGE_SIZE, 2 * MAPPING_PAGE_SIZE, MREMAP_MAYMOVE), EINVAL);
523
524 LxtCheckErrnoFailure((int)mremap(RWMapping, MAPPING_PAGE_SIZE, 0, MREMAP_MAYMOVE), EINVAL);
525
526 #pragma GCC diagnostic pop
527
528 //
529 // Success cases.
530 //
531
532 //
533 // Shrink the mapped memory.
534 //
535
536 RemappedMemory = (char*)mremap(RWMapping, 3 * MAPPING_PAGE_SIZE, 2 * MAPPING_PAGE_SIZE, MREMAP_MAYMOVE);
537
538 if (RemappedMemory == MAP_FAILED)
539 {
540 LxtLogInfo("Mapping Failed");
541 Result = errno;
542 goto ErrorExit;
543 }
544
545 LxtLogInfo("RemappedMemory = %p", RemappedMemory);
546
547 //
548 // All tests passed at this point.
549 //
550
551 LxtLogPassed("Success!") Result = 0;
552
553 ErrorExit:
554 if (RWFileDescriptor >= 0)
555 {
556 if (LxtClose(RWFileDescriptor) < 0)
557 {
558 LxtLogInfo("Failed to close test file at the end of the test");
559 }
560 }
561
562 return Result;
563 }
564
565 int MprotectStackVariation(PLXT_ARGS Args)
566
567 {
568
569 void* Address;
570 int Result;
571 char StackBuffer[20000];
572
573 //
574 // Ensure PROT_GROWSDOWN doesn't work on normal allocations.
575 //
576
577 Address = mmap(NULL, 4096, PROT_NONE, MAP_ANONYMOUS, -1, 0);
578 LxtCheckErrnoFailure(mprotect(Address, 4096, PROT_READ | PROT_WRITE | PROT_GROWSDOWN), EINVAL);
579 munmap(Address, 4096);
580
581 //
582 // Make sure PROT_GROWSDOWN works on the stack. There's not an easy
583 // way to validate that it actually worked without parsing /proc/self/maps...
584 //
585
586 StackBuffer[0] = 'x';
587 Address = (void*)(((long)StackBuffer + sizeof(StackBuffer)) & ~4095);
588 LxtCheckErrno(mprotect(Address, 4096, PROT_READ | PROT_WRITE | PROT_GROWSDOWN));
589
590 Result = 0;
591
592 ErrorExit:
593 return Result;
594 }
595
596 int MprotectTestEntry(int Argc, char* Argv[])
597 {
598
599 LXT_ARGS Args;
600 int Result;
601
602 LxtCheckResult(LxtInitialize(Argc, Argv, &Args, LXT_NAME));
603 LxtCheckResult(LxtRunVariations(&Args, g_LxtVariations, LXT_COUNT_OF(g_LxtVariations)));
604
605 ErrorExit:
606 LxtUninitialize();
607 return LXT_RESULT_SUCCESS;
608 }