1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 #define _GNU_SOURCE
4 #include "../kselftest_harness.h"
5 #include <asm-generic/mman.h> /* Force the import of the tools version. */
6 #include <assert.h>
7 #include <errno.h>
8 #include <fcntl.h>
9 #include <linux/limits.h>
10 #include <linux/userfaultfd.h>
11 #include <setjmp.h>
12 #include <signal.h>
13 #include <stdbool.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <sys/ioctl.h>
18 #include <sys/mman.h>
19 #include <sys/syscall.h>
20 #include <sys/uio.h>
21 #include <unistd.h>
22 #include "vm_util.h"
23
24 #include "../pidfd/pidfd.h"
25
26 /*
27 * Ignore the checkpatch warning, as per the C99 standard, section 7.14.1.1:
28 *
29 * "If the signal occurs other than as the result of calling the abort or raise
30 * function, the behavior is undefined if the signal handler refers to any
31 * object with static storage duration other than by assigning a value to an
32 * object declared as volatile sig_atomic_t"
33 */
34 static volatile sig_atomic_t signal_jump_set;
35 static sigjmp_buf signal_jmp_buf;
36
37 /*
38 * Ignore the checkpatch warning, we must read from x but don't want to do
39 * anything with it in order to trigger a read page fault. We therefore must use
40 * volatile to stop the compiler from optimising this away.
41 */
42 #define FORCE_READ(x) (*(volatile typeof(x) *)x)
43
44 /*
45 * How is the test backing the mapping being tested?
46 */
47 enum backing_type {
48 ANON_BACKED,
49 SHMEM_BACKED,
50 LOCAL_FILE_BACKED,
51 };
52
FIXTURE(guard_regions)53 FIXTURE(guard_regions)
54 {
55 unsigned long page_size;
56 char path[PATH_MAX];
57 int fd;
58 };
59
FIXTURE_VARIANT(guard_regions)60 FIXTURE_VARIANT(guard_regions)
61 {
62 enum backing_type backing;
63 };
64
FIXTURE_VARIANT_ADD(guard_regions,anon)65 FIXTURE_VARIANT_ADD(guard_regions, anon)
66 {
67 .backing = ANON_BACKED,
68 };
69
FIXTURE_VARIANT_ADD(guard_regions,shmem)70 FIXTURE_VARIANT_ADD(guard_regions, shmem)
71 {
72 .backing = SHMEM_BACKED,
73 };
74
FIXTURE_VARIANT_ADD(guard_regions,file)75 FIXTURE_VARIANT_ADD(guard_regions, file)
76 {
77 .backing = LOCAL_FILE_BACKED,
78 };
79
is_anon_backed(const FIXTURE_VARIANT (guard_regions)* variant)80 static bool is_anon_backed(const FIXTURE_VARIANT(guard_regions) * variant)
81 {
82 switch (variant->backing) {
83 case ANON_BACKED:
84 case SHMEM_BACKED:
85 return true;
86 default:
87 return false;
88 }
89 }
90
mmap_(FIXTURE_DATA (guard_regions)* self,const FIXTURE_VARIANT (guard_regions)* variant,void * addr,size_t length,int prot,int extra_flags,off_t offset)91 static void *mmap_(FIXTURE_DATA(guard_regions) * self,
92 const FIXTURE_VARIANT(guard_regions) * variant,
93 void *addr, size_t length, int prot, int extra_flags,
94 off_t offset)
95 {
96 int fd;
97 int flags = extra_flags;
98
99 switch (variant->backing) {
100 case ANON_BACKED:
101 flags |= MAP_PRIVATE | MAP_ANON;
102 fd = -1;
103 break;
104 case SHMEM_BACKED:
105 case LOCAL_FILE_BACKED:
106 flags |= MAP_SHARED;
107 fd = self->fd;
108 break;
109 default:
110 ksft_exit_fail();
111 break;
112 }
113
114 return mmap(addr, length, prot, flags, fd, offset);
115 }
116
userfaultfd(int flags)117 static int userfaultfd(int flags)
118 {
119 return syscall(SYS_userfaultfd, flags);
120 }
121
handle_fatal(int c)122 static void handle_fatal(int c)
123 {
124 if (!signal_jump_set)
125 return;
126
127 siglongjmp(signal_jmp_buf, c);
128 }
129
sys_process_madvise(int pidfd,const struct iovec * iovec,size_t n,int advice,unsigned int flags)130 static ssize_t sys_process_madvise(int pidfd, const struct iovec *iovec,
131 size_t n, int advice, unsigned int flags)
132 {
133 return syscall(__NR_process_madvise, pidfd, iovec, n, advice, flags);
134 }
135
136 /*
137 * Enable our signal catcher and try to read/write the specified buffer. The
138 * return value indicates whether the read/write succeeds without a fatal
139 * signal.
140 */
try_access_buf(char * ptr,bool write)141 static bool try_access_buf(char *ptr, bool write)
142 {
143 bool failed;
144
145 /* Tell signal handler to jump back here on fatal signal. */
146 signal_jump_set = true;
147 /* If a fatal signal arose, we will jump back here and failed is set. */
148 failed = sigsetjmp(signal_jmp_buf, 0) != 0;
149
150 if (!failed) {
151 if (write)
152 *ptr = 'x';
153 else
154 FORCE_READ(ptr);
155 }
156
157 signal_jump_set = false;
158 return !failed;
159 }
160
161 /* Try and read from a buffer, return true if no fatal signal. */
try_read_buf(char * ptr)162 static bool try_read_buf(char *ptr)
163 {
164 return try_access_buf(ptr, false);
165 }
166
167 /* Try and write to a buffer, return true if no fatal signal. */
try_write_buf(char * ptr)168 static bool try_write_buf(char *ptr)
169 {
170 return try_access_buf(ptr, true);
171 }
172
173 /*
174 * Try and BOTH read from AND write to a buffer, return true if BOTH operations
175 * succeed.
176 */
try_read_write_buf(char * ptr)177 static bool try_read_write_buf(char *ptr)
178 {
179 return try_read_buf(ptr) && try_write_buf(ptr);
180 }
181
setup_sighandler(void)182 static void setup_sighandler(void)
183 {
184 struct sigaction act = {
185 .sa_handler = &handle_fatal,
186 .sa_flags = SA_NODEFER,
187 };
188
189 sigemptyset(&act.sa_mask);
190 if (sigaction(SIGSEGV, &act, NULL))
191 ksft_exit_fail_perror("sigaction");
192 }
193
teardown_sighandler(void)194 static void teardown_sighandler(void)
195 {
196 struct sigaction act = {
197 .sa_handler = SIG_DFL,
198 .sa_flags = SA_NODEFER,
199 };
200
201 sigemptyset(&act.sa_mask);
202 sigaction(SIGSEGV, &act, NULL);
203 }
204
open_file(const char * prefix,char * path)205 static int open_file(const char *prefix, char *path)
206 {
207 int fd;
208
209 snprintf(path, PATH_MAX, "%sguard_regions_test_file_XXXXXX", prefix);
210 fd = mkstemp(path);
211 if (fd < 0)
212 ksft_exit_fail_perror("mkstemp");
213
214 return fd;
215 }
216
217 /* Establish a varying pattern in a buffer. */
set_pattern(char * ptr,size_t num_pages,size_t page_size)218 static void set_pattern(char *ptr, size_t num_pages, size_t page_size)
219 {
220 size_t i;
221
222 for (i = 0; i < num_pages; i++) {
223 char *ptr2 = &ptr[i * page_size];
224
225 memset(ptr2, 'a' + (i % 26), page_size);
226 }
227 }
228
229 /*
230 * Check that a buffer contains the pattern set by set_pattern(), starting at a
231 * page offset of pgoff within the buffer.
232 */
check_pattern_offset(char * ptr,size_t num_pages,size_t page_size,size_t pgoff)233 static bool check_pattern_offset(char *ptr, size_t num_pages, size_t page_size,
234 size_t pgoff)
235 {
236 size_t i;
237
238 for (i = 0; i < num_pages * page_size; i++) {
239 size_t offset = pgoff * page_size + i;
240 char actual = ptr[offset];
241 char expected = 'a' + ((offset / page_size) % 26);
242
243 if (actual != expected)
244 return false;
245 }
246
247 return true;
248 }
249
250 /* Check that a buffer contains the pattern set by set_pattern(). */
check_pattern(char * ptr,size_t num_pages,size_t page_size)251 static bool check_pattern(char *ptr, size_t num_pages, size_t page_size)
252 {
253 return check_pattern_offset(ptr, num_pages, page_size, 0);
254 }
255
256 /* Determine if a buffer contains only repetitions of a specified char. */
is_buf_eq(char * buf,size_t size,char chr)257 static bool is_buf_eq(char *buf, size_t size, char chr)
258 {
259 size_t i;
260
261 for (i = 0; i < size; i++) {
262 if (buf[i] != chr)
263 return false;
264 }
265
266 return true;
267 }
268
FIXTURE_SETUP(guard_regions)269 FIXTURE_SETUP(guard_regions)
270 {
271 self->page_size = (unsigned long)sysconf(_SC_PAGESIZE);
272 setup_sighandler();
273
274 switch (variant->backing) {
275 case ANON_BACKED:
276 return;
277 case LOCAL_FILE_BACKED:
278 self->fd = open_file("", self->path);
279 break;
280 case SHMEM_BACKED:
281 self->fd = memfd_create(self->path, 0);
282 break;
283 }
284
285 /* We truncate file to at least 100 pages, tests can modify as needed. */
286 ASSERT_EQ(ftruncate(self->fd, 100 * self->page_size), 0);
287 };
288
FIXTURE_TEARDOWN_PARENT(guard_regions)289 FIXTURE_TEARDOWN_PARENT(guard_regions)
290 {
291 teardown_sighandler();
292
293 if (variant->backing == ANON_BACKED)
294 return;
295
296 if (self->fd >= 0)
297 close(self->fd);
298
299 if (self->path[0] != '\0')
300 unlink(self->path);
301 }
302
TEST_F(guard_regions,basic)303 TEST_F(guard_regions, basic)
304 {
305 const unsigned long NUM_PAGES = 10;
306 const unsigned long page_size = self->page_size;
307 char *ptr;
308 int i;
309
310 ptr = mmap_(self, variant, NULL, NUM_PAGES * page_size,
311 PROT_READ | PROT_WRITE, 0, 0);
312 ASSERT_NE(ptr, MAP_FAILED);
313
314 /* Trivially assert we can touch the first page. */
315 ASSERT_TRUE(try_read_write_buf(ptr));
316
317 ASSERT_EQ(madvise(ptr, page_size, MADV_GUARD_INSTALL), 0);
318
319 /* Establish that 1st page SIGSEGV's. */
320 ASSERT_FALSE(try_read_write_buf(ptr));
321
322 /* Ensure we can touch everything else.*/
323 for (i = 1; i < NUM_PAGES; i++) {
324 char *curr = &ptr[i * page_size];
325
326 ASSERT_TRUE(try_read_write_buf(curr));
327 }
328
329 /* Establish a guard page at the end of the mapping. */
330 ASSERT_EQ(madvise(&ptr[(NUM_PAGES - 1) * page_size], page_size,
331 MADV_GUARD_INSTALL), 0);
332
333 /* Check that both guard pages result in SIGSEGV. */
334 ASSERT_FALSE(try_read_write_buf(ptr));
335 ASSERT_FALSE(try_read_write_buf(&ptr[(NUM_PAGES - 1) * page_size]));
336
337 /* Remove the first guard page. */
338 ASSERT_FALSE(madvise(ptr, page_size, MADV_GUARD_REMOVE));
339
340 /* Make sure we can touch it. */
341 ASSERT_TRUE(try_read_write_buf(ptr));
342
343 /* Remove the last guard page. */
344 ASSERT_FALSE(madvise(&ptr[(NUM_PAGES - 1) * page_size], page_size,
345 MADV_GUARD_REMOVE));
346
347 /* Make sure we can touch it. */
348 ASSERT_TRUE(try_read_write_buf(&ptr[(NUM_PAGES - 1) * page_size]));
349
350 /*
351 * Test setting a _range_ of pages, namely the first 3. The first of
352 * these be faulted in, so this also tests that we can install guard
353 * pages over backed pages.
354 */
355 ASSERT_EQ(madvise(ptr, 3 * page_size, MADV_GUARD_INSTALL), 0);
356
357 /* Make sure they are all guard pages. */
358 for (i = 0; i < 3; i++) {
359 char *curr = &ptr[i * page_size];
360
361 ASSERT_FALSE(try_read_write_buf(curr));
362 }
363
364 /* Make sure the rest are not. */
365 for (i = 3; i < NUM_PAGES; i++) {
366 char *curr = &ptr[i * page_size];
367
368 ASSERT_TRUE(try_read_write_buf(curr));
369 }
370
371 /* Remove guard pages. */
372 ASSERT_EQ(madvise(ptr, NUM_PAGES * page_size, MADV_GUARD_REMOVE), 0);
373
374 /* Now make sure we can touch everything. */
375 for (i = 0; i < NUM_PAGES; i++) {
376 char *curr = &ptr[i * page_size];
377
378 ASSERT_TRUE(try_read_write_buf(curr));
379 }
380
381 /*
382 * Now remove all guard pages, make sure we don't remove existing
383 * entries.
384 */
385 ASSERT_EQ(madvise(ptr, NUM_PAGES * page_size, MADV_GUARD_REMOVE), 0);
386
387 for (i = 0; i < NUM_PAGES * page_size; i += page_size) {
388 char chr = ptr[i];
389
390 ASSERT_EQ(chr, 'x');
391 }
392
393 ASSERT_EQ(munmap(ptr, NUM_PAGES * page_size), 0);
394 }
395
396 /* Assert that operations applied across multiple VMAs work as expected. */
TEST_F(guard_regions,multi_vma)397 TEST_F(guard_regions, multi_vma)
398 {
399 const unsigned long page_size = self->page_size;
400 char *ptr_region, *ptr, *ptr1, *ptr2, *ptr3;
401 int i;
402
403 /* Reserve a 100 page region over which we can install VMAs. */
404 ptr_region = mmap_(self, variant, NULL, 100 * page_size,
405 PROT_NONE, 0, 0);
406 ASSERT_NE(ptr_region, MAP_FAILED);
407
408 /* Place a VMA of 10 pages size at the start of the region. */
409 ptr1 = mmap_(self, variant, ptr_region, 10 * page_size,
410 PROT_READ | PROT_WRITE, MAP_FIXED, 0);
411 ASSERT_NE(ptr1, MAP_FAILED);
412
413 /* Place a VMA of 5 pages size 50 pages into the region. */
414 ptr2 = mmap_(self, variant, &ptr_region[50 * page_size], 5 * page_size,
415 PROT_READ | PROT_WRITE, MAP_FIXED, 0);
416 ASSERT_NE(ptr2, MAP_FAILED);
417
418 /* Place a VMA of 20 pages size at the end of the region. */
419 ptr3 = mmap_(self, variant, &ptr_region[80 * page_size], 20 * page_size,
420 PROT_READ | PROT_WRITE, MAP_FIXED, 0);
421 ASSERT_NE(ptr3, MAP_FAILED);
422
423 /* Unmap gaps. */
424 ASSERT_EQ(munmap(&ptr_region[10 * page_size], 40 * page_size), 0);
425 ASSERT_EQ(munmap(&ptr_region[55 * page_size], 25 * page_size), 0);
426
427 /*
428 * We end up with VMAs like this:
429 *
430 * 0 10 .. 50 55 .. 80 100
431 * [---] [---] [---]
432 */
433
434 /*
435 * Now mark the whole range as guard pages and make sure all VMAs are as
436 * such.
437 */
438
439 /*
440 * madvise() is certifiable and lets you perform operations over gaps,
441 * everything works, but it indicates an error and errno is set to
442 * -ENOMEM. Also if anything runs out of memory it is set to
443 * -ENOMEM. You are meant to guess which is which.
444 */
445 ASSERT_EQ(madvise(ptr_region, 100 * page_size, MADV_GUARD_INSTALL), -1);
446 ASSERT_EQ(errno, ENOMEM);
447
448 for (i = 0; i < 10; i++) {
449 char *curr = &ptr1[i * page_size];
450
451 ASSERT_FALSE(try_read_write_buf(curr));
452 }
453
454 for (i = 0; i < 5; i++) {
455 char *curr = &ptr2[i * page_size];
456
457 ASSERT_FALSE(try_read_write_buf(curr));
458 }
459
460 for (i = 0; i < 20; i++) {
461 char *curr = &ptr3[i * page_size];
462
463 ASSERT_FALSE(try_read_write_buf(curr));
464 }
465
466 /* Now remove guar pages over range and assert the opposite. */
467
468 ASSERT_EQ(madvise(ptr_region, 100 * page_size, MADV_GUARD_REMOVE), -1);
469 ASSERT_EQ(errno, ENOMEM);
470
471 for (i = 0; i < 10; i++) {
472 char *curr = &ptr1[i * page_size];
473
474 ASSERT_TRUE(try_read_write_buf(curr));
475 }
476
477 for (i = 0; i < 5; i++) {
478 char *curr = &ptr2[i * page_size];
479
480 ASSERT_TRUE(try_read_write_buf(curr));
481 }
482
483 for (i = 0; i < 20; i++) {
484 char *curr = &ptr3[i * page_size];
485
486 ASSERT_TRUE(try_read_write_buf(curr));
487 }
488
489 /* Now map incompatible VMAs in the gaps. */
490 ptr = mmap_(self, variant, &ptr_region[10 * page_size], 40 * page_size,
491 PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED, 0);
492 ASSERT_NE(ptr, MAP_FAILED);
493 ptr = mmap_(self, variant, &ptr_region[55 * page_size], 25 * page_size,
494 PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED, 0);
495 ASSERT_NE(ptr, MAP_FAILED);
496
497 /*
498 * We end up with VMAs like this:
499 *
500 * 0 10 .. 50 55 .. 80 100
501 * [---][xxxx][---][xxxx][---]
502 *
503 * Where 'x' signifies VMAs that cannot be merged with those adjacent to
504 * them.
505 */
506
507 /* Multiple VMAs adjacent to one another should result in no error. */
508 ASSERT_EQ(madvise(ptr_region, 100 * page_size, MADV_GUARD_INSTALL), 0);
509 for (i = 0; i < 100; i++) {
510 char *curr = &ptr_region[i * page_size];
511
512 ASSERT_FALSE(try_read_write_buf(curr));
513 }
514 ASSERT_EQ(madvise(ptr_region, 100 * page_size, MADV_GUARD_REMOVE), 0);
515 for (i = 0; i < 100; i++) {
516 char *curr = &ptr_region[i * page_size];
517
518 ASSERT_TRUE(try_read_write_buf(curr));
519 }
520
521 /* Cleanup. */
522 ASSERT_EQ(munmap(ptr_region, 100 * page_size), 0);
523 }
524
525 /*
526 * Assert that batched operations performed using process_madvise() work as
527 * expected.
528 */
TEST_F(guard_regions,process_madvise)529 TEST_F(guard_regions, process_madvise)
530 {
531 const unsigned long page_size = self->page_size;
532 char *ptr_region, *ptr1, *ptr2, *ptr3;
533 ssize_t count;
534 struct iovec vec[6];
535
536 /* Reserve region to map over. */
537 ptr_region = mmap_(self, variant, NULL, 100 * page_size,
538 PROT_NONE, 0, 0);
539 ASSERT_NE(ptr_region, MAP_FAILED);
540
541 /*
542 * 10 pages offset 1 page into reserve region. We MAP_POPULATE so we
543 * overwrite existing entries and test this code path against
544 * overwriting existing entries.
545 */
546 ptr1 = mmap_(self, variant, &ptr_region[page_size], 10 * page_size,
547 PROT_READ | PROT_WRITE, MAP_FIXED | MAP_POPULATE, 0);
548 ASSERT_NE(ptr1, MAP_FAILED);
549 /* We want guard markers at start/end of each VMA. */
550 vec[0].iov_base = ptr1;
551 vec[0].iov_len = page_size;
552 vec[1].iov_base = &ptr1[9 * page_size];
553 vec[1].iov_len = page_size;
554
555 /* 5 pages offset 50 pages into reserve region. */
556 ptr2 = mmap_(self, variant, &ptr_region[50 * page_size], 5 * page_size,
557 PROT_READ | PROT_WRITE, MAP_FIXED, 0);
558 ASSERT_NE(ptr2, MAP_FAILED);
559 vec[2].iov_base = ptr2;
560 vec[2].iov_len = page_size;
561 vec[3].iov_base = &ptr2[4 * page_size];
562 vec[3].iov_len = page_size;
563
564 /* 20 pages offset 79 pages into reserve region. */
565 ptr3 = mmap_(self, variant, &ptr_region[79 * page_size], 20 * page_size,
566 PROT_READ | PROT_WRITE, MAP_FIXED, 0);
567 ASSERT_NE(ptr3, MAP_FAILED);
568 vec[4].iov_base = ptr3;
569 vec[4].iov_len = page_size;
570 vec[5].iov_base = &ptr3[19 * page_size];
571 vec[5].iov_len = page_size;
572
573 /* Free surrounding VMAs. */
574 ASSERT_EQ(munmap(ptr_region, page_size), 0);
575 ASSERT_EQ(munmap(&ptr_region[11 * page_size], 39 * page_size), 0);
576 ASSERT_EQ(munmap(&ptr_region[55 * page_size], 24 * page_size), 0);
577 ASSERT_EQ(munmap(&ptr_region[99 * page_size], page_size), 0);
578
579 /* Now guard in one step. */
580 count = sys_process_madvise(PIDFD_SELF, vec, 6, MADV_GUARD_INSTALL, 0);
581
582 /* OK we don't have permission to do this, skip. */
583 if (count == -1 && errno == EPERM)
584 ksft_exit_skip("No process_madvise() permissions, try running as root.\n");
585
586 /* Returns the number of bytes advised. */
587 ASSERT_EQ(count, 6 * page_size);
588
589 /* Now make sure the guarding was applied. */
590
591 ASSERT_FALSE(try_read_write_buf(ptr1));
592 ASSERT_FALSE(try_read_write_buf(&ptr1[9 * page_size]));
593
594 ASSERT_FALSE(try_read_write_buf(ptr2));
595 ASSERT_FALSE(try_read_write_buf(&ptr2[4 * page_size]));
596
597 ASSERT_FALSE(try_read_write_buf(ptr3));
598 ASSERT_FALSE(try_read_write_buf(&ptr3[19 * page_size]));
599
600 /* Now do the same with unguard... */
601 count = sys_process_madvise(PIDFD_SELF, vec, 6, MADV_GUARD_REMOVE, 0);
602
603 /* ...and everything should now succeed. */
604
605 ASSERT_TRUE(try_read_write_buf(ptr1));
606 ASSERT_TRUE(try_read_write_buf(&ptr1[9 * page_size]));
607
608 ASSERT_TRUE(try_read_write_buf(ptr2));
609 ASSERT_TRUE(try_read_write_buf(&ptr2[4 * page_size]));
610
611 ASSERT_TRUE(try_read_write_buf(ptr3));
612 ASSERT_TRUE(try_read_write_buf(&ptr3[19 * page_size]));
613
614 /* Cleanup. */
615 ASSERT_EQ(munmap(ptr1, 10 * page_size), 0);
616 ASSERT_EQ(munmap(ptr2, 5 * page_size), 0);
617 ASSERT_EQ(munmap(ptr3, 20 * page_size), 0);
618 }
619
620 /* Assert that unmapping ranges does not leave guard markers behind. */
TEST_F(guard_regions,munmap)621 TEST_F(guard_regions, munmap)
622 {
623 const unsigned long page_size = self->page_size;
624 char *ptr, *ptr_new1, *ptr_new2;
625
626 ptr = mmap_(self, variant, NULL, 10 * page_size,
627 PROT_READ | PROT_WRITE, 0, 0);
628 ASSERT_NE(ptr, MAP_FAILED);
629
630 /* Guard first and last pages. */
631 ASSERT_EQ(madvise(ptr, page_size, MADV_GUARD_INSTALL), 0);
632 ASSERT_EQ(madvise(&ptr[9 * page_size], page_size, MADV_GUARD_INSTALL), 0);
633
634 /* Assert that they are guarded. */
635 ASSERT_FALSE(try_read_write_buf(ptr));
636 ASSERT_FALSE(try_read_write_buf(&ptr[9 * page_size]));
637
638 /* Unmap them. */
639 ASSERT_EQ(munmap(ptr, page_size), 0);
640 ASSERT_EQ(munmap(&ptr[9 * page_size], page_size), 0);
641
642 /* Map over them.*/
643 ptr_new1 = mmap_(self, variant, ptr, page_size, PROT_READ | PROT_WRITE,
644 MAP_FIXED, 0);
645 ASSERT_NE(ptr_new1, MAP_FAILED);
646 ptr_new2 = mmap_(self, variant, &ptr[9 * page_size], page_size,
647 PROT_READ | PROT_WRITE, MAP_FIXED, 0);
648 ASSERT_NE(ptr_new2, MAP_FAILED);
649
650 /* Assert that they are now not guarded. */
651 ASSERT_TRUE(try_read_write_buf(ptr_new1));
652 ASSERT_TRUE(try_read_write_buf(ptr_new2));
653
654 /* Cleanup. */
655 ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
656 }
657
658 /* Assert that mprotect() operations have no bearing on guard markers. */
TEST_F(guard_regions,mprotect)659 TEST_F(guard_regions, mprotect)
660 {
661 const unsigned long page_size = self->page_size;
662 char *ptr;
663 int i;
664
665 ptr = mmap_(self, variant, NULL, 10 * page_size,
666 PROT_READ | PROT_WRITE, 0, 0);
667 ASSERT_NE(ptr, MAP_FAILED);
668
669 /* Guard the middle of the range. */
670 ASSERT_EQ(madvise(&ptr[5 * page_size], 2 * page_size,
671 MADV_GUARD_INSTALL), 0);
672
673 /* Assert that it is indeed guarded. */
674 ASSERT_FALSE(try_read_write_buf(&ptr[5 * page_size]));
675 ASSERT_FALSE(try_read_write_buf(&ptr[6 * page_size]));
676
677 /* Now make these pages read-only. */
678 ASSERT_EQ(mprotect(&ptr[5 * page_size], 2 * page_size, PROT_READ), 0);
679
680 /* Make sure the range is still guarded. */
681 ASSERT_FALSE(try_read_buf(&ptr[5 * page_size]));
682 ASSERT_FALSE(try_read_buf(&ptr[6 * page_size]));
683
684 /* Make sure we can guard again without issue.*/
685 ASSERT_EQ(madvise(&ptr[5 * page_size], 2 * page_size,
686 MADV_GUARD_INSTALL), 0);
687
688 /* Make sure the range is, yet again, still guarded. */
689 ASSERT_FALSE(try_read_buf(&ptr[5 * page_size]));
690 ASSERT_FALSE(try_read_buf(&ptr[6 * page_size]));
691
692 /* Now unguard the whole range. */
693 ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_REMOVE), 0);
694
695 /* Make sure the whole range is readable. */
696 for (i = 0; i < 10; i++) {
697 char *curr = &ptr[i * page_size];
698
699 ASSERT_TRUE(try_read_buf(curr));
700 }
701
702 /* Cleanup. */
703 ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
704 }
705
706 /* Split and merge VMAs and make sure guard pages still behave. */
TEST_F(guard_regions,split_merge)707 TEST_F(guard_regions, split_merge)
708 {
709 const unsigned long page_size = self->page_size;
710 char *ptr, *ptr_new;
711 int i;
712
713 ptr = mmap_(self, variant, NULL, 10 * page_size,
714 PROT_READ | PROT_WRITE, 0, 0);
715 ASSERT_NE(ptr, MAP_FAILED);
716
717 /* Guard the whole range. */
718 ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_INSTALL), 0);
719
720 /* Make sure the whole range is guarded. */
721 for (i = 0; i < 10; i++) {
722 char *curr = &ptr[i * page_size];
723
724 ASSERT_FALSE(try_read_write_buf(curr));
725 }
726
727 /* Now unmap some pages in the range so we split. */
728 ASSERT_EQ(munmap(&ptr[2 * page_size], page_size), 0);
729 ASSERT_EQ(munmap(&ptr[5 * page_size], page_size), 0);
730 ASSERT_EQ(munmap(&ptr[8 * page_size], page_size), 0);
731
732 /* Make sure the remaining ranges are guarded post-split. */
733 for (i = 0; i < 2; i++) {
734 char *curr = &ptr[i * page_size];
735
736 ASSERT_FALSE(try_read_write_buf(curr));
737 }
738 for (i = 2; i < 5; i++) {
739 char *curr = &ptr[i * page_size];
740
741 ASSERT_FALSE(try_read_write_buf(curr));
742 }
743 for (i = 6; i < 8; i++) {
744 char *curr = &ptr[i * page_size];
745
746 ASSERT_FALSE(try_read_write_buf(curr));
747 }
748 for (i = 9; i < 10; i++) {
749 char *curr = &ptr[i * page_size];
750
751 ASSERT_FALSE(try_read_write_buf(curr));
752 }
753
754 /* Now map them again - the unmap will have cleared the guards. */
755 ptr_new = mmap_(self, variant, &ptr[2 * page_size], page_size,
756 PROT_READ | PROT_WRITE, MAP_FIXED, 0);
757 ASSERT_NE(ptr_new, MAP_FAILED);
758 ptr_new = mmap_(self, variant, &ptr[5 * page_size], page_size,
759 PROT_READ | PROT_WRITE, MAP_FIXED, 0);
760 ASSERT_NE(ptr_new, MAP_FAILED);
761 ptr_new = mmap_(self, variant, &ptr[8 * page_size], page_size,
762 PROT_READ | PROT_WRITE, MAP_FIXED, 0);
763 ASSERT_NE(ptr_new, MAP_FAILED);
764
765 /* Now make sure guard pages are established. */
766 for (i = 0; i < 10; i++) {
767 char *curr = &ptr[i * page_size];
768 bool result = try_read_write_buf(curr);
769 bool expect_true = i == 2 || i == 5 || i == 8;
770
771 ASSERT_TRUE(expect_true ? result : !result);
772 }
773
774 /* Now guard everything again. */
775 ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_INSTALL), 0);
776
777 /* Make sure the whole range is guarded. */
778 for (i = 0; i < 10; i++) {
779 char *curr = &ptr[i * page_size];
780
781 ASSERT_FALSE(try_read_write_buf(curr));
782 }
783
784 /* Now split the range into three. */
785 ASSERT_EQ(mprotect(ptr, 3 * page_size, PROT_READ), 0);
786 ASSERT_EQ(mprotect(&ptr[7 * page_size], 3 * page_size, PROT_READ), 0);
787
788 /* Make sure the whole range is guarded for read. */
789 for (i = 0; i < 10; i++) {
790 char *curr = &ptr[i * page_size];
791
792 ASSERT_FALSE(try_read_buf(curr));
793 }
794
795 /* Now reset protection bits so we merge the whole thing. */
796 ASSERT_EQ(mprotect(ptr, 3 * page_size, PROT_READ | PROT_WRITE), 0);
797 ASSERT_EQ(mprotect(&ptr[7 * page_size], 3 * page_size,
798 PROT_READ | PROT_WRITE), 0);
799
800 /* Make sure the whole range is still guarded. */
801 for (i = 0; i < 10; i++) {
802 char *curr = &ptr[i * page_size];
803
804 ASSERT_FALSE(try_read_write_buf(curr));
805 }
806
807 /* Split range into 3 again... */
808 ASSERT_EQ(mprotect(ptr, 3 * page_size, PROT_READ), 0);
809 ASSERT_EQ(mprotect(&ptr[7 * page_size], 3 * page_size, PROT_READ), 0);
810
811 /* ...and unguard the whole range. */
812 ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_REMOVE), 0);
813
814 /* Make sure the whole range is remedied for read. */
815 for (i = 0; i < 10; i++) {
816 char *curr = &ptr[i * page_size];
817
818 ASSERT_TRUE(try_read_buf(curr));
819 }
820
821 /* Merge them again. */
822 ASSERT_EQ(mprotect(ptr, 3 * page_size, PROT_READ | PROT_WRITE), 0);
823 ASSERT_EQ(mprotect(&ptr[7 * page_size], 3 * page_size,
824 PROT_READ | PROT_WRITE), 0);
825
826 /* Now ensure the merged range is remedied for read/write. */
827 for (i = 0; i < 10; i++) {
828 char *curr = &ptr[i * page_size];
829
830 ASSERT_TRUE(try_read_write_buf(curr));
831 }
832
833 /* Cleanup. */
834 ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
835 }
836
837 /* Assert that MADV_DONTNEED does not remove guard markers. */
TEST_F(guard_regions,dontneed)838 TEST_F(guard_regions, dontneed)
839 {
840 const unsigned long page_size = self->page_size;
841 char *ptr;
842 int i;
843
844 ptr = mmap_(self, variant, NULL, 10 * page_size,
845 PROT_READ | PROT_WRITE, 0, 0);
846 ASSERT_NE(ptr, MAP_FAILED);
847
848 /* Back the whole range. */
849 for (i = 0; i < 10; i++) {
850 char *curr = &ptr[i * page_size];
851
852 *curr = 'y';
853 }
854
855 /* Guard every other page. */
856 for (i = 0; i < 10; i += 2) {
857 char *curr = &ptr[i * page_size];
858 int res = madvise(curr, page_size, MADV_GUARD_INSTALL);
859
860 ASSERT_EQ(res, 0);
861 }
862
863 /* Indicate that we don't need any of the range. */
864 ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_DONTNEED), 0);
865
866 /* Check to ensure guard markers are still in place. */
867 for (i = 0; i < 10; i++) {
868 char *curr = &ptr[i * page_size];
869 bool result = try_read_buf(curr);
870
871 if (i % 2 == 0) {
872 ASSERT_FALSE(result);
873 } else {
874 ASSERT_TRUE(result);
875 switch (variant->backing) {
876 case ANON_BACKED:
877 /* If anon, then we get a zero page. */
878 ASSERT_EQ(*curr, '\0');
879 break;
880 default:
881 /* Otherwise, we get the file data. */
882 ASSERT_EQ(*curr, 'y');
883 break;
884 }
885 }
886
887 /* Now write... */
888 result = try_write_buf(&ptr[i * page_size]);
889
890 /* ...and make sure same result. */
891 ASSERT_TRUE(i % 2 != 0 ? result : !result);
892 }
893
894 /* Cleanup. */
895 ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
896 }
897
898 /* Assert that mlock()'ed pages work correctly with guard markers. */
TEST_F(guard_regions,mlock)899 TEST_F(guard_regions, mlock)
900 {
901 const unsigned long page_size = self->page_size;
902 char *ptr;
903 int i;
904
905 ptr = mmap_(self, variant, NULL, 10 * page_size,
906 PROT_READ | PROT_WRITE, 0, 0);
907 ASSERT_NE(ptr, MAP_FAILED);
908
909 /* Populate. */
910 for (i = 0; i < 10; i++) {
911 char *curr = &ptr[i * page_size];
912
913 *curr = 'y';
914 }
915
916 /* Lock. */
917 ASSERT_EQ(mlock(ptr, 10 * page_size), 0);
918
919 /* Now try to guard, should fail with EINVAL. */
920 ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_INSTALL), -1);
921 ASSERT_EQ(errno, EINVAL);
922
923 /* OK unlock. */
924 ASSERT_EQ(munlock(ptr, 10 * page_size), 0);
925
926 /* Guard first half of range, should now succeed. */
927 ASSERT_EQ(madvise(ptr, 5 * page_size, MADV_GUARD_INSTALL), 0);
928
929 /* Make sure guard works. */
930 for (i = 0; i < 10; i++) {
931 char *curr = &ptr[i * page_size];
932 bool result = try_read_write_buf(curr);
933
934 if (i < 5) {
935 ASSERT_FALSE(result);
936 } else {
937 ASSERT_TRUE(result);
938 ASSERT_EQ(*curr, 'x');
939 }
940 }
941
942 /*
943 * Now lock the latter part of the range. We can't lock the guard pages,
944 * as this would result in the pages being populated and the guarding
945 * would cause this to error out.
946 */
947 ASSERT_EQ(mlock(&ptr[5 * page_size], 5 * page_size), 0);
948
949 /*
950 * Now remove guard pages, we permit mlock()'d ranges to have guard
951 * pages removed as it is a non-destructive operation.
952 */
953 ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_REMOVE), 0);
954
955 /* Now check that no guard pages remain. */
956 for (i = 0; i < 10; i++) {
957 char *curr = &ptr[i * page_size];
958
959 ASSERT_TRUE(try_read_write_buf(curr));
960 }
961
962 /* Cleanup. */
963 ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
964 }
965
966 /*
967 * Assert that moving, extending and shrinking memory via mremap() retains
968 * guard markers where possible.
969 *
970 * - Moving a mapping alone should retain markers as they are.
971 */
TEST_F(guard_regions,mremap_move)972 TEST_F(guard_regions, mremap_move)
973 {
974 const unsigned long page_size = self->page_size;
975 char *ptr, *ptr_new;
976
977 /* Map 5 pages. */
978 ptr = mmap_(self, variant, NULL, 5 * page_size,
979 PROT_READ | PROT_WRITE, 0, 0);
980 ASSERT_NE(ptr, MAP_FAILED);
981
982 /* Place guard markers at both ends of the 5 page span. */
983 ASSERT_EQ(madvise(ptr, page_size, MADV_GUARD_INSTALL), 0);
984 ASSERT_EQ(madvise(&ptr[4 * page_size], page_size, MADV_GUARD_INSTALL), 0);
985
986 /* Make sure the guard pages are in effect. */
987 ASSERT_FALSE(try_read_write_buf(ptr));
988 ASSERT_FALSE(try_read_write_buf(&ptr[4 * page_size]));
989
990 /* Map a new region we will move this range into. Doing this ensures
991 * that we have reserved a range to map into.
992 */
993 ptr_new = mmap_(self, variant, NULL, 5 * page_size, PROT_NONE, 0, 0);
994 ASSERT_NE(ptr_new, MAP_FAILED);
995
996 ASSERT_EQ(mremap(ptr, 5 * page_size, 5 * page_size,
997 MREMAP_MAYMOVE | MREMAP_FIXED, ptr_new), ptr_new);
998
999 /* Make sure the guard markers are retained. */
1000 ASSERT_FALSE(try_read_write_buf(ptr_new));
1001 ASSERT_FALSE(try_read_write_buf(&ptr_new[4 * page_size]));
1002
1003 /*
1004 * Clean up - we only need reference the new pointer as we overwrote the
1005 * PROT_NONE range and moved the existing one.
1006 */
1007 munmap(ptr_new, 5 * page_size);
1008 }
1009
1010 /*
1011 * Assert that moving, extending and shrinking memory via mremap() retains
1012 * guard markers where possible.
1013 *
1014 * Expanding should retain guard pages, only now in different position. The user
1015 * will have to remove guard pages manually to fix up (they'd have to do the
1016 * same if it were a PROT_NONE mapping).
1017 */
TEST_F(guard_regions,mremap_expand)1018 TEST_F(guard_regions, mremap_expand)
1019 {
1020 const unsigned long page_size = self->page_size;
1021 char *ptr, *ptr_new;
1022
1023 /* Map 10 pages... */
1024 ptr = mmap_(self, variant, NULL, 10 * page_size,
1025 PROT_READ | PROT_WRITE, 0, 0);
1026 ASSERT_NE(ptr, MAP_FAILED);
1027 /* ...But unmap the last 5 so we can ensure we can expand into them. */
1028 ASSERT_EQ(munmap(&ptr[5 * page_size], 5 * page_size), 0);
1029
1030 /* Place guard markers at both ends of the 5 page span. */
1031 ASSERT_EQ(madvise(ptr, page_size, MADV_GUARD_INSTALL), 0);
1032 ASSERT_EQ(madvise(&ptr[4 * page_size], page_size, MADV_GUARD_INSTALL), 0);
1033
1034 /* Make sure the guarding is in effect. */
1035 ASSERT_FALSE(try_read_write_buf(ptr));
1036 ASSERT_FALSE(try_read_write_buf(&ptr[4 * page_size]));
1037
1038 /* Now expand to 10 pages. */
1039 ptr = mremap(ptr, 5 * page_size, 10 * page_size, 0);
1040 ASSERT_NE(ptr, MAP_FAILED);
1041
1042 /*
1043 * Make sure the guard markers are retained in their original positions.
1044 */
1045 ASSERT_FALSE(try_read_write_buf(ptr));
1046 ASSERT_FALSE(try_read_write_buf(&ptr[4 * page_size]));
1047
1048 /* Reserve a region which we can move to and expand into. */
1049 ptr_new = mmap_(self, variant, NULL, 20 * page_size, PROT_NONE, 0, 0);
1050 ASSERT_NE(ptr_new, MAP_FAILED);
1051
1052 /* Now move and expand into it. */
1053 ptr = mremap(ptr, 10 * page_size, 20 * page_size,
1054 MREMAP_MAYMOVE | MREMAP_FIXED, ptr_new);
1055 ASSERT_EQ(ptr, ptr_new);
1056
1057 /*
1058 * Again, make sure the guard markers are retained in their original positions.
1059 */
1060 ASSERT_FALSE(try_read_write_buf(ptr));
1061 ASSERT_FALSE(try_read_write_buf(&ptr[4 * page_size]));
1062
1063 /*
1064 * A real user would have to remove guard markers, but would reasonably
1065 * expect all characteristics of the mapping to be retained, including
1066 * guard markers.
1067 */
1068
1069 /* Cleanup. */
1070 munmap(ptr, 20 * page_size);
1071 }
1072 /*
1073 * Assert that moving, extending and shrinking memory via mremap() retains
1074 * guard markers where possible.
1075 *
1076 * Shrinking will result in markers that are shrunk over being removed. Again,
1077 * if the user were using a PROT_NONE mapping they'd have to manually fix this
1078 * up also so this is OK.
1079 */
TEST_F(guard_regions,mremap_shrink)1080 TEST_F(guard_regions, mremap_shrink)
1081 {
1082 const unsigned long page_size = self->page_size;
1083 char *ptr;
1084 int i;
1085
1086 /* Map 5 pages. */
1087 ptr = mmap_(self, variant, NULL, 5 * page_size,
1088 PROT_READ | PROT_WRITE, 0, 0);
1089 ASSERT_NE(ptr, MAP_FAILED);
1090
1091 /* Place guard markers at both ends of the 5 page span. */
1092 ASSERT_EQ(madvise(ptr, page_size, MADV_GUARD_INSTALL), 0);
1093 ASSERT_EQ(madvise(&ptr[4 * page_size], page_size, MADV_GUARD_INSTALL), 0);
1094
1095 /* Make sure the guarding is in effect. */
1096 ASSERT_FALSE(try_read_write_buf(ptr));
1097 ASSERT_FALSE(try_read_write_buf(&ptr[4 * page_size]));
1098
1099 /* Now shrink to 3 pages. */
1100 ptr = mremap(ptr, 5 * page_size, 3 * page_size, MREMAP_MAYMOVE);
1101 ASSERT_NE(ptr, MAP_FAILED);
1102
1103 /* We expect the guard marker at the start to be retained... */
1104 ASSERT_FALSE(try_read_write_buf(ptr));
1105
1106 /* ...But remaining pages will not have guard markers. */
1107 for (i = 1; i < 3; i++) {
1108 char *curr = &ptr[i * page_size];
1109
1110 ASSERT_TRUE(try_read_write_buf(curr));
1111 }
1112
1113 /*
1114 * As with expansion, a real user would have to remove guard pages and
1115 * fixup. But you'd have to do similar manual things with PROT_NONE
1116 * mappings too.
1117 */
1118
1119 /*
1120 * If we expand back to the original size, the end marker will, of
1121 * course, no longer be present.
1122 */
1123 ptr = mremap(ptr, 3 * page_size, 5 * page_size, 0);
1124 ASSERT_NE(ptr, MAP_FAILED);
1125
1126 /* Again, we expect the guard marker at the start to be retained... */
1127 ASSERT_FALSE(try_read_write_buf(ptr));
1128
1129 /* ...But remaining pages will not have guard markers. */
1130 for (i = 1; i < 5; i++) {
1131 char *curr = &ptr[i * page_size];
1132
1133 ASSERT_TRUE(try_read_write_buf(curr));
1134 }
1135
1136 /* Cleanup. */
1137 munmap(ptr, 5 * page_size);
1138 }
1139
1140 /*
1141 * Assert that forking a process with VMAs that do not have VM_WIPEONFORK set
1142 * retain guard pages.
1143 */
TEST_F(guard_regions,fork)1144 TEST_F(guard_regions, fork)
1145 {
1146 const unsigned long page_size = self->page_size;
1147 char *ptr;
1148 pid_t pid;
1149 int i;
1150
1151 /* Map 10 pages. */
1152 ptr = mmap_(self, variant, NULL, 10 * page_size,
1153 PROT_READ | PROT_WRITE, 0, 0);
1154 ASSERT_NE(ptr, MAP_FAILED);
1155
1156 /* Establish guard pages in the first 5 pages. */
1157 ASSERT_EQ(madvise(ptr, 5 * page_size, MADV_GUARD_INSTALL), 0);
1158
1159 pid = fork();
1160 ASSERT_NE(pid, -1);
1161 if (!pid) {
1162 /* This is the child process now. */
1163
1164 /* Assert that the guarding is in effect. */
1165 for (i = 0; i < 10; i++) {
1166 char *curr = &ptr[i * page_size];
1167 bool result = try_read_write_buf(curr);
1168
1169 ASSERT_TRUE(i >= 5 ? result : !result);
1170 }
1171
1172 /* Now unguard the range.*/
1173 ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_REMOVE), 0);
1174
1175 exit(0);
1176 }
1177
1178 /* Parent process. */
1179
1180 /* Parent simply waits on child. */
1181 waitpid(pid, NULL, 0);
1182
1183 /* Child unguard does not impact parent page table state. */
1184 for (i = 0; i < 10; i++) {
1185 char *curr = &ptr[i * page_size];
1186 bool result = try_read_write_buf(curr);
1187
1188 ASSERT_TRUE(i >= 5 ? result : !result);
1189 }
1190
1191 /* Cleanup. */
1192 ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
1193 }
1194
1195 /*
1196 * Assert expected behaviour after we fork populated ranges of anonymous memory
1197 * and then guard and unguard the range.
1198 */
TEST_F(guard_regions,fork_cow)1199 TEST_F(guard_regions, fork_cow)
1200 {
1201 const unsigned long page_size = self->page_size;
1202 char *ptr;
1203 pid_t pid;
1204 int i;
1205
1206 if (variant->backing != ANON_BACKED)
1207 SKIP(return, "CoW only supported on anon mappings");
1208
1209 /* Map 10 pages. */
1210 ptr = mmap_(self, variant, NULL, 10 * page_size,
1211 PROT_READ | PROT_WRITE, 0, 0);
1212 ASSERT_NE(ptr, MAP_FAILED);
1213
1214 /* Populate range. */
1215 for (i = 0; i < 10 * page_size; i++) {
1216 char chr = 'a' + (i % 26);
1217
1218 ptr[i] = chr;
1219 }
1220
1221 pid = fork();
1222 ASSERT_NE(pid, -1);
1223 if (!pid) {
1224 /* This is the child process now. */
1225
1226 /* Ensure the range is as expected. */
1227 for (i = 0; i < 10 * page_size; i++) {
1228 char expected = 'a' + (i % 26);
1229 char actual = ptr[i];
1230
1231 ASSERT_EQ(actual, expected);
1232 }
1233
1234 /* Establish guard pages across the whole range. */
1235 ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_INSTALL), 0);
1236 /* Remove it. */
1237 ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_REMOVE), 0);
1238
1239 /*
1240 * By removing the guard pages, the page tables will be
1241 * cleared. Assert that we are looking at the zero page now.
1242 */
1243 for (i = 0; i < 10 * page_size; i++) {
1244 char actual = ptr[i];
1245
1246 ASSERT_EQ(actual, '\0');
1247 }
1248
1249 exit(0);
1250 }
1251
1252 /* Parent process. */
1253
1254 /* Parent simply waits on child. */
1255 waitpid(pid, NULL, 0);
1256
1257 /* Ensure the range is unchanged in parent anon range. */
1258 for (i = 0; i < 10 * page_size; i++) {
1259 char expected = 'a' + (i % 26);
1260 char actual = ptr[i];
1261
1262 ASSERT_EQ(actual, expected);
1263 }
1264
1265 /* Cleanup. */
1266 ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
1267 }
1268
1269 /*
1270 * Assert that forking a process with VMAs that do have VM_WIPEONFORK set
1271 * behave as expected.
1272 */
TEST_F(guard_regions,fork_wipeonfork)1273 TEST_F(guard_regions, fork_wipeonfork)
1274 {
1275 const unsigned long page_size = self->page_size;
1276 char *ptr;
1277 pid_t pid;
1278 int i;
1279
1280 if (variant->backing != ANON_BACKED)
1281 SKIP(return, "Wipe on fork only supported on anon mappings");
1282
1283 /* Map 10 pages. */
1284 ptr = mmap_(self, variant, NULL, 10 * page_size,
1285 PROT_READ | PROT_WRITE, 0, 0);
1286 ASSERT_NE(ptr, MAP_FAILED);
1287
1288 /* Mark wipe on fork. */
1289 ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_WIPEONFORK), 0);
1290
1291 /* Guard the first 5 pages. */
1292 ASSERT_EQ(madvise(ptr, 5 * page_size, MADV_GUARD_INSTALL), 0);
1293
1294 pid = fork();
1295 ASSERT_NE(pid, -1);
1296 if (!pid) {
1297 /* This is the child process now. */
1298
1299 /* Guard will have been wiped. */
1300 for (i = 0; i < 10; i++) {
1301 char *curr = &ptr[i * page_size];
1302
1303 ASSERT_TRUE(try_read_write_buf(curr));
1304 }
1305
1306 exit(0);
1307 }
1308
1309 /* Parent process. */
1310
1311 waitpid(pid, NULL, 0);
1312
1313 /* Guard markers should be in effect.*/
1314 for (i = 0; i < 10; i++) {
1315 char *curr = &ptr[i * page_size];
1316 bool result = try_read_write_buf(curr);
1317
1318 ASSERT_TRUE(i >= 5 ? result : !result);
1319 }
1320
1321 /* Cleanup. */
1322 ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
1323 }
1324
1325 /* Ensure that MADV_FREE retains guard entries as expected. */
TEST_F(guard_regions,lazyfree)1326 TEST_F(guard_regions, lazyfree)
1327 {
1328 const unsigned long page_size = self->page_size;
1329 char *ptr;
1330 int i;
1331
1332 if (variant->backing != ANON_BACKED)
1333 SKIP(return, "MADV_FREE only supported on anon mappings");
1334
1335 /* Map 10 pages. */
1336 ptr = mmap_(self, variant, NULL, 10 * page_size,
1337 PROT_READ | PROT_WRITE, 0, 0);
1338 ASSERT_NE(ptr, MAP_FAILED);
1339
1340 /* Guard range. */
1341 ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_INSTALL), 0);
1342
1343 /* Ensure guarded. */
1344 for (i = 0; i < 10; i++) {
1345 char *curr = &ptr[i * page_size];
1346
1347 ASSERT_FALSE(try_read_write_buf(curr));
1348 }
1349
1350 /* Lazyfree range. */
1351 ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_FREE), 0);
1352
1353 /* This should leave the guard markers in place. */
1354 for (i = 0; i < 10; i++) {
1355 char *curr = &ptr[i * page_size];
1356
1357 ASSERT_FALSE(try_read_write_buf(curr));
1358 }
1359
1360 /* Cleanup. */
1361 ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
1362 }
1363
1364 /* Ensure that MADV_POPULATE_READ, MADV_POPULATE_WRITE behave as expected. */
TEST_F(guard_regions,populate)1365 TEST_F(guard_regions, populate)
1366 {
1367 const unsigned long page_size = self->page_size;
1368 char *ptr;
1369
1370 /* Map 10 pages. */
1371 ptr = mmap_(self, variant, NULL, 10 * page_size,
1372 PROT_READ | PROT_WRITE, 0, 0);
1373 ASSERT_NE(ptr, MAP_FAILED);
1374
1375 /* Guard range. */
1376 ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_INSTALL), 0);
1377
1378 /* Populate read should error out... */
1379 ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_POPULATE_READ), -1);
1380 ASSERT_EQ(errno, EFAULT);
1381
1382 /* ...as should populate write. */
1383 ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_POPULATE_WRITE), -1);
1384 ASSERT_EQ(errno, EFAULT);
1385
1386 /* Cleanup. */
1387 ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
1388 }
1389
1390 /* Ensure that MADV_COLD, MADV_PAGEOUT do not remove guard markers. */
TEST_F(guard_regions,cold_pageout)1391 TEST_F(guard_regions, cold_pageout)
1392 {
1393 const unsigned long page_size = self->page_size;
1394 char *ptr;
1395 int i;
1396
1397 /* Map 10 pages. */
1398 ptr = mmap_(self, variant, NULL, 10 * page_size,
1399 PROT_READ | PROT_WRITE, 0, 0);
1400 ASSERT_NE(ptr, MAP_FAILED);
1401
1402 /* Guard range. */
1403 ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_INSTALL), 0);
1404
1405 /* Ensured guarded. */
1406 for (i = 0; i < 10; i++) {
1407 char *curr = &ptr[i * page_size];
1408
1409 ASSERT_FALSE(try_read_write_buf(curr));
1410 }
1411
1412 /* Now mark cold. This should have no impact on guard markers. */
1413 ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_COLD), 0);
1414
1415 /* Should remain guarded. */
1416 for (i = 0; i < 10; i++) {
1417 char *curr = &ptr[i * page_size];
1418
1419 ASSERT_FALSE(try_read_write_buf(curr));
1420 }
1421
1422 /* OK, now page out. This should equally, have no effect on markers. */
1423 ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_PAGEOUT), 0);
1424
1425 /* Should remain guarded. */
1426 for (i = 0; i < 10; i++) {
1427 char *curr = &ptr[i * page_size];
1428
1429 ASSERT_FALSE(try_read_write_buf(curr));
1430 }
1431
1432 /* Cleanup. */
1433 ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
1434 }
1435
1436 /* Ensure that guard pages do not break userfaultd. */
TEST_F(guard_regions,uffd)1437 TEST_F(guard_regions, uffd)
1438 {
1439 const unsigned long page_size = self->page_size;
1440 int uffd;
1441 char *ptr;
1442 int i;
1443 struct uffdio_api api = {
1444 .api = UFFD_API,
1445 .features = 0,
1446 };
1447 struct uffdio_register reg;
1448 struct uffdio_range range;
1449
1450 if (!is_anon_backed(variant))
1451 SKIP(return, "uffd only works on anon backing");
1452
1453 /* Set up uffd. */
1454 uffd = userfaultfd(0);
1455 if (uffd == -1 && errno == EPERM)
1456 ksft_exit_skip("No userfaultfd permissions, try running as root.\n");
1457 ASSERT_NE(uffd, -1);
1458
1459 ASSERT_EQ(ioctl(uffd, UFFDIO_API, &api), 0);
1460
1461 /* Map 10 pages. */
1462 ptr = mmap_(self, variant, NULL, 10 * page_size,
1463 PROT_READ | PROT_WRITE, 0, 0);
1464 ASSERT_NE(ptr, MAP_FAILED);
1465
1466 /* Register the range with uffd. */
1467 range.start = (unsigned long)ptr;
1468 range.len = 10 * page_size;
1469 reg.range = range;
1470 reg.mode = UFFDIO_REGISTER_MODE_MISSING;
1471 ASSERT_EQ(ioctl(uffd, UFFDIO_REGISTER, ®), 0);
1472
1473 /* Guard the range. This should not trigger the uffd. */
1474 ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_INSTALL), 0);
1475
1476 /* The guarding should behave as usual with no uffd intervention. */
1477 for (i = 0; i < 10; i++) {
1478 char *curr = &ptr[i * page_size];
1479
1480 ASSERT_FALSE(try_read_write_buf(curr));
1481 }
1482
1483 /* Cleanup. */
1484 ASSERT_EQ(ioctl(uffd, UFFDIO_UNREGISTER, &range), 0);
1485 close(uffd);
1486 ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
1487 }
1488
1489 /*
1490 * Mark a region within a file-backed mapping using MADV_SEQUENTIAL so we
1491 * aggressively read-ahead, then install guard regions and assert that it
1492 * behaves correctly.
1493 *
1494 * We page out using MADV_PAGEOUT before checking guard regions so we drop page
1495 * cache folios, meaning we maximise the possibility of some broken readahead.
1496 */
TEST_F(guard_regions,madvise_sequential)1497 TEST_F(guard_regions, madvise_sequential)
1498 {
1499 char *ptr;
1500 int i;
1501 const unsigned long page_size = self->page_size;
1502
1503 if (variant->backing == ANON_BACKED)
1504 SKIP(return, "MADV_SEQUENTIAL meaningful only for file-backed");
1505
1506 ptr = mmap_(self, variant, NULL, 10 * page_size,
1507 PROT_READ | PROT_WRITE, 0, 0);
1508 ASSERT_NE(ptr, MAP_FAILED);
1509
1510 /* Establish a pattern of data in the file. */
1511 set_pattern(ptr, 10, page_size);
1512 ASSERT_TRUE(check_pattern(ptr, 10, page_size));
1513
1514 /* Mark it as being accessed sequentially. */
1515 ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_SEQUENTIAL), 0);
1516
1517 /* Mark every other page a guard page. */
1518 for (i = 0; i < 10; i += 2) {
1519 char *ptr2 = &ptr[i * page_size];
1520
1521 ASSERT_EQ(madvise(ptr2, page_size, MADV_GUARD_INSTALL), 0);
1522 }
1523
1524 /* Now page it out. */
1525 ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_PAGEOUT), 0);
1526
1527 /* Now make sure pages are as expected. */
1528 for (i = 0; i < 10; i++) {
1529 char *chrp = &ptr[i * page_size];
1530
1531 if (i % 2 == 0) {
1532 bool result = try_read_write_buf(chrp);
1533
1534 ASSERT_FALSE(result);
1535 } else {
1536 ASSERT_EQ(*chrp, 'a' + i);
1537 }
1538 }
1539
1540 /* Now remove guard pages. */
1541 ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_REMOVE), 0);
1542
1543 /* Now make sure all data is as expected. */
1544 if (!check_pattern(ptr, 10, page_size))
1545 ASSERT_TRUE(false);
1546
1547 ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
1548 }
1549
1550 /*
1551 * Check that file-backed mappings implement guard regions with MAP_PRIVATE
1552 * correctly.
1553 */
TEST_F(guard_regions,map_private)1554 TEST_F(guard_regions, map_private)
1555 {
1556 const unsigned long page_size = self->page_size;
1557 char *ptr_shared, *ptr_private;
1558 int i;
1559
1560 if (variant->backing == ANON_BACKED)
1561 SKIP(return, "MAP_PRIVATE test specific to file-backed");
1562
1563 ptr_shared = mmap_(self, variant, NULL, 10 * page_size, PROT_READ | PROT_WRITE, 0, 0);
1564 ASSERT_NE(ptr_shared, MAP_FAILED);
1565
1566 /* Manually mmap(), do not use mmap_() wrapper so we can force MAP_PRIVATE. */
1567 ptr_private = mmap(NULL, 10 * page_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, self->fd, 0);
1568 ASSERT_NE(ptr_private, MAP_FAILED);
1569
1570 /* Set pattern in shared mapping. */
1571 set_pattern(ptr_shared, 10, page_size);
1572
1573 /* Install guard regions in every other page in the shared mapping. */
1574 for (i = 0; i < 10; i += 2) {
1575 char *ptr = &ptr_shared[i * page_size];
1576
1577 ASSERT_EQ(madvise(ptr, page_size, MADV_GUARD_INSTALL), 0);
1578 }
1579
1580 for (i = 0; i < 10; i++) {
1581 /* Every even shared page should be guarded. */
1582 ASSERT_EQ(try_read_buf(&ptr_shared[i * page_size]), i % 2 != 0);
1583 /* Private mappings should always be readable. */
1584 ASSERT_TRUE(try_read_buf(&ptr_private[i * page_size]));
1585 }
1586
1587 /* Install guard regions in every other page in the private mapping. */
1588 for (i = 0; i < 10; i += 2) {
1589 char *ptr = &ptr_private[i * page_size];
1590
1591 ASSERT_EQ(madvise(ptr, page_size, MADV_GUARD_INSTALL), 0);
1592 }
1593
1594 for (i = 0; i < 10; i++) {
1595 /* Every even shared page should be guarded. */
1596 ASSERT_EQ(try_read_buf(&ptr_shared[i * page_size]), i % 2 != 0);
1597 /* Every odd private page should be guarded. */
1598 ASSERT_EQ(try_read_buf(&ptr_private[i * page_size]), i % 2 != 0);
1599 }
1600
1601 /* Remove guard regions from shared mapping. */
1602 ASSERT_EQ(madvise(ptr_shared, 10 * page_size, MADV_GUARD_REMOVE), 0);
1603
1604 for (i = 0; i < 10; i++) {
1605 /* Shared mappings should always be readable. */
1606 ASSERT_TRUE(try_read_buf(&ptr_shared[i * page_size]));
1607 /* Every even private page should be guarded. */
1608 ASSERT_EQ(try_read_buf(&ptr_private[i * page_size]), i % 2 != 0);
1609 }
1610
1611 /* Remove guard regions from private mapping. */
1612 ASSERT_EQ(madvise(ptr_private, 10 * page_size, MADV_GUARD_REMOVE), 0);
1613
1614 for (i = 0; i < 10; i++) {
1615 /* Shared mappings should always be readable. */
1616 ASSERT_TRUE(try_read_buf(&ptr_shared[i * page_size]));
1617 /* Private mappings should always be readable. */
1618 ASSERT_TRUE(try_read_buf(&ptr_private[i * page_size]));
1619 }
1620
1621 /* Ensure patterns are intact. */
1622 ASSERT_TRUE(check_pattern(ptr_shared, 10, page_size));
1623 ASSERT_TRUE(check_pattern(ptr_private, 10, page_size));
1624
1625 /* Now write out every other page to MAP_PRIVATE. */
1626 for (i = 0; i < 10; i += 2) {
1627 char *ptr = &ptr_private[i * page_size];
1628
1629 memset(ptr, 'a' + i, page_size);
1630 }
1631
1632 /*
1633 * At this point the mapping is:
1634 *
1635 * 0123456789
1636 * SPSPSPSPSP
1637 *
1638 * Where S = shared, P = private mappings.
1639 */
1640
1641 /* Now mark the beginning of the mapping guarded. */
1642 ASSERT_EQ(madvise(ptr_private, 5 * page_size, MADV_GUARD_INSTALL), 0);
1643
1644 /*
1645 * This renders the mapping:
1646 *
1647 * 0123456789
1648 * xxxxxPSPSP
1649 */
1650
1651 for (i = 0; i < 10; i++) {
1652 char *ptr = &ptr_private[i * page_size];
1653
1654 /* Ensure guard regions as expected. */
1655 ASSERT_EQ(try_read_buf(ptr), i >= 5);
1656 /* The shared mapping should always succeed. */
1657 ASSERT_TRUE(try_read_buf(&ptr_shared[i * page_size]));
1658 }
1659
1660 /* Remove the guard regions altogether. */
1661 ASSERT_EQ(madvise(ptr_private, 10 * page_size, MADV_GUARD_REMOVE), 0);
1662
1663 /*
1664 *
1665 * We now expect the mapping to be:
1666 *
1667 * 0123456789
1668 * SSSSSPSPSP
1669 *
1670 * As we removed guard regions, the private pages from the first 5 will
1671 * have been zapped, so on fault will reestablish the shared mapping.
1672 */
1673
1674 for (i = 0; i < 10; i++) {
1675 char *ptr = &ptr_private[i * page_size];
1676
1677 /*
1678 * Assert that shared mappings in the MAP_PRIVATE mapping match
1679 * the shared mapping.
1680 */
1681 if (i < 5 || i % 2 == 0) {
1682 char *ptr_s = &ptr_shared[i * page_size];
1683
1684 ASSERT_EQ(memcmp(ptr, ptr_s, page_size), 0);
1685 continue;
1686 }
1687
1688 /* Everything else is a private mapping. */
1689 ASSERT_TRUE(is_buf_eq(ptr, page_size, 'a' + i));
1690 }
1691
1692 ASSERT_EQ(munmap(ptr_shared, 10 * page_size), 0);
1693 ASSERT_EQ(munmap(ptr_private, 10 * page_size), 0);
1694 }
1695
1696 /* Test that guard regions established over a read-only mapping function correctly. */
TEST_F(guard_regions,readonly_file)1697 TEST_F(guard_regions, readonly_file)
1698 {
1699 const unsigned long page_size = self->page_size;
1700 char *ptr;
1701 int i;
1702
1703 if (variant->backing != LOCAL_FILE_BACKED)
1704 SKIP(return, "Read-only test specific to file-backed");
1705
1706 /* Map shared so we can populate with pattern, populate it, unmap. */
1707 ptr = mmap_(self, variant, NULL, 10 * page_size,
1708 PROT_READ | PROT_WRITE, 0, 0);
1709 ASSERT_NE(ptr, MAP_FAILED);
1710 set_pattern(ptr, 10, page_size);
1711 ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
1712 /* Close the fd so we can re-open read-only. */
1713 ASSERT_EQ(close(self->fd), 0);
1714
1715 /* Re-open read-only. */
1716 self->fd = open(self->path, O_RDONLY);
1717 ASSERT_NE(self->fd, -1);
1718 /* Re-map read-only. */
1719 ptr = mmap_(self, variant, NULL, 10 * page_size, PROT_READ, 0, 0);
1720 ASSERT_NE(ptr, MAP_FAILED);
1721
1722 /* Mark every other page guarded. */
1723 for (i = 0; i < 10; i += 2) {
1724 char *ptr_pg = &ptr[i * page_size];
1725
1726 ASSERT_EQ(madvise(ptr_pg, page_size, MADV_GUARD_INSTALL), 0);
1727 }
1728
1729 /* Assert that the guard regions are in place.*/
1730 for (i = 0; i < 10; i++) {
1731 char *ptr_pg = &ptr[i * page_size];
1732
1733 ASSERT_EQ(try_read_buf(ptr_pg), i % 2 != 0);
1734 }
1735
1736 /* Remove guard regions. */
1737 ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_REMOVE), 0);
1738
1739 /* Ensure the data is as expected. */
1740 ASSERT_TRUE(check_pattern(ptr, 10, page_size));
1741
1742 ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
1743 }
1744
TEST_F(guard_regions,fault_around)1745 TEST_F(guard_regions, fault_around)
1746 {
1747 const unsigned long page_size = self->page_size;
1748 char *ptr;
1749 int i;
1750
1751 if (variant->backing == ANON_BACKED)
1752 SKIP(return, "Fault-around test specific to file-backed");
1753
1754 ptr = mmap_(self, variant, NULL, 10 * page_size,
1755 PROT_READ | PROT_WRITE, 0, 0);
1756 ASSERT_NE(ptr, MAP_FAILED);
1757
1758 /* Establish a pattern in the backing file. */
1759 set_pattern(ptr, 10, page_size);
1760
1761 /*
1762 * Now drop it from the page cache so we get major faults when next we
1763 * map it.
1764 */
1765 ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_PAGEOUT), 0);
1766
1767 /* Unmap and remap 'to be sure'. */
1768 ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
1769 ptr = mmap_(self, variant, NULL, 10 * page_size,
1770 PROT_READ | PROT_WRITE, 0, 0);
1771 ASSERT_NE(ptr, MAP_FAILED);
1772
1773 /* Now make every even page guarded. */
1774 for (i = 0; i < 10; i += 2) {
1775 char *ptr_p = &ptr[i * page_size];
1776
1777 ASSERT_EQ(madvise(ptr_p, page_size, MADV_GUARD_INSTALL), 0);
1778 }
1779
1780 /* Now fault in every odd page. This should trigger fault-around. */
1781 for (i = 1; i < 10; i += 2) {
1782 char *ptr_p = &ptr[i * page_size];
1783
1784 ASSERT_TRUE(try_read_buf(ptr_p));
1785 }
1786
1787 /* Finally, ensure that guard regions are intact as expected. */
1788 for (i = 0; i < 10; i++) {
1789 char *ptr_p = &ptr[i * page_size];
1790
1791 ASSERT_EQ(try_read_buf(ptr_p), i % 2 != 0);
1792 }
1793
1794 ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
1795 }
1796
TEST_F(guard_regions,truncation)1797 TEST_F(guard_regions, truncation)
1798 {
1799 const unsigned long page_size = self->page_size;
1800 char *ptr;
1801 int i;
1802
1803 if (variant->backing == ANON_BACKED)
1804 SKIP(return, "Truncation test specific to file-backed");
1805
1806 ptr = mmap_(self, variant, NULL, 10 * page_size,
1807 PROT_READ | PROT_WRITE, 0, 0);
1808 ASSERT_NE(ptr, MAP_FAILED);
1809
1810 /*
1811 * Establish a pattern in the backing file, just so there is data
1812 * there.
1813 */
1814 set_pattern(ptr, 10, page_size);
1815
1816 /* Now make every even page guarded. */
1817 for (i = 0; i < 10; i += 2) {
1818 char *ptr_p = &ptr[i * page_size];
1819
1820 ASSERT_EQ(madvise(ptr_p, page_size, MADV_GUARD_INSTALL), 0);
1821 }
1822
1823 /* Now assert things are as expected. */
1824 for (i = 0; i < 10; i++) {
1825 char *ptr_p = &ptr[i * page_size];
1826
1827 ASSERT_EQ(try_read_write_buf(ptr_p), i % 2 != 0);
1828 }
1829
1830 /* Now truncate to actually used size (initialised to 100). */
1831 ASSERT_EQ(ftruncate(self->fd, 10 * page_size), 0);
1832
1833 /* Here the guard regions will remain intact. */
1834 for (i = 0; i < 10; i++) {
1835 char *ptr_p = &ptr[i * page_size];
1836
1837 ASSERT_EQ(try_read_write_buf(ptr_p), i % 2 != 0);
1838 }
1839
1840 /* Now truncate to half the size, then truncate again to the full size. */
1841 ASSERT_EQ(ftruncate(self->fd, 5 * page_size), 0);
1842 ASSERT_EQ(ftruncate(self->fd, 10 * page_size), 0);
1843
1844 /* Again, guard pages will remain intact. */
1845 for (i = 0; i < 10; i++) {
1846 char *ptr_p = &ptr[i * page_size];
1847
1848 ASSERT_EQ(try_read_write_buf(ptr_p), i % 2 != 0);
1849 }
1850
1851 ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
1852 }
1853
TEST_F(guard_regions,hole_punch)1854 TEST_F(guard_regions, hole_punch)
1855 {
1856 const unsigned long page_size = self->page_size;
1857 char *ptr;
1858 int i;
1859
1860 if (variant->backing == ANON_BACKED)
1861 SKIP(return, "Truncation test specific to file-backed");
1862
1863 /* Establish pattern in mapping. */
1864 ptr = mmap_(self, variant, NULL, 10 * page_size,
1865 PROT_READ | PROT_WRITE, 0, 0);
1866 ASSERT_NE(ptr, MAP_FAILED);
1867 set_pattern(ptr, 10, page_size);
1868
1869 /* Install a guard region in the middle of the mapping. */
1870 ASSERT_EQ(madvise(&ptr[3 * page_size], 4 * page_size,
1871 MADV_GUARD_INSTALL), 0);
1872
1873 /*
1874 * The buffer will now be:
1875 *
1876 * 0123456789
1877 * ***xxxx***
1878 *
1879 * Where * is data and x is the guard region.
1880 */
1881
1882 /* Ensure established. */
1883 for (i = 0; i < 10; i++) {
1884 char *ptr_p = &ptr[i * page_size];
1885
1886 ASSERT_EQ(try_read_buf(ptr_p), i < 3 || i >= 7);
1887 }
1888
1889 /* Now hole punch the guarded region. */
1890 ASSERT_EQ(madvise(&ptr[3 * page_size], 4 * page_size,
1891 MADV_REMOVE), 0);
1892
1893 /* Ensure guard regions remain. */
1894 for (i = 0; i < 10; i++) {
1895 char *ptr_p = &ptr[i * page_size];
1896
1897 ASSERT_EQ(try_read_buf(ptr_p), i < 3 || i >= 7);
1898 }
1899
1900 /* Now remove guard region throughout. */
1901 ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_REMOVE), 0);
1902
1903 /* Check that the pattern exists in non-hole punched region. */
1904 ASSERT_TRUE(check_pattern(ptr, 3, page_size));
1905 /* Check that hole punched region is zeroed. */
1906 ASSERT_TRUE(is_buf_eq(&ptr[3 * page_size], 4 * page_size, '\0'));
1907 /* Check that the pattern exists in the remainder of the file. */
1908 ASSERT_TRUE(check_pattern_offset(ptr, 3, page_size, 7));
1909
1910 ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
1911 }
1912
1913 /*
1914 * Ensure that a memfd works correctly with guard regions, that we can write
1915 * seal it then open the mapping read-only and still establish guard regions
1916 * within, remove those guard regions and have everything work correctly.
1917 */
TEST_F(guard_regions,memfd_write_seal)1918 TEST_F(guard_regions, memfd_write_seal)
1919 {
1920 const unsigned long page_size = self->page_size;
1921 char *ptr;
1922 int i;
1923
1924 if (variant->backing != SHMEM_BACKED)
1925 SKIP(return, "memfd write seal test specific to shmem");
1926
1927 /* OK, we need a memfd, so close existing one. */
1928 ASSERT_EQ(close(self->fd), 0);
1929
1930 /* Create and truncate memfd. */
1931 self->fd = memfd_create("guard_regions_memfd_seals_test",
1932 MFD_ALLOW_SEALING);
1933 ASSERT_NE(self->fd, -1);
1934 ASSERT_EQ(ftruncate(self->fd, 10 * page_size), 0);
1935
1936 /* Map, set pattern, unmap. */
1937 ptr = mmap_(self, variant, NULL, 10 * page_size, PROT_READ | PROT_WRITE, 0, 0);
1938 ASSERT_NE(ptr, MAP_FAILED);
1939 set_pattern(ptr, 10, page_size);
1940 ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
1941
1942 /* Write-seal the memfd. */
1943 ASSERT_EQ(fcntl(self->fd, F_ADD_SEALS, F_SEAL_WRITE), 0);
1944
1945 /* Now map the memfd readonly. */
1946 ptr = mmap_(self, variant, NULL, 10 * page_size, PROT_READ, 0, 0);
1947 ASSERT_NE(ptr, MAP_FAILED);
1948
1949 /* Ensure pattern is as expected. */
1950 ASSERT_TRUE(check_pattern(ptr, 10, page_size));
1951
1952 /* Now make every even page guarded. */
1953 for (i = 0; i < 10; i += 2) {
1954 char *ptr_p = &ptr[i * page_size];
1955
1956 ASSERT_EQ(madvise(ptr_p, page_size, MADV_GUARD_INSTALL), 0);
1957 }
1958
1959 /* Now assert things are as expected. */
1960 for (i = 0; i < 10; i++) {
1961 char *ptr_p = &ptr[i * page_size];
1962
1963 ASSERT_EQ(try_read_buf(ptr_p), i % 2 != 0);
1964 }
1965
1966 /* Now remove guard regions. */
1967 ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_REMOVE), 0);
1968
1969 /* Ensure pattern is as expected. */
1970 ASSERT_TRUE(check_pattern(ptr, 10, page_size));
1971
1972 /* Ensure write seal intact. */
1973 for (i = 0; i < 10; i++) {
1974 char *ptr_p = &ptr[i * page_size];
1975
1976 ASSERT_FALSE(try_write_buf(ptr_p));
1977 }
1978
1979 ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
1980 }
1981
1982
1983 /*
1984 * Since we are now permitted to establish guard regions in read-only anonymous
1985 * mappings, for the sake of thoroughness, though it probably has no practical
1986 * use, test that guard regions function with a mapping to the anonymous zero
1987 * page.
1988 */
TEST_F(guard_regions,anon_zeropage)1989 TEST_F(guard_regions, anon_zeropage)
1990 {
1991 const unsigned long page_size = self->page_size;
1992 char *ptr;
1993 int i;
1994
1995 if (!is_anon_backed(variant))
1996 SKIP(return, "anon zero page test specific to anon/shmem");
1997
1998 /* Obtain a read-only i.e. anon zero page mapping. */
1999 ptr = mmap_(self, variant, NULL, 10 * page_size, PROT_READ, 0, 0);
2000 ASSERT_NE(ptr, MAP_FAILED);
2001
2002 /* Now make every even page guarded. */
2003 for (i = 0; i < 10; i += 2) {
2004 char *ptr_p = &ptr[i * page_size];
2005
2006 ASSERT_EQ(madvise(ptr_p, page_size, MADV_GUARD_INSTALL), 0);
2007 }
2008
2009 /* Now assert things are as expected. */
2010 for (i = 0; i < 10; i++) {
2011 char *ptr_p = &ptr[i * page_size];
2012
2013 ASSERT_EQ(try_read_buf(ptr_p), i % 2 != 0);
2014 }
2015
2016 /* Now remove all guard regions. */
2017 ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_REMOVE), 0);
2018
2019 /* Now assert things are as expected. */
2020 for (i = 0; i < 10; i++) {
2021 char *ptr_p = &ptr[i * page_size];
2022
2023 ASSERT_TRUE(try_read_buf(ptr_p));
2024 }
2025
2026 /* Ensure zero page...*/
2027 ASSERT_TRUE(is_buf_eq(ptr, 10 * page_size, '\0'));
2028
2029 ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
2030 }
2031
2032 /*
2033 * Assert that /proc/$pid/pagemap correctly identifies guard region ranges.
2034 */
TEST_F(guard_regions,pagemap)2035 TEST_F(guard_regions, pagemap)
2036 {
2037 const unsigned long page_size = self->page_size;
2038 int proc_fd;
2039 char *ptr;
2040 int i;
2041
2042 proc_fd = open("/proc/self/pagemap", O_RDONLY);
2043 ASSERT_NE(proc_fd, -1);
2044
2045 ptr = mmap_(self, variant, NULL, 10 * page_size,
2046 PROT_READ | PROT_WRITE, 0, 0);
2047 ASSERT_NE(ptr, MAP_FAILED);
2048
2049 /* Read from pagemap, and assert no guard regions are detected. */
2050 for (i = 0; i < 10; i++) {
2051 char *ptr_p = &ptr[i * page_size];
2052 unsigned long entry = pagemap_get_entry(proc_fd, ptr_p);
2053 unsigned long masked = entry & PM_GUARD_REGION;
2054
2055 ASSERT_EQ(masked, 0);
2056 }
2057
2058 /* Install a guard region in every other page. */
2059 for (i = 0; i < 10; i += 2) {
2060 char *ptr_p = &ptr[i * page_size];
2061
2062 ASSERT_EQ(madvise(ptr_p, page_size, MADV_GUARD_INSTALL), 0);
2063 }
2064
2065 /* Re-read from pagemap, and assert guard regions are detected. */
2066 for (i = 0; i < 10; i++) {
2067 char *ptr_p = &ptr[i * page_size];
2068 unsigned long entry = pagemap_get_entry(proc_fd, ptr_p);
2069 unsigned long masked = entry & PM_GUARD_REGION;
2070
2071 ASSERT_EQ(masked, i % 2 == 0 ? PM_GUARD_REGION : 0);
2072 }
2073
2074 ASSERT_EQ(close(proc_fd), 0);
2075 ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
2076 }
2077
2078 TEST_HARNESS_MAIN
2079