xref: /linux/tools/testing/selftests/mm/guard-regions.c (revision 3349e275067f94ffb4141989aed9cbae7409429b)
1ce1c0824SLorenzo Stoakes // SPDX-License-Identifier: GPL-2.0-or-later
2ce1c0824SLorenzo Stoakes 
3ce1c0824SLorenzo Stoakes #define _GNU_SOURCE
4ce1c0824SLorenzo Stoakes #include "../kselftest_harness.h"
5ce1c0824SLorenzo Stoakes #include <asm-generic/mman.h> /* Force the import of the tools version. */
6ce1c0824SLorenzo Stoakes #include <assert.h>
7ce1c0824SLorenzo Stoakes #include <errno.h>
8ce1c0824SLorenzo Stoakes #include <fcntl.h>
9272f37d3SLorenzo Stoakes #include <linux/limits.h>
10ce1c0824SLorenzo Stoakes #include <linux/userfaultfd.h>
11ce1c0824SLorenzo Stoakes #include <linux/fs.h>
12ce1c0824SLorenzo Stoakes #include <setjmp.h>
13ce1c0824SLorenzo Stoakes #include <signal.h>
14ce1c0824SLorenzo Stoakes #include <stdbool.h>
15ce1c0824SLorenzo Stoakes #include <stdio.h>
16ce1c0824SLorenzo Stoakes #include <stdlib.h>
17ce1c0824SLorenzo Stoakes #include <string.h>
18ce1c0824SLorenzo Stoakes #include <sys/ioctl.h>
19ce1c0824SLorenzo Stoakes #include <sys/mman.h>
20ce1c0824SLorenzo Stoakes #include <sys/syscall.h>
21ce1c0824SLorenzo Stoakes #include <sys/uio.h>
22f3b92176SLorenzo Stoakes #include <unistd.h>
23ce1c0824SLorenzo Stoakes #include "vm_util.h"
24eb0ece16SLinus Torvalds 
25eb0ece16SLinus Torvalds #include "../pidfd/pidfd.h"
26ce1c0824SLorenzo Stoakes 
27ce1c0824SLorenzo Stoakes /*
28ce1c0824SLorenzo Stoakes  * Ignore the checkpatch warning, as per the C99 standard, section 7.14.1.1:
29ce1c0824SLorenzo Stoakes  *
30ce1c0824SLorenzo Stoakes  * "If the signal occurs other than as the result of calling the abort or raise
31ce1c0824SLorenzo Stoakes  *  function, the behavior is undefined if the signal handler refers to any
32ce1c0824SLorenzo Stoakes  *  object with static storage duration other than by assigning a value to an
33ce1c0824SLorenzo Stoakes  *  object declared as volatile sig_atomic_t"
34ce1c0824SLorenzo Stoakes  */
35ce1c0824SLorenzo Stoakes static volatile sig_atomic_t signal_jump_set;
36ce1c0824SLorenzo Stoakes static sigjmp_buf signal_jmp_buf;
37ce1c0824SLorenzo Stoakes 
38ce1c0824SLorenzo Stoakes /*
39ce1c0824SLorenzo Stoakes  * Ignore the checkpatch warning, we must read from x but don't want to do
40ce1c0824SLorenzo Stoakes  * anything with it in order to trigger a read page fault. We therefore must use
41ce1c0824SLorenzo Stoakes  * volatile to stop the compiler from optimising this away.
42ce1c0824SLorenzo Stoakes  */
43ce1c0824SLorenzo Stoakes #define FORCE_READ(x) (*(volatile typeof(x) *)x)
44272f37d3SLorenzo Stoakes 
45272f37d3SLorenzo Stoakes /*
46272f37d3SLorenzo Stoakes  * How is the test backing the mapping being tested?
47272f37d3SLorenzo Stoakes  */
48272f37d3SLorenzo Stoakes enum backing_type {
49272f37d3SLorenzo Stoakes 	ANON_BACKED,
50272f37d3SLorenzo Stoakes 	SHMEM_BACKED,
51272f37d3SLorenzo Stoakes 	LOCAL_FILE_BACKED,
52272f37d3SLorenzo Stoakes };
53272f37d3SLorenzo Stoakes 
FIXTURE(guard_regions)54272f37d3SLorenzo Stoakes FIXTURE(guard_regions)
55272f37d3SLorenzo Stoakes {
56272f37d3SLorenzo Stoakes 	unsigned long page_size;
57272f37d3SLorenzo Stoakes 	char path[PATH_MAX];
58272f37d3SLorenzo Stoakes 	int fd;
59272f37d3SLorenzo Stoakes };
60272f37d3SLorenzo Stoakes 
FIXTURE_VARIANT(guard_regions)61272f37d3SLorenzo Stoakes FIXTURE_VARIANT(guard_regions)
62272f37d3SLorenzo Stoakes {
63272f37d3SLorenzo Stoakes 	enum backing_type backing;
64272f37d3SLorenzo Stoakes };
65272f37d3SLorenzo Stoakes 
FIXTURE_VARIANT_ADD(guard_regions,anon)66272f37d3SLorenzo Stoakes FIXTURE_VARIANT_ADD(guard_regions, anon)
67272f37d3SLorenzo Stoakes {
68272f37d3SLorenzo Stoakes 	.backing = ANON_BACKED,
69272f37d3SLorenzo Stoakes };
70272f37d3SLorenzo Stoakes 
FIXTURE_VARIANT_ADD(guard_regions,shmem)71272f37d3SLorenzo Stoakes FIXTURE_VARIANT_ADD(guard_regions, shmem)
72272f37d3SLorenzo Stoakes {
73272f37d3SLorenzo Stoakes 	.backing = SHMEM_BACKED,
74272f37d3SLorenzo Stoakes };
75272f37d3SLorenzo Stoakes 
FIXTURE_VARIANT_ADD(guard_regions,file)76272f37d3SLorenzo Stoakes FIXTURE_VARIANT_ADD(guard_regions, file)
77272f37d3SLorenzo Stoakes {
78272f37d3SLorenzo Stoakes 	.backing = LOCAL_FILE_BACKED,
79272f37d3SLorenzo Stoakes };
80272f37d3SLorenzo Stoakes 
is_anon_backed(const FIXTURE_VARIANT (guard_regions)* variant)81272f37d3SLorenzo Stoakes static bool is_anon_backed(const FIXTURE_VARIANT(guard_regions) * variant)
82272f37d3SLorenzo Stoakes {
83272f37d3SLorenzo Stoakes 	switch (variant->backing) {
84272f37d3SLorenzo Stoakes 	case  ANON_BACKED:
85272f37d3SLorenzo Stoakes 	case  SHMEM_BACKED:
86272f37d3SLorenzo Stoakes 		return true;
87272f37d3SLorenzo Stoakes 	default:
88272f37d3SLorenzo Stoakes 		return false;
89272f37d3SLorenzo Stoakes 	}
90272f37d3SLorenzo Stoakes }
91272f37d3SLorenzo Stoakes 
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)92272f37d3SLorenzo Stoakes static void *mmap_(FIXTURE_DATA(guard_regions) * self,
93272f37d3SLorenzo Stoakes 		   const FIXTURE_VARIANT(guard_regions) * variant,
94272f37d3SLorenzo Stoakes 		   void *addr, size_t length, int prot, int extra_flags,
95272f37d3SLorenzo Stoakes 		   off_t offset)
96272f37d3SLorenzo Stoakes {
97272f37d3SLorenzo Stoakes 	int fd;
98272f37d3SLorenzo Stoakes 	int flags = extra_flags;
99272f37d3SLorenzo Stoakes 
100272f37d3SLorenzo Stoakes 	switch (variant->backing) {
101272f37d3SLorenzo Stoakes 	case ANON_BACKED:
102272f37d3SLorenzo Stoakes 		flags |= MAP_PRIVATE | MAP_ANON;
103272f37d3SLorenzo Stoakes 		fd = -1;
104272f37d3SLorenzo Stoakes 		break;
105272f37d3SLorenzo Stoakes 	case SHMEM_BACKED:
106272f37d3SLorenzo Stoakes 	case LOCAL_FILE_BACKED:
107272f37d3SLorenzo Stoakes 		flags |= MAP_SHARED;
108272f37d3SLorenzo Stoakes 		fd = self->fd;
109272f37d3SLorenzo Stoakes 		break;
110272f37d3SLorenzo Stoakes 	default:
111272f37d3SLorenzo Stoakes 		ksft_exit_fail();
112272f37d3SLorenzo Stoakes 		break;
113272f37d3SLorenzo Stoakes 	}
114272f37d3SLorenzo Stoakes 
115272f37d3SLorenzo Stoakes 	return mmap(addr, length, prot, flags, fd, offset);
116272f37d3SLorenzo Stoakes }
117ce1c0824SLorenzo Stoakes 
userfaultfd(int flags)118ce1c0824SLorenzo Stoakes static int userfaultfd(int flags)
119ce1c0824SLorenzo Stoakes {
120ce1c0824SLorenzo Stoakes 	return syscall(SYS_userfaultfd, flags);
121ce1c0824SLorenzo Stoakes }
122ce1c0824SLorenzo Stoakes 
handle_fatal(int c)123ce1c0824SLorenzo Stoakes static void handle_fatal(int c)
124ce1c0824SLorenzo Stoakes {
125ce1c0824SLorenzo Stoakes 	if (!signal_jump_set)
126ce1c0824SLorenzo Stoakes 		return;
127ce1c0824SLorenzo Stoakes 
128ce1c0824SLorenzo Stoakes 	siglongjmp(signal_jmp_buf, c);
129ce1c0824SLorenzo Stoakes }
130ce1c0824SLorenzo Stoakes 
sys_process_madvise(int pidfd,const struct iovec * iovec,size_t n,int advice,unsigned int flags)131ce1c0824SLorenzo Stoakes static ssize_t sys_process_madvise(int pidfd, const struct iovec *iovec,
132ce1c0824SLorenzo Stoakes 				   size_t n, int advice, unsigned int flags)
133ce1c0824SLorenzo Stoakes {
134ce1c0824SLorenzo Stoakes 	return syscall(__NR_process_madvise, pidfd, iovec, n, advice, flags);
135ce1c0824SLorenzo Stoakes }
136ce1c0824SLorenzo Stoakes 
137ce1c0824SLorenzo Stoakes /*
138ce1c0824SLorenzo Stoakes  * Enable our signal catcher and try to read/write the specified buffer. The
139ce1c0824SLorenzo Stoakes  * return value indicates whether the read/write succeeds without a fatal
140ce1c0824SLorenzo Stoakes  * signal.
141ce1c0824SLorenzo Stoakes  */
try_access_buf(char * ptr,bool write)142ce1c0824SLorenzo Stoakes static bool try_access_buf(char *ptr, bool write)
143ce1c0824SLorenzo Stoakes {
144ce1c0824SLorenzo Stoakes 	bool failed;
145ce1c0824SLorenzo Stoakes 
146ce1c0824SLorenzo Stoakes 	/* Tell signal handler to jump back here on fatal signal. */
147ce1c0824SLorenzo Stoakes 	signal_jump_set = true;
148ce1c0824SLorenzo Stoakes 	/* If a fatal signal arose, we will jump back here and failed is set. */
149ce1c0824SLorenzo Stoakes 	failed = sigsetjmp(signal_jmp_buf, 0) != 0;
150ce1c0824SLorenzo Stoakes 
151ce1c0824SLorenzo Stoakes 	if (!failed) {
152ce1c0824SLorenzo Stoakes 		if (write)
153ce1c0824SLorenzo Stoakes 			*ptr = 'x';
154ce1c0824SLorenzo Stoakes 		else
155ce1c0824SLorenzo Stoakes 			FORCE_READ(ptr);
156ce1c0824SLorenzo Stoakes 	}
157ce1c0824SLorenzo Stoakes 
158ce1c0824SLorenzo Stoakes 	signal_jump_set = false;
159ce1c0824SLorenzo Stoakes 	return !failed;
160ce1c0824SLorenzo Stoakes }
161ce1c0824SLorenzo Stoakes 
162ce1c0824SLorenzo Stoakes /* Try and read from a buffer, return true if no fatal signal. */
try_read_buf(char * ptr)163ce1c0824SLorenzo Stoakes static bool try_read_buf(char *ptr)
164ce1c0824SLorenzo Stoakes {
165ce1c0824SLorenzo Stoakes 	return try_access_buf(ptr, false);
166ce1c0824SLorenzo Stoakes }
167ce1c0824SLorenzo Stoakes 
168ce1c0824SLorenzo Stoakes /* Try and write to a buffer, return true if no fatal signal. */
try_write_buf(char * ptr)169ce1c0824SLorenzo Stoakes static bool try_write_buf(char *ptr)
170ce1c0824SLorenzo Stoakes {
171ce1c0824SLorenzo Stoakes 	return try_access_buf(ptr, true);
172ce1c0824SLorenzo Stoakes }
173ce1c0824SLorenzo Stoakes 
174ce1c0824SLorenzo Stoakes /*
175ce1c0824SLorenzo Stoakes  * Try and BOTH read from AND write to a buffer, return true if BOTH operations
176ce1c0824SLorenzo Stoakes  * succeed.
177ce1c0824SLorenzo Stoakes  */
try_read_write_buf(char * ptr)178ce1c0824SLorenzo Stoakes static bool try_read_write_buf(char *ptr)
179ce1c0824SLorenzo Stoakes {
180ce1c0824SLorenzo Stoakes 	return try_read_buf(ptr) && try_write_buf(ptr);
181ce1c0824SLorenzo Stoakes }
182272f37d3SLorenzo Stoakes 
setup_sighandler(void)183ce1c0824SLorenzo Stoakes static void setup_sighandler(void)
184ce1c0824SLorenzo Stoakes {
185ce1c0824SLorenzo Stoakes 	struct sigaction act = {
186ce1c0824SLorenzo Stoakes 		.sa_handler = &handle_fatal,
187ce1c0824SLorenzo Stoakes 		.sa_flags = SA_NODEFER,
188ce1c0824SLorenzo Stoakes 	};
189ce1c0824SLorenzo Stoakes 
190ce1c0824SLorenzo Stoakes 	sigemptyset(&act.sa_mask);
191ce1c0824SLorenzo Stoakes 	if (sigaction(SIGSEGV, &act, NULL))
192272f37d3SLorenzo Stoakes 		ksft_exit_fail_perror("sigaction");
193ce1c0824SLorenzo Stoakes }
194272f37d3SLorenzo Stoakes 
teardown_sighandler(void)195ce1c0824SLorenzo Stoakes static void teardown_sighandler(void)
196ce1c0824SLorenzo Stoakes {
197ce1c0824SLorenzo Stoakes 	struct sigaction act = {
198ce1c0824SLorenzo Stoakes 		.sa_handler = SIG_DFL,
199ce1c0824SLorenzo Stoakes 		.sa_flags = SA_NODEFER,
200ce1c0824SLorenzo Stoakes 	};
201ce1c0824SLorenzo Stoakes 
202ce1c0824SLorenzo Stoakes 	sigemptyset(&act.sa_mask);
203ce1c0824SLorenzo Stoakes 	sigaction(SIGSEGV, &act, NULL);
204ce1c0824SLorenzo Stoakes }
205272f37d3SLorenzo Stoakes 
open_file(const char * prefix,char * path)206272f37d3SLorenzo Stoakes static int open_file(const char *prefix, char *path)
207272f37d3SLorenzo Stoakes {
208272f37d3SLorenzo Stoakes 	int fd;
209272f37d3SLorenzo Stoakes 
210272f37d3SLorenzo Stoakes 	snprintf(path, PATH_MAX, "%sguard_regions_test_file_XXXXXX", prefix);
211272f37d3SLorenzo Stoakes 	fd = mkstemp(path);
212272f37d3SLorenzo Stoakes 	if (fd < 0)
213272f37d3SLorenzo Stoakes 		ksft_exit_fail_perror("mkstemp");
214272f37d3SLorenzo Stoakes 
215272f37d3SLorenzo Stoakes 	return fd;
216272f37d3SLorenzo Stoakes }
2170b6d4853SLorenzo Stoakes 
2180b6d4853SLorenzo Stoakes /* Establish a varying pattern in a buffer. */
set_pattern(char * ptr,size_t num_pages,size_t page_size)2190b6d4853SLorenzo Stoakes static void set_pattern(char *ptr, size_t num_pages, size_t page_size)
2200b6d4853SLorenzo Stoakes {
2210b6d4853SLorenzo Stoakes 	size_t i;
2220b6d4853SLorenzo Stoakes 
2230b6d4853SLorenzo Stoakes 	for (i = 0; i < num_pages; i++) {
2240b6d4853SLorenzo Stoakes 		char *ptr2 = &ptr[i * page_size];
2250b6d4853SLorenzo Stoakes 
2260b6d4853SLorenzo Stoakes 		memset(ptr2, 'a' + (i % 26), page_size);
2270b6d4853SLorenzo Stoakes 	}
2280b6d4853SLorenzo Stoakes }
2290b6d4853SLorenzo Stoakes 
2300b6d4853SLorenzo Stoakes /*
2310b6d4853SLorenzo Stoakes  * Check that a buffer contains the pattern set by set_pattern(), starting at a
2320b6d4853SLorenzo Stoakes  * page offset of pgoff within the buffer.
2330b6d4853SLorenzo Stoakes  */
check_pattern_offset(char * ptr,size_t num_pages,size_t page_size,size_t pgoff)2340b6d4853SLorenzo Stoakes static bool check_pattern_offset(char *ptr, size_t num_pages, size_t page_size,
2350b6d4853SLorenzo Stoakes 				 size_t pgoff)
2360b6d4853SLorenzo Stoakes {
2370b6d4853SLorenzo Stoakes 	size_t i;
2380b6d4853SLorenzo Stoakes 
2390b6d4853SLorenzo Stoakes 	for (i = 0; i < num_pages * page_size; i++) {
2400b6d4853SLorenzo Stoakes 		size_t offset = pgoff * page_size + i;
2410b6d4853SLorenzo Stoakes 		char actual = ptr[offset];
2420b6d4853SLorenzo Stoakes 		char expected = 'a' + ((offset / page_size) % 26);
2430b6d4853SLorenzo Stoakes 
2440b6d4853SLorenzo Stoakes 		if (actual != expected)
2450b6d4853SLorenzo Stoakes 			return false;
2460b6d4853SLorenzo Stoakes 	}
2470b6d4853SLorenzo Stoakes 
2480b6d4853SLorenzo Stoakes 	return true;
2490b6d4853SLorenzo Stoakes }
2500b6d4853SLorenzo Stoakes 
2510b6d4853SLorenzo Stoakes /* Check that a buffer contains the pattern set by set_pattern(). */
check_pattern(char * ptr,size_t num_pages,size_t page_size)2520b6d4853SLorenzo Stoakes static bool check_pattern(char *ptr, size_t num_pages, size_t page_size)
2530b6d4853SLorenzo Stoakes {
2540b6d4853SLorenzo Stoakes 	return check_pattern_offset(ptr, num_pages, page_size, 0);
2550b6d4853SLorenzo Stoakes }
2560b6d4853SLorenzo Stoakes 
2570b6d4853SLorenzo Stoakes /* Determine if a buffer contains only repetitions of a specified char. */
is_buf_eq(char * buf,size_t size,char chr)2580b6d4853SLorenzo Stoakes static bool is_buf_eq(char *buf, size_t size, char chr)
2590b6d4853SLorenzo Stoakes {
2600b6d4853SLorenzo Stoakes 	size_t i;
2610b6d4853SLorenzo Stoakes 
2620b6d4853SLorenzo Stoakes 	for (i = 0; i < size; i++) {
2630b6d4853SLorenzo Stoakes 		if (buf[i] != chr)
2640b6d4853SLorenzo Stoakes 			return false;
2650b6d4853SLorenzo Stoakes 	}
2660b6d4853SLorenzo Stoakes 
2670b6d4853SLorenzo Stoakes 	return true;
2680b6d4853SLorenzo Stoakes }
269272f37d3SLorenzo Stoakes 
FIXTURE_SETUP(guard_regions)270272f37d3SLorenzo Stoakes FIXTURE_SETUP(guard_regions)
271272f37d3SLorenzo Stoakes {
272272f37d3SLorenzo Stoakes 	self->page_size = (unsigned long)sysconf(_SC_PAGESIZE);
273272f37d3SLorenzo Stoakes 	setup_sighandler();
274*a8efaddaSLorenzo Stoakes 
275*a8efaddaSLorenzo Stoakes 	switch (variant->backing) {
276272f37d3SLorenzo Stoakes 	case ANON_BACKED:
277*a8efaddaSLorenzo Stoakes 		return;
278*a8efaddaSLorenzo Stoakes 	case LOCAL_FILE_BACKED:
279*a8efaddaSLorenzo Stoakes 		self->fd = open_file("", self->path);
280*a8efaddaSLorenzo Stoakes 		break;
281*a8efaddaSLorenzo Stoakes 	case SHMEM_BACKED:
282*a8efaddaSLorenzo Stoakes 		self->fd = memfd_create(self->path, 0);
283*a8efaddaSLorenzo Stoakes 		break;
284272f37d3SLorenzo Stoakes 	}
285272f37d3SLorenzo Stoakes 
286272f37d3SLorenzo Stoakes 	/* We truncate file to at least 100 pages, tests can modify as needed. */
287272f37d3SLorenzo Stoakes 	ASSERT_EQ(ftruncate(self->fd, 100 * self->page_size), 0);
288272f37d3SLorenzo Stoakes };
289272f37d3SLorenzo Stoakes 
FIXTURE_TEARDOWN_PARENT(guard_regions)290272f37d3SLorenzo Stoakes FIXTURE_TEARDOWN_PARENT(guard_regions)
291272f37d3SLorenzo Stoakes {
292272f37d3SLorenzo Stoakes 	teardown_sighandler();
293272f37d3SLorenzo Stoakes 
294272f37d3SLorenzo Stoakes 	if (variant->backing == ANON_BACKED)
295272f37d3SLorenzo Stoakes 		return;
296272f37d3SLorenzo Stoakes 
297272f37d3SLorenzo Stoakes 	if (self->fd >= 0)
298272f37d3SLorenzo Stoakes 		close(self->fd);
299272f37d3SLorenzo Stoakes 
300272f37d3SLorenzo Stoakes 	if (self->path[0] != '\0')
301272f37d3SLorenzo Stoakes 		unlink(self->path);
302272f37d3SLorenzo Stoakes }
303ce1c0824SLorenzo Stoakes 
TEST_F(guard_regions,basic)304ce1c0824SLorenzo Stoakes TEST_F(guard_regions, basic)
305ce1c0824SLorenzo Stoakes {
306ce1c0824SLorenzo Stoakes 	const unsigned long NUM_PAGES = 10;
307ce1c0824SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
308ce1c0824SLorenzo Stoakes 	char *ptr;
309ce1c0824SLorenzo Stoakes 	int i;
310272f37d3SLorenzo Stoakes 
311272f37d3SLorenzo Stoakes 	ptr = mmap_(self, variant, NULL, NUM_PAGES * page_size,
312ce1c0824SLorenzo Stoakes 		    PROT_READ | PROT_WRITE, 0, 0);
313ce1c0824SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
314ce1c0824SLorenzo Stoakes 
315ce1c0824SLorenzo Stoakes 	/* Trivially assert we can touch the first page. */
316ce1c0824SLorenzo Stoakes 	ASSERT_TRUE(try_read_write_buf(ptr));
317ce1c0824SLorenzo Stoakes 
318ce1c0824SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, page_size, MADV_GUARD_INSTALL), 0);
319ce1c0824SLorenzo Stoakes 
320ce1c0824SLorenzo Stoakes 	/* Establish that 1st page SIGSEGV's. */
321ce1c0824SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(ptr));
322ce1c0824SLorenzo Stoakes 
323ce1c0824SLorenzo Stoakes 	/* Ensure we can touch everything else.*/
324ce1c0824SLorenzo Stoakes 	for (i = 1; i < NUM_PAGES; i++) {
325ce1c0824SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
326ce1c0824SLorenzo Stoakes 
327ce1c0824SLorenzo Stoakes 		ASSERT_TRUE(try_read_write_buf(curr));
328ce1c0824SLorenzo Stoakes 	}
329ce1c0824SLorenzo Stoakes 
330ce1c0824SLorenzo Stoakes 	/* Establish a guard page at the end of the mapping. */
331ce1c0824SLorenzo Stoakes 	ASSERT_EQ(madvise(&ptr[(NUM_PAGES - 1) * page_size], page_size,
332ce1c0824SLorenzo Stoakes 			  MADV_GUARD_INSTALL), 0);
333ce1c0824SLorenzo Stoakes 
334ce1c0824SLorenzo Stoakes 	/* Check that both guard pages result in SIGSEGV. */
335ce1c0824SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(ptr));
336ce1c0824SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(&ptr[(NUM_PAGES - 1) * page_size]));
337ce1c0824SLorenzo Stoakes 
338ce1c0824SLorenzo Stoakes 	/* Remove the first guard page. */
339ce1c0824SLorenzo Stoakes 	ASSERT_FALSE(madvise(ptr, page_size, MADV_GUARD_REMOVE));
340ce1c0824SLorenzo Stoakes 
341ce1c0824SLorenzo Stoakes 	/* Make sure we can touch it. */
342ce1c0824SLorenzo Stoakes 	ASSERT_TRUE(try_read_write_buf(ptr));
343ce1c0824SLorenzo Stoakes 
344ce1c0824SLorenzo Stoakes 	/* Remove the last guard page. */
345ce1c0824SLorenzo Stoakes 	ASSERT_FALSE(madvise(&ptr[(NUM_PAGES - 1) * page_size], page_size,
346ce1c0824SLorenzo Stoakes 			     MADV_GUARD_REMOVE));
347ce1c0824SLorenzo Stoakes 
348ce1c0824SLorenzo Stoakes 	/* Make sure we can touch it. */
349ce1c0824SLorenzo Stoakes 	ASSERT_TRUE(try_read_write_buf(&ptr[(NUM_PAGES - 1) * page_size]));
350ce1c0824SLorenzo Stoakes 
351ce1c0824SLorenzo Stoakes 	/*
352ce1c0824SLorenzo Stoakes 	 *  Test setting a _range_ of pages, namely the first 3. The first of
353ce1c0824SLorenzo Stoakes 	 *  these be faulted in, so this also tests that we can install guard
354ce1c0824SLorenzo Stoakes 	 *  pages over backed pages.
355ce1c0824SLorenzo Stoakes 	 */
356ce1c0824SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 3 * page_size, MADV_GUARD_INSTALL), 0);
357ce1c0824SLorenzo Stoakes 
358ce1c0824SLorenzo Stoakes 	/* Make sure they are all guard pages. */
359ce1c0824SLorenzo Stoakes 	for (i = 0; i < 3; i++) {
360ce1c0824SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
361ce1c0824SLorenzo Stoakes 
362ce1c0824SLorenzo Stoakes 		ASSERT_FALSE(try_read_write_buf(curr));
363ce1c0824SLorenzo Stoakes 	}
364ce1c0824SLorenzo Stoakes 
365ce1c0824SLorenzo Stoakes 	/* Make sure the rest are not. */
366ce1c0824SLorenzo Stoakes 	for (i = 3; i < NUM_PAGES; i++) {
367ce1c0824SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
368ce1c0824SLorenzo Stoakes 
369ce1c0824SLorenzo Stoakes 		ASSERT_TRUE(try_read_write_buf(curr));
370ce1c0824SLorenzo Stoakes 	}
371ce1c0824SLorenzo Stoakes 
372ce1c0824SLorenzo Stoakes 	/* Remove guard pages. */
373ce1c0824SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, NUM_PAGES * page_size, MADV_GUARD_REMOVE), 0);
374ce1c0824SLorenzo Stoakes 
375ce1c0824SLorenzo Stoakes 	/* Now make sure we can touch everything. */
376ce1c0824SLorenzo Stoakes 	for (i = 0; i < NUM_PAGES; i++) {
377ce1c0824SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
378ce1c0824SLorenzo Stoakes 
379ce1c0824SLorenzo Stoakes 		ASSERT_TRUE(try_read_write_buf(curr));
380ce1c0824SLorenzo Stoakes 	}
381ce1c0824SLorenzo Stoakes 
382ce1c0824SLorenzo Stoakes 	/*
383ce1c0824SLorenzo Stoakes 	 * Now remove all guard pages, make sure we don't remove existing
384ce1c0824SLorenzo Stoakes 	 * entries.
385ce1c0824SLorenzo Stoakes 	 */
386ce1c0824SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, NUM_PAGES * page_size, MADV_GUARD_REMOVE), 0);
387ce1c0824SLorenzo Stoakes 
388ce1c0824SLorenzo Stoakes 	for (i = 0; i < NUM_PAGES * page_size; i += page_size) {
389ce1c0824SLorenzo Stoakes 		char chr = ptr[i];
390ce1c0824SLorenzo Stoakes 
391ce1c0824SLorenzo Stoakes 		ASSERT_EQ(chr, 'x');
392ce1c0824SLorenzo Stoakes 	}
393ce1c0824SLorenzo Stoakes 
394ce1c0824SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr, NUM_PAGES * page_size), 0);
395ce1c0824SLorenzo Stoakes }
396ce1c0824SLorenzo Stoakes 
397ce1c0824SLorenzo Stoakes /* Assert that operations applied across multiple VMAs work as expected. */
TEST_F(guard_regions,multi_vma)398ce1c0824SLorenzo Stoakes TEST_F(guard_regions, multi_vma)
399ce1c0824SLorenzo Stoakes {
400ce1c0824SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
401ce1c0824SLorenzo Stoakes 	char *ptr_region, *ptr, *ptr1, *ptr2, *ptr3;
402ce1c0824SLorenzo Stoakes 	int i;
403ce1c0824SLorenzo Stoakes 
404272f37d3SLorenzo Stoakes 	/* Reserve a 100 page region over which we can install VMAs. */
405272f37d3SLorenzo Stoakes 	ptr_region = mmap_(self, variant, NULL, 100 * page_size,
406ce1c0824SLorenzo Stoakes 			   PROT_NONE, 0, 0);
407ce1c0824SLorenzo Stoakes 	ASSERT_NE(ptr_region, MAP_FAILED);
408ce1c0824SLorenzo Stoakes 
409272f37d3SLorenzo Stoakes 	/* Place a VMA of 10 pages size at the start of the region. */
410272f37d3SLorenzo Stoakes 	ptr1 = mmap_(self, variant, ptr_region, 10 * page_size,
411ce1c0824SLorenzo Stoakes 		     PROT_READ | PROT_WRITE, MAP_FIXED, 0);
412ce1c0824SLorenzo Stoakes 	ASSERT_NE(ptr1, MAP_FAILED);
413ce1c0824SLorenzo Stoakes 
414272f37d3SLorenzo Stoakes 	/* Place a VMA of 5 pages size 50 pages into the region. */
415272f37d3SLorenzo Stoakes 	ptr2 = mmap_(self, variant, &ptr_region[50 * page_size], 5 * page_size,
416ce1c0824SLorenzo Stoakes 		     PROT_READ | PROT_WRITE, MAP_FIXED, 0);
417ce1c0824SLorenzo Stoakes 	ASSERT_NE(ptr2, MAP_FAILED);
418ce1c0824SLorenzo Stoakes 
419272f37d3SLorenzo Stoakes 	/* Place a VMA of 20 pages size at the end of the region. */
420272f37d3SLorenzo Stoakes 	ptr3 = mmap_(self, variant, &ptr_region[80 * page_size], 20 * page_size,
421ce1c0824SLorenzo Stoakes 		     PROT_READ | PROT_WRITE, MAP_FIXED, 0);
422ce1c0824SLorenzo Stoakes 	ASSERT_NE(ptr3, MAP_FAILED);
423ce1c0824SLorenzo Stoakes 
424ce1c0824SLorenzo Stoakes 	/* Unmap gaps. */
425ce1c0824SLorenzo Stoakes 	ASSERT_EQ(munmap(&ptr_region[10 * page_size], 40 * page_size), 0);
426ce1c0824SLorenzo Stoakes 	ASSERT_EQ(munmap(&ptr_region[55 * page_size], 25 * page_size), 0);
427ce1c0824SLorenzo Stoakes 
428ce1c0824SLorenzo Stoakes 	/*
429ce1c0824SLorenzo Stoakes 	 * We end up with VMAs like this:
430ce1c0824SLorenzo Stoakes 	 *
431ce1c0824SLorenzo Stoakes 	 * 0    10 .. 50   55 .. 80   100
432ce1c0824SLorenzo Stoakes 	 * [---]      [---]      [---]
433ce1c0824SLorenzo Stoakes 	 */
434ce1c0824SLorenzo Stoakes 
435ce1c0824SLorenzo Stoakes 	/*
436ce1c0824SLorenzo Stoakes 	 * Now mark the whole range as guard pages and make sure all VMAs are as
437ce1c0824SLorenzo Stoakes 	 * such.
438ce1c0824SLorenzo Stoakes 	 */
439ce1c0824SLorenzo Stoakes 
440ce1c0824SLorenzo Stoakes 	/*
441ce1c0824SLorenzo Stoakes 	 * madvise() is certifiable and lets you perform operations over gaps,
442ce1c0824SLorenzo Stoakes 	 * everything works, but it indicates an error and errno is set to
443ce1c0824SLorenzo Stoakes 	 * -ENOMEM. Also if anything runs out of memory it is set to
444ce1c0824SLorenzo Stoakes 	 * -ENOMEM. You are meant to guess which is which.
445ce1c0824SLorenzo Stoakes 	 */
446ce1c0824SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr_region, 100 * page_size, MADV_GUARD_INSTALL), -1);
447ce1c0824SLorenzo Stoakes 	ASSERT_EQ(errno, ENOMEM);
448ce1c0824SLorenzo Stoakes 
449ce1c0824SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
450ce1c0824SLorenzo Stoakes 		char *curr = &ptr1[i * page_size];
451ce1c0824SLorenzo Stoakes 
452ce1c0824SLorenzo Stoakes 		ASSERT_FALSE(try_read_write_buf(curr));
453ce1c0824SLorenzo Stoakes 	}
454ce1c0824SLorenzo Stoakes 
455ce1c0824SLorenzo Stoakes 	for (i = 0; i < 5; i++) {
456ce1c0824SLorenzo Stoakes 		char *curr = &ptr2[i * page_size];
457ce1c0824SLorenzo Stoakes 
458ce1c0824SLorenzo Stoakes 		ASSERT_FALSE(try_read_write_buf(curr));
459ce1c0824SLorenzo Stoakes 	}
460ce1c0824SLorenzo Stoakes 
461ce1c0824SLorenzo Stoakes 	for (i = 0; i < 20; i++) {
462ce1c0824SLorenzo Stoakes 		char *curr = &ptr3[i * page_size];
463ce1c0824SLorenzo Stoakes 
464ce1c0824SLorenzo Stoakes 		ASSERT_FALSE(try_read_write_buf(curr));
465ce1c0824SLorenzo Stoakes 	}
466ce1c0824SLorenzo Stoakes 
467ce1c0824SLorenzo Stoakes 	/* Now remove guar pages over range and assert the opposite. */
468ce1c0824SLorenzo Stoakes 
469ce1c0824SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr_region, 100 * page_size, MADV_GUARD_REMOVE), -1);
470ce1c0824SLorenzo Stoakes 	ASSERT_EQ(errno, ENOMEM);
471ce1c0824SLorenzo Stoakes 
472ce1c0824SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
473ce1c0824SLorenzo Stoakes 		char *curr = &ptr1[i * page_size];
474ce1c0824SLorenzo Stoakes 
475ce1c0824SLorenzo Stoakes 		ASSERT_TRUE(try_read_write_buf(curr));
476ce1c0824SLorenzo Stoakes 	}
477ce1c0824SLorenzo Stoakes 
478ce1c0824SLorenzo Stoakes 	for (i = 0; i < 5; i++) {
479ce1c0824SLorenzo Stoakes 		char *curr = &ptr2[i * page_size];
480ce1c0824SLorenzo Stoakes 
481ce1c0824SLorenzo Stoakes 		ASSERT_TRUE(try_read_write_buf(curr));
482ce1c0824SLorenzo Stoakes 	}
483ce1c0824SLorenzo Stoakes 
484ce1c0824SLorenzo Stoakes 	for (i = 0; i < 20; i++) {
485ce1c0824SLorenzo Stoakes 		char *curr = &ptr3[i * page_size];
486ce1c0824SLorenzo Stoakes 
487ce1c0824SLorenzo Stoakes 		ASSERT_TRUE(try_read_write_buf(curr));
488ce1c0824SLorenzo Stoakes 	}
489ce1c0824SLorenzo Stoakes 
490272f37d3SLorenzo Stoakes 	/* Now map incompatible VMAs in the gaps. */
491272f37d3SLorenzo Stoakes 	ptr = mmap_(self, variant, &ptr_region[10 * page_size], 40 * page_size,
492ce1c0824SLorenzo Stoakes 		    PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED, 0);
493272f37d3SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
494272f37d3SLorenzo Stoakes 	ptr = mmap_(self, variant, &ptr_region[55 * page_size], 25 * page_size,
495ce1c0824SLorenzo Stoakes 		    PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED, 0);
496ce1c0824SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
497ce1c0824SLorenzo Stoakes 
498ce1c0824SLorenzo Stoakes 	/*
499ce1c0824SLorenzo Stoakes 	 * We end up with VMAs like this:
500ce1c0824SLorenzo Stoakes 	 *
501ce1c0824SLorenzo Stoakes 	 * 0    10 .. 50   55 .. 80   100
502ce1c0824SLorenzo Stoakes 	 * [---][xxxx][---][xxxx][---]
503ce1c0824SLorenzo Stoakes 	 *
504ce1c0824SLorenzo Stoakes 	 * Where 'x' signifies VMAs that cannot be merged with those adjacent to
505ce1c0824SLorenzo Stoakes 	 * them.
506ce1c0824SLorenzo Stoakes 	 */
507ce1c0824SLorenzo Stoakes 
508ce1c0824SLorenzo Stoakes 	/* Multiple VMAs adjacent to one another should result in no error. */
509ce1c0824SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr_region, 100 * page_size, MADV_GUARD_INSTALL), 0);
510ce1c0824SLorenzo Stoakes 	for (i = 0; i < 100; i++) {
511ce1c0824SLorenzo Stoakes 		char *curr = &ptr_region[i * page_size];
512ce1c0824SLorenzo Stoakes 
513ce1c0824SLorenzo Stoakes 		ASSERT_FALSE(try_read_write_buf(curr));
514ce1c0824SLorenzo Stoakes 	}
515ce1c0824SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr_region, 100 * page_size, MADV_GUARD_REMOVE), 0);
516ce1c0824SLorenzo Stoakes 	for (i = 0; i < 100; i++) {
517ce1c0824SLorenzo Stoakes 		char *curr = &ptr_region[i * page_size];
518ce1c0824SLorenzo Stoakes 
519ce1c0824SLorenzo Stoakes 		ASSERT_TRUE(try_read_write_buf(curr));
520ce1c0824SLorenzo Stoakes 	}
521ce1c0824SLorenzo Stoakes 
522ce1c0824SLorenzo Stoakes 	/* Cleanup. */
523ce1c0824SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr_region, 100 * page_size), 0);
524ce1c0824SLorenzo Stoakes }
525ce1c0824SLorenzo Stoakes 
526ce1c0824SLorenzo Stoakes /*
527ce1c0824SLorenzo Stoakes  * Assert that batched operations performed using process_madvise() work as
528ce1c0824SLorenzo Stoakes  * expected.
529ce1c0824SLorenzo Stoakes  */
TEST_F(guard_regions,process_madvise)530ce1c0824SLorenzo Stoakes TEST_F(guard_regions, process_madvise)
531ce1c0824SLorenzo Stoakes {
532ce1c0824SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
533ce1c0824SLorenzo Stoakes 	char *ptr_region, *ptr1, *ptr2, *ptr3;
534ce1c0824SLorenzo Stoakes 	ssize_t count;
535ce1c0824SLorenzo Stoakes 	struct iovec vec[6];
536ce1c0824SLorenzo Stoakes 
537272f37d3SLorenzo Stoakes 	/* Reserve region to map over. */
538272f37d3SLorenzo Stoakes 	ptr_region = mmap_(self, variant, NULL, 100 * page_size,
539ce1c0824SLorenzo Stoakes 			   PROT_NONE, 0, 0);
540ce1c0824SLorenzo Stoakes 	ASSERT_NE(ptr_region, MAP_FAILED);
541ce1c0824SLorenzo Stoakes 
542ce1c0824SLorenzo Stoakes 	/*
543ce1c0824SLorenzo Stoakes 	 * 10 pages offset 1 page into reserve region. We MAP_POPULATE so we
544ce1c0824SLorenzo Stoakes 	 * overwrite existing entries and test this code path against
545ce1c0824SLorenzo Stoakes 	 * overwriting existing entries.
546272f37d3SLorenzo Stoakes 	 */
547272f37d3SLorenzo Stoakes 	ptr1 = mmap_(self, variant, &ptr_region[page_size], 10 * page_size,
548ce1c0824SLorenzo Stoakes 		     PROT_READ | PROT_WRITE, MAP_FIXED | MAP_POPULATE, 0);
549ce1c0824SLorenzo Stoakes 	ASSERT_NE(ptr1, MAP_FAILED);
550ce1c0824SLorenzo Stoakes 	/* We want guard markers at start/end of each VMA. */
551ce1c0824SLorenzo Stoakes 	vec[0].iov_base = ptr1;
552ce1c0824SLorenzo Stoakes 	vec[0].iov_len = page_size;
553ce1c0824SLorenzo Stoakes 	vec[1].iov_base = &ptr1[9 * page_size];
554ce1c0824SLorenzo Stoakes 	vec[1].iov_len = page_size;
555ce1c0824SLorenzo Stoakes 
556272f37d3SLorenzo Stoakes 	/* 5 pages offset 50 pages into reserve region. */
557272f37d3SLorenzo Stoakes 	ptr2 = mmap_(self, variant, &ptr_region[50 * page_size], 5 * page_size,
558ce1c0824SLorenzo Stoakes 		     PROT_READ | PROT_WRITE, MAP_FIXED, 0);
559ce1c0824SLorenzo Stoakes 	ASSERT_NE(ptr2, MAP_FAILED);
560ce1c0824SLorenzo Stoakes 	vec[2].iov_base = ptr2;
561ce1c0824SLorenzo Stoakes 	vec[2].iov_len = page_size;
562ce1c0824SLorenzo Stoakes 	vec[3].iov_base = &ptr2[4 * page_size];
563ce1c0824SLorenzo Stoakes 	vec[3].iov_len = page_size;
564ce1c0824SLorenzo Stoakes 
565272f37d3SLorenzo Stoakes 	/* 20 pages offset 79 pages into reserve region. */
566272f37d3SLorenzo Stoakes 	ptr3 = mmap_(self, variant, &ptr_region[79 * page_size], 20 * page_size,
567ce1c0824SLorenzo Stoakes 		    PROT_READ | PROT_WRITE, MAP_FIXED, 0);
568ce1c0824SLorenzo Stoakes 	ASSERT_NE(ptr3, MAP_FAILED);
569ce1c0824SLorenzo Stoakes 	vec[4].iov_base = ptr3;
570ce1c0824SLorenzo Stoakes 	vec[4].iov_len = page_size;
571ce1c0824SLorenzo Stoakes 	vec[5].iov_base = &ptr3[19 * page_size];
572ce1c0824SLorenzo Stoakes 	vec[5].iov_len = page_size;
573ce1c0824SLorenzo Stoakes 
574ce1c0824SLorenzo Stoakes 	/* Free surrounding VMAs. */
575ce1c0824SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr_region, page_size), 0);
576ce1c0824SLorenzo Stoakes 	ASSERT_EQ(munmap(&ptr_region[11 * page_size], 39 * page_size), 0);
577ce1c0824SLorenzo Stoakes 	ASSERT_EQ(munmap(&ptr_region[55 * page_size], 24 * page_size), 0);
578ce1c0824SLorenzo Stoakes 	ASSERT_EQ(munmap(&ptr_region[99 * page_size], page_size), 0);
579ce1c0824SLorenzo Stoakes 
580eb0ece16SLinus Torvalds 	/* Now guard in one step. */
581ce1c0824SLorenzo Stoakes 	count = sys_process_madvise(PIDFD_SELF, vec, 6, MADV_GUARD_INSTALL, 0);
582ce1c0824SLorenzo Stoakes 
583ce1c0824SLorenzo Stoakes 	/* OK we don't have permission to do this, skip. */
584ce1c0824SLorenzo Stoakes 	if (count == -1 && errno == EPERM)
585ce1c0824SLorenzo Stoakes 		ksft_exit_skip("No process_madvise() permissions, try running as root.\n");
586ce1c0824SLorenzo Stoakes 
587ce1c0824SLorenzo Stoakes 	/* Returns the number of bytes advised. */
588ce1c0824SLorenzo Stoakes 	ASSERT_EQ(count, 6 * page_size);
589ce1c0824SLorenzo Stoakes 
590ce1c0824SLorenzo Stoakes 	/* Now make sure the guarding was applied. */
591ce1c0824SLorenzo Stoakes 
592ce1c0824SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(ptr1));
593ce1c0824SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(&ptr1[9 * page_size]));
594ce1c0824SLorenzo Stoakes 
595ce1c0824SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(ptr2));
596ce1c0824SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(&ptr2[4 * page_size]));
597ce1c0824SLorenzo Stoakes 
598ce1c0824SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(ptr3));
599ce1c0824SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(&ptr3[19 * page_size]));
600ce1c0824SLorenzo Stoakes 
601eb0ece16SLinus Torvalds 	/* Now do the same with unguard... */
602ce1c0824SLorenzo Stoakes 	count = sys_process_madvise(PIDFD_SELF, vec, 6, MADV_GUARD_REMOVE, 0);
603ce1c0824SLorenzo Stoakes 
604ce1c0824SLorenzo Stoakes 	/* ...and everything should now succeed. */
605ce1c0824SLorenzo Stoakes 
606ce1c0824SLorenzo Stoakes 	ASSERT_TRUE(try_read_write_buf(ptr1));
607ce1c0824SLorenzo Stoakes 	ASSERT_TRUE(try_read_write_buf(&ptr1[9 * page_size]));
608ce1c0824SLorenzo Stoakes 
609ce1c0824SLorenzo Stoakes 	ASSERT_TRUE(try_read_write_buf(ptr2));
610ce1c0824SLorenzo Stoakes 	ASSERT_TRUE(try_read_write_buf(&ptr2[4 * page_size]));
611ce1c0824SLorenzo Stoakes 
612ce1c0824SLorenzo Stoakes 	ASSERT_TRUE(try_read_write_buf(ptr3));
613ce1c0824SLorenzo Stoakes 	ASSERT_TRUE(try_read_write_buf(&ptr3[19 * page_size]));
614ce1c0824SLorenzo Stoakes 
615ce1c0824SLorenzo Stoakes 	/* Cleanup. */
616ce1c0824SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr1, 10 * page_size), 0);
617ce1c0824SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr2, 5 * page_size), 0);
618ce1c0824SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr3, 20 * page_size), 0);
619ce1c0824SLorenzo Stoakes }
620ce1c0824SLorenzo Stoakes 
621ce1c0824SLorenzo Stoakes /* Assert that unmapping ranges does not leave guard markers behind. */
TEST_F(guard_regions,munmap)622ce1c0824SLorenzo Stoakes TEST_F(guard_regions, munmap)
623ce1c0824SLorenzo Stoakes {
624ce1c0824SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
625ce1c0824SLorenzo Stoakes 	char *ptr, *ptr_new1, *ptr_new2;
626272f37d3SLorenzo Stoakes 
627272f37d3SLorenzo Stoakes 	ptr = mmap_(self, variant, NULL, 10 * page_size,
628ce1c0824SLorenzo Stoakes 		    PROT_READ | PROT_WRITE, 0, 0);
629ce1c0824SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
630ce1c0824SLorenzo Stoakes 
631ce1c0824SLorenzo Stoakes 	/* Guard first and last pages. */
632ce1c0824SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, page_size, MADV_GUARD_INSTALL), 0);
633ce1c0824SLorenzo Stoakes 	ASSERT_EQ(madvise(&ptr[9 * page_size], page_size, MADV_GUARD_INSTALL), 0);
634ce1c0824SLorenzo Stoakes 
635ce1c0824SLorenzo Stoakes 	/* Assert that they are guarded. */
636ce1c0824SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(ptr));
637ce1c0824SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(&ptr[9 * page_size]));
638ce1c0824SLorenzo Stoakes 
639ce1c0824SLorenzo Stoakes 	/* Unmap them. */
640ce1c0824SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr, page_size), 0);
641ce1c0824SLorenzo Stoakes 	ASSERT_EQ(munmap(&ptr[9 * page_size], page_size), 0);
642ce1c0824SLorenzo Stoakes 
643272f37d3SLorenzo Stoakes 	/* Map over them.*/
644272f37d3SLorenzo Stoakes 	ptr_new1 = mmap_(self, variant, ptr, page_size, PROT_READ | PROT_WRITE,
645ce1c0824SLorenzo Stoakes 			 MAP_FIXED, 0);
646272f37d3SLorenzo Stoakes 	ASSERT_NE(ptr_new1, MAP_FAILED);
647272f37d3SLorenzo Stoakes 	ptr_new2 = mmap_(self, variant, &ptr[9 * page_size], page_size,
648ce1c0824SLorenzo Stoakes 			 PROT_READ | PROT_WRITE, MAP_FIXED, 0);
649ce1c0824SLorenzo Stoakes 	ASSERT_NE(ptr_new2, MAP_FAILED);
650ce1c0824SLorenzo Stoakes 
651ce1c0824SLorenzo Stoakes 	/* Assert that they are now not guarded. */
652ce1c0824SLorenzo Stoakes 	ASSERT_TRUE(try_read_write_buf(ptr_new1));
653ce1c0824SLorenzo Stoakes 	ASSERT_TRUE(try_read_write_buf(ptr_new2));
654ce1c0824SLorenzo Stoakes 
655ce1c0824SLorenzo Stoakes 	/* Cleanup. */
656ce1c0824SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
657ce1c0824SLorenzo Stoakes }
658ce1c0824SLorenzo Stoakes 
659ce1c0824SLorenzo Stoakes /* Assert that mprotect() operations have no bearing on guard markers. */
TEST_F(guard_regions,mprotect)660ce1c0824SLorenzo Stoakes TEST_F(guard_regions, mprotect)
661ce1c0824SLorenzo Stoakes {
662ce1c0824SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
663ce1c0824SLorenzo Stoakes 	char *ptr;
664ce1c0824SLorenzo Stoakes 	int i;
665272f37d3SLorenzo Stoakes 
666272f37d3SLorenzo Stoakes 	ptr = mmap_(self, variant, NULL, 10 * page_size,
667ce1c0824SLorenzo Stoakes 		    PROT_READ | PROT_WRITE, 0, 0);
668ce1c0824SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
669ce1c0824SLorenzo Stoakes 
670ce1c0824SLorenzo Stoakes 	/* Guard the middle of the range. */
671ce1c0824SLorenzo Stoakes 	ASSERT_EQ(madvise(&ptr[5 * page_size], 2 * page_size,
672ce1c0824SLorenzo Stoakes 			  MADV_GUARD_INSTALL), 0);
673ce1c0824SLorenzo Stoakes 
674ce1c0824SLorenzo Stoakes 	/* Assert that it is indeed guarded. */
675ce1c0824SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(&ptr[5 * page_size]));
676ce1c0824SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(&ptr[6 * page_size]));
677ce1c0824SLorenzo Stoakes 
678ce1c0824SLorenzo Stoakes 	/* Now make these pages read-only. */
679ce1c0824SLorenzo Stoakes 	ASSERT_EQ(mprotect(&ptr[5 * page_size], 2 * page_size, PROT_READ), 0);
680ce1c0824SLorenzo Stoakes 
681ce1c0824SLorenzo Stoakes 	/* Make sure the range is still guarded. */
682ce1c0824SLorenzo Stoakes 	ASSERT_FALSE(try_read_buf(&ptr[5 * page_size]));
683ce1c0824SLorenzo Stoakes 	ASSERT_FALSE(try_read_buf(&ptr[6 * page_size]));
684ce1c0824SLorenzo Stoakes 
685ce1c0824SLorenzo Stoakes 	/* Make sure we can guard again without issue.*/
686ce1c0824SLorenzo Stoakes 	ASSERT_EQ(madvise(&ptr[5 * page_size], 2 * page_size,
687ce1c0824SLorenzo Stoakes 			  MADV_GUARD_INSTALL), 0);
688ce1c0824SLorenzo Stoakes 
689ce1c0824SLorenzo Stoakes 	/* Make sure the range is, yet again, still guarded. */
690ce1c0824SLorenzo Stoakes 	ASSERT_FALSE(try_read_buf(&ptr[5 * page_size]));
691ce1c0824SLorenzo Stoakes 	ASSERT_FALSE(try_read_buf(&ptr[6 * page_size]));
692ce1c0824SLorenzo Stoakes 
693ce1c0824SLorenzo Stoakes 	/* Now unguard the whole range. */
694ce1c0824SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_REMOVE), 0);
695ce1c0824SLorenzo Stoakes 
696ce1c0824SLorenzo Stoakes 	/* Make sure the whole range is readable. */
697ce1c0824SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
698ce1c0824SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
699ce1c0824SLorenzo Stoakes 
700ce1c0824SLorenzo Stoakes 		ASSERT_TRUE(try_read_buf(curr));
701ce1c0824SLorenzo Stoakes 	}
702ce1c0824SLorenzo Stoakes 
703ce1c0824SLorenzo Stoakes 	/* Cleanup. */
704ce1c0824SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
705ce1c0824SLorenzo Stoakes }
706ce1c0824SLorenzo Stoakes 
707ce1c0824SLorenzo Stoakes /* Split and merge VMAs and make sure guard pages still behave. */
TEST_F(guard_regions,split_merge)708ce1c0824SLorenzo Stoakes TEST_F(guard_regions, split_merge)
709ce1c0824SLorenzo Stoakes {
710ce1c0824SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
711ce1c0824SLorenzo Stoakes 	char *ptr, *ptr_new;
712ce1c0824SLorenzo Stoakes 	int i;
713272f37d3SLorenzo Stoakes 
714272f37d3SLorenzo Stoakes 	ptr = mmap_(self, variant, NULL, 10 * page_size,
715ce1c0824SLorenzo Stoakes 		    PROT_READ | PROT_WRITE, 0, 0);
716ce1c0824SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
717ce1c0824SLorenzo Stoakes 
718ce1c0824SLorenzo Stoakes 	/* Guard the whole range. */
719ce1c0824SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_INSTALL), 0);
720ce1c0824SLorenzo Stoakes 
721ce1c0824SLorenzo Stoakes 	/* Make sure the whole range is guarded. */
722ce1c0824SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
723ce1c0824SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
724ce1c0824SLorenzo Stoakes 
725ce1c0824SLorenzo Stoakes 		ASSERT_FALSE(try_read_write_buf(curr));
726ce1c0824SLorenzo Stoakes 	}
727ce1c0824SLorenzo Stoakes 
728ce1c0824SLorenzo Stoakes 	/* Now unmap some pages in the range so we split. */
729ce1c0824SLorenzo Stoakes 	ASSERT_EQ(munmap(&ptr[2 * page_size], page_size), 0);
730ce1c0824SLorenzo Stoakes 	ASSERT_EQ(munmap(&ptr[5 * page_size], page_size), 0);
731ce1c0824SLorenzo Stoakes 	ASSERT_EQ(munmap(&ptr[8 * page_size], page_size), 0);
732ce1c0824SLorenzo Stoakes 
733ce1c0824SLorenzo Stoakes 	/* Make sure the remaining ranges are guarded post-split. */
734ce1c0824SLorenzo Stoakes 	for (i = 0; i < 2; i++) {
735ce1c0824SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
736ce1c0824SLorenzo Stoakes 
737ce1c0824SLorenzo Stoakes 		ASSERT_FALSE(try_read_write_buf(curr));
738ce1c0824SLorenzo Stoakes 	}
739ce1c0824SLorenzo Stoakes 	for (i = 2; i < 5; i++) {
740ce1c0824SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
741ce1c0824SLorenzo Stoakes 
742ce1c0824SLorenzo Stoakes 		ASSERT_FALSE(try_read_write_buf(curr));
743ce1c0824SLorenzo Stoakes 	}
744ce1c0824SLorenzo Stoakes 	for (i = 6; i < 8; i++) {
745ce1c0824SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
746ce1c0824SLorenzo Stoakes 
747ce1c0824SLorenzo Stoakes 		ASSERT_FALSE(try_read_write_buf(curr));
748ce1c0824SLorenzo Stoakes 	}
749ce1c0824SLorenzo Stoakes 	for (i = 9; i < 10; i++) {
750ce1c0824SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
751ce1c0824SLorenzo Stoakes 
752ce1c0824SLorenzo Stoakes 		ASSERT_FALSE(try_read_write_buf(curr));
753ce1c0824SLorenzo Stoakes 	}
754ce1c0824SLorenzo Stoakes 
755272f37d3SLorenzo Stoakes 	/* Now map them again - the unmap will have cleared the guards. */
756272f37d3SLorenzo Stoakes 	ptr_new = mmap_(self, variant, &ptr[2 * page_size], page_size,
757ce1c0824SLorenzo Stoakes 			PROT_READ | PROT_WRITE, MAP_FIXED, 0);
758272f37d3SLorenzo Stoakes 	ASSERT_NE(ptr_new, MAP_FAILED);
759272f37d3SLorenzo Stoakes 	ptr_new = mmap_(self, variant, &ptr[5 * page_size], page_size,
760ce1c0824SLorenzo Stoakes 			PROT_READ | PROT_WRITE, MAP_FIXED, 0);
761272f37d3SLorenzo Stoakes 	ASSERT_NE(ptr_new, MAP_FAILED);
762272f37d3SLorenzo Stoakes 	ptr_new = mmap_(self, variant, &ptr[8 * page_size], page_size,
763ce1c0824SLorenzo Stoakes 			PROT_READ | PROT_WRITE, MAP_FIXED, 0);
764ce1c0824SLorenzo Stoakes 	ASSERT_NE(ptr_new, MAP_FAILED);
765ce1c0824SLorenzo Stoakes 
766ce1c0824SLorenzo Stoakes 	/* Now make sure guard pages are established. */
767ce1c0824SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
768ce1c0824SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
769ce1c0824SLorenzo Stoakes 		bool result = try_read_write_buf(curr);
770ce1c0824SLorenzo Stoakes 		bool expect_true = i == 2 || i == 5 || i == 8;
771ce1c0824SLorenzo Stoakes 
772ce1c0824SLorenzo Stoakes 		ASSERT_TRUE(expect_true ? result : !result);
773ce1c0824SLorenzo Stoakes 	}
774ce1c0824SLorenzo Stoakes 
775ce1c0824SLorenzo Stoakes 	/* Now guard everything again. */
776ce1c0824SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_INSTALL), 0);
777ce1c0824SLorenzo Stoakes 
778ce1c0824SLorenzo Stoakes 	/* Make sure the whole range is guarded. */
779ce1c0824SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
780ce1c0824SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
781ce1c0824SLorenzo Stoakes 
782ce1c0824SLorenzo Stoakes 		ASSERT_FALSE(try_read_write_buf(curr));
783ce1c0824SLorenzo Stoakes 	}
784ce1c0824SLorenzo Stoakes 
785ce1c0824SLorenzo Stoakes 	/* Now split the range into three. */
786ce1c0824SLorenzo Stoakes 	ASSERT_EQ(mprotect(ptr, 3 * page_size, PROT_READ), 0);
787ce1c0824SLorenzo Stoakes 	ASSERT_EQ(mprotect(&ptr[7 * page_size], 3 * page_size, PROT_READ), 0);
788ce1c0824SLorenzo Stoakes 
789ce1c0824SLorenzo Stoakes 	/* Make sure the whole range is guarded for read. */
790ce1c0824SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
791ce1c0824SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
792ce1c0824SLorenzo Stoakes 
793ce1c0824SLorenzo Stoakes 		ASSERT_FALSE(try_read_buf(curr));
794ce1c0824SLorenzo Stoakes 	}
795ce1c0824SLorenzo Stoakes 
796ce1c0824SLorenzo Stoakes 	/* Now reset protection bits so we merge the whole thing. */
797ce1c0824SLorenzo Stoakes 	ASSERT_EQ(mprotect(ptr, 3 * page_size, PROT_READ | PROT_WRITE), 0);
798ce1c0824SLorenzo Stoakes 	ASSERT_EQ(mprotect(&ptr[7 * page_size], 3 * page_size,
799ce1c0824SLorenzo Stoakes 			   PROT_READ | PROT_WRITE), 0);
800ce1c0824SLorenzo Stoakes 
801ce1c0824SLorenzo Stoakes 	/* Make sure the whole range is still guarded. */
802ce1c0824SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
803ce1c0824SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
804ce1c0824SLorenzo Stoakes 
805ce1c0824SLorenzo Stoakes 		ASSERT_FALSE(try_read_write_buf(curr));
806ce1c0824SLorenzo Stoakes 	}
807ce1c0824SLorenzo Stoakes 
808ce1c0824SLorenzo Stoakes 	/* Split range into 3 again... */
809ce1c0824SLorenzo Stoakes 	ASSERT_EQ(mprotect(ptr, 3 * page_size, PROT_READ), 0);
810ce1c0824SLorenzo Stoakes 	ASSERT_EQ(mprotect(&ptr[7 * page_size], 3 * page_size, PROT_READ), 0);
811ce1c0824SLorenzo Stoakes 
812ce1c0824SLorenzo Stoakes 	/* ...and unguard the whole range. */
813ce1c0824SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_REMOVE), 0);
814ce1c0824SLorenzo Stoakes 
815ce1c0824SLorenzo Stoakes 	/* Make sure the whole range is remedied for read. */
816ce1c0824SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
817ce1c0824SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
818ce1c0824SLorenzo Stoakes 
819ce1c0824SLorenzo Stoakes 		ASSERT_TRUE(try_read_buf(curr));
820ce1c0824SLorenzo Stoakes 	}
821ce1c0824SLorenzo Stoakes 
822ce1c0824SLorenzo Stoakes 	/* Merge them again. */
823ce1c0824SLorenzo Stoakes 	ASSERT_EQ(mprotect(ptr, 3 * page_size, PROT_READ | PROT_WRITE), 0);
824ce1c0824SLorenzo Stoakes 	ASSERT_EQ(mprotect(&ptr[7 * page_size], 3 * page_size,
825ce1c0824SLorenzo Stoakes 			   PROT_READ | PROT_WRITE), 0);
826ce1c0824SLorenzo Stoakes 
827ce1c0824SLorenzo Stoakes 	/* Now ensure the merged range is remedied for read/write. */
828ce1c0824SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
829ce1c0824SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
830ce1c0824SLorenzo Stoakes 
831ce1c0824SLorenzo Stoakes 		ASSERT_TRUE(try_read_write_buf(curr));
832ce1c0824SLorenzo Stoakes 	}
833ce1c0824SLorenzo Stoakes 
834ce1c0824SLorenzo Stoakes 	/* Cleanup. */
835ce1c0824SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
836ce1c0824SLorenzo Stoakes }
837ce1c0824SLorenzo Stoakes 
838ce1c0824SLorenzo Stoakes /* Assert that MADV_DONTNEED does not remove guard markers. */
TEST_F(guard_regions,dontneed)839ce1c0824SLorenzo Stoakes TEST_F(guard_regions, dontneed)
840ce1c0824SLorenzo Stoakes {
841ce1c0824SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
842ce1c0824SLorenzo Stoakes 	char *ptr;
843ce1c0824SLorenzo Stoakes 	int i;
844272f37d3SLorenzo Stoakes 
845272f37d3SLorenzo Stoakes 	ptr = mmap_(self, variant, NULL, 10 * page_size,
846ce1c0824SLorenzo Stoakes 		    PROT_READ | PROT_WRITE, 0, 0);
847ce1c0824SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
848ce1c0824SLorenzo Stoakes 
849ce1c0824SLorenzo Stoakes 	/* Back the whole range. */
850ce1c0824SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
851ce1c0824SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
852ce1c0824SLorenzo Stoakes 
853ce1c0824SLorenzo Stoakes 		*curr = 'y';
854ce1c0824SLorenzo Stoakes 	}
855ce1c0824SLorenzo Stoakes 
856ce1c0824SLorenzo Stoakes 	/* Guard every other page. */
857ce1c0824SLorenzo Stoakes 	for (i = 0; i < 10; i += 2) {
858ce1c0824SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
859ce1c0824SLorenzo Stoakes 		int res = madvise(curr, page_size, MADV_GUARD_INSTALL);
860ce1c0824SLorenzo Stoakes 
861ce1c0824SLorenzo Stoakes 		ASSERT_EQ(res, 0);
862ce1c0824SLorenzo Stoakes 	}
863ce1c0824SLorenzo Stoakes 
864ce1c0824SLorenzo Stoakes 	/* Indicate that we don't need any of the range. */
865ce1c0824SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_DONTNEED), 0);
866ce1c0824SLorenzo Stoakes 
867ce1c0824SLorenzo Stoakes 	/* Check to ensure guard markers are still in place. */
868ce1c0824SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
869ce1c0824SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
870ce1c0824SLorenzo Stoakes 		bool result = try_read_buf(curr);
871ce1c0824SLorenzo Stoakes 
872ce1c0824SLorenzo Stoakes 		if (i % 2 == 0) {
873ce1c0824SLorenzo Stoakes 			ASSERT_FALSE(result);
874ce1c0824SLorenzo Stoakes 		} else {
875272f37d3SLorenzo Stoakes 			ASSERT_TRUE(result);
876272f37d3SLorenzo Stoakes 			switch (variant->backing) {
877272f37d3SLorenzo Stoakes 			case ANON_BACKED:
878ce1c0824SLorenzo Stoakes 				/* If anon, then we get a zero page. */
879272f37d3SLorenzo Stoakes 				ASSERT_EQ(*curr, '\0');
880272f37d3SLorenzo Stoakes 				break;
881272f37d3SLorenzo Stoakes 			default:
882272f37d3SLorenzo Stoakes 				/* Otherwise, we get the file data. */
883272f37d3SLorenzo Stoakes 				ASSERT_EQ(*curr, 'y');
884272f37d3SLorenzo Stoakes 				break;
885ce1c0824SLorenzo Stoakes 			}
886ce1c0824SLorenzo Stoakes 		}
887ce1c0824SLorenzo Stoakes 
888ce1c0824SLorenzo Stoakes 		/* Now write... */
889ce1c0824SLorenzo Stoakes 		result = try_write_buf(&ptr[i * page_size]);
890ce1c0824SLorenzo Stoakes 
891ce1c0824SLorenzo Stoakes 		/* ...and make sure same result. */
892ce1c0824SLorenzo Stoakes 		ASSERT_TRUE(i % 2 != 0 ? result : !result);
893ce1c0824SLorenzo Stoakes 	}
894ce1c0824SLorenzo Stoakes 
895ce1c0824SLorenzo Stoakes 	/* Cleanup. */
896ce1c0824SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
897ce1c0824SLorenzo Stoakes }
898ce1c0824SLorenzo Stoakes 
899ce1c0824SLorenzo Stoakes /* Assert that mlock()'ed pages work correctly with guard markers. */
TEST_F(guard_regions,mlock)900ce1c0824SLorenzo Stoakes TEST_F(guard_regions, mlock)
901ce1c0824SLorenzo Stoakes {
902ce1c0824SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
903ce1c0824SLorenzo Stoakes 	char *ptr;
904ce1c0824SLorenzo Stoakes 	int i;
905272f37d3SLorenzo Stoakes 
906272f37d3SLorenzo Stoakes 	ptr = mmap_(self, variant, NULL, 10 * page_size,
907ce1c0824SLorenzo Stoakes 		    PROT_READ | PROT_WRITE, 0, 0);
908ce1c0824SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
909ce1c0824SLorenzo Stoakes 
910ce1c0824SLorenzo Stoakes 	/* Populate. */
911ce1c0824SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
912ce1c0824SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
913ce1c0824SLorenzo Stoakes 
914ce1c0824SLorenzo Stoakes 		*curr = 'y';
915ce1c0824SLorenzo Stoakes 	}
916ce1c0824SLorenzo Stoakes 
917ce1c0824SLorenzo Stoakes 	/* Lock. */
918ce1c0824SLorenzo Stoakes 	ASSERT_EQ(mlock(ptr, 10 * page_size), 0);
919ce1c0824SLorenzo Stoakes 
920ce1c0824SLorenzo Stoakes 	/* Now try to guard, should fail with EINVAL. */
921ce1c0824SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_INSTALL), -1);
922ce1c0824SLorenzo Stoakes 	ASSERT_EQ(errno, EINVAL);
923ce1c0824SLorenzo Stoakes 
924ce1c0824SLorenzo Stoakes 	/* OK unlock. */
925ce1c0824SLorenzo Stoakes 	ASSERT_EQ(munlock(ptr, 10 * page_size), 0);
926ce1c0824SLorenzo Stoakes 
927ce1c0824SLorenzo Stoakes 	/* Guard first half of range, should now succeed. */
928ce1c0824SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 5 * page_size, MADV_GUARD_INSTALL), 0);
929ce1c0824SLorenzo Stoakes 
930ce1c0824SLorenzo Stoakes 	/* Make sure guard works. */
931ce1c0824SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
932ce1c0824SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
933ce1c0824SLorenzo Stoakes 		bool result = try_read_write_buf(curr);
934ce1c0824SLorenzo Stoakes 
935ce1c0824SLorenzo Stoakes 		if (i < 5) {
936ce1c0824SLorenzo Stoakes 			ASSERT_FALSE(result);
937ce1c0824SLorenzo Stoakes 		} else {
938ce1c0824SLorenzo Stoakes 			ASSERT_TRUE(result);
939ce1c0824SLorenzo Stoakes 			ASSERT_EQ(*curr, 'x');
940ce1c0824SLorenzo Stoakes 		}
941ce1c0824SLorenzo Stoakes 	}
942ce1c0824SLorenzo Stoakes 
943ce1c0824SLorenzo Stoakes 	/*
944ce1c0824SLorenzo Stoakes 	 * Now lock the latter part of the range. We can't lock the guard pages,
945ce1c0824SLorenzo Stoakes 	 * as this would result in the pages being populated and the guarding
946ce1c0824SLorenzo Stoakes 	 * would cause this to error out.
947ce1c0824SLorenzo Stoakes 	 */
948ce1c0824SLorenzo Stoakes 	ASSERT_EQ(mlock(&ptr[5 * page_size], 5 * page_size), 0);
949ce1c0824SLorenzo Stoakes 
950ce1c0824SLorenzo Stoakes 	/*
951ce1c0824SLorenzo Stoakes 	 * Now remove guard pages, we permit mlock()'d ranges to have guard
952ce1c0824SLorenzo Stoakes 	 * pages removed as it is a non-destructive operation.
953ce1c0824SLorenzo Stoakes 	 */
954ce1c0824SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_REMOVE), 0);
955ce1c0824SLorenzo Stoakes 
956ce1c0824SLorenzo Stoakes 	/* Now check that no guard pages remain. */
957ce1c0824SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
958ce1c0824SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
959ce1c0824SLorenzo Stoakes 
960ce1c0824SLorenzo Stoakes 		ASSERT_TRUE(try_read_write_buf(curr));
961ce1c0824SLorenzo Stoakes 	}
962ce1c0824SLorenzo Stoakes 
963ce1c0824SLorenzo Stoakes 	/* Cleanup. */
964ce1c0824SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
965ce1c0824SLorenzo Stoakes }
966ce1c0824SLorenzo Stoakes 
967ce1c0824SLorenzo Stoakes /*
968ce1c0824SLorenzo Stoakes  * Assert that moving, extending and shrinking memory via mremap() retains
969ce1c0824SLorenzo Stoakes  * guard markers where possible.
970ce1c0824SLorenzo Stoakes  *
971ce1c0824SLorenzo Stoakes  * - Moving a mapping alone should retain markers as they are.
972ce1c0824SLorenzo Stoakes  */
TEST_F(guard_regions,mremap_move)973ce1c0824SLorenzo Stoakes TEST_F(guard_regions, mremap_move)
974ce1c0824SLorenzo Stoakes {
975ce1c0824SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
976ce1c0824SLorenzo Stoakes 	char *ptr, *ptr_new;
977ce1c0824SLorenzo Stoakes 
978272f37d3SLorenzo Stoakes 	/* Map 5 pages. */
979272f37d3SLorenzo Stoakes 	ptr = mmap_(self, variant, NULL, 5 * page_size,
980ce1c0824SLorenzo Stoakes 		    PROT_READ | PROT_WRITE, 0, 0);
981ce1c0824SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
982ce1c0824SLorenzo Stoakes 
983ce1c0824SLorenzo Stoakes 	/* Place guard markers at both ends of the 5 page span. */
984ce1c0824SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, page_size, MADV_GUARD_INSTALL), 0);
985ce1c0824SLorenzo Stoakes 	ASSERT_EQ(madvise(&ptr[4 * page_size], page_size, MADV_GUARD_INSTALL), 0);
986ce1c0824SLorenzo Stoakes 
987ce1c0824SLorenzo Stoakes 	/* Make sure the guard pages are in effect. */
988ce1c0824SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(ptr));
989ce1c0824SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(&ptr[4 * page_size]));
990ce1c0824SLorenzo Stoakes 
991ce1c0824SLorenzo Stoakes 	/* Map a new region we will move this range into. Doing this ensures
992ce1c0824SLorenzo Stoakes 	 * that we have reserved a range to map into.
993272f37d3SLorenzo Stoakes 	 */
994ce1c0824SLorenzo Stoakes 	ptr_new = mmap_(self, variant, NULL, 5 * page_size, PROT_NONE, 0, 0);
995ce1c0824SLorenzo Stoakes 	ASSERT_NE(ptr_new, MAP_FAILED);
996ce1c0824SLorenzo Stoakes 
997ce1c0824SLorenzo Stoakes 	ASSERT_EQ(mremap(ptr, 5 * page_size, 5 * page_size,
998ce1c0824SLorenzo Stoakes 			 MREMAP_MAYMOVE | MREMAP_FIXED, ptr_new), ptr_new);
999ce1c0824SLorenzo Stoakes 
1000ce1c0824SLorenzo Stoakes 	/* Make sure the guard markers are retained. */
1001ce1c0824SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(ptr_new));
1002ce1c0824SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(&ptr_new[4 * page_size]));
1003ce1c0824SLorenzo Stoakes 
1004ce1c0824SLorenzo Stoakes 	/*
1005ce1c0824SLorenzo Stoakes 	 * Clean up - we only need reference the new pointer as we overwrote the
1006ce1c0824SLorenzo Stoakes 	 * PROT_NONE range and moved the existing one.
1007ce1c0824SLorenzo Stoakes 	 */
1008ce1c0824SLorenzo Stoakes 	munmap(ptr_new, 5 * page_size);
1009ce1c0824SLorenzo Stoakes }
1010ce1c0824SLorenzo Stoakes 
1011ce1c0824SLorenzo Stoakes /*
1012ce1c0824SLorenzo Stoakes  * Assert that moving, extending and shrinking memory via mremap() retains
1013ce1c0824SLorenzo Stoakes  * guard markers where possible.
1014ce1c0824SLorenzo Stoakes  *
1015ce1c0824SLorenzo Stoakes  * Expanding should retain guard pages, only now in different position. The user
1016ce1c0824SLorenzo Stoakes  * will have to remove guard pages manually to fix up (they'd have to do the
1017ce1c0824SLorenzo Stoakes  * same if it were a PROT_NONE mapping).
1018ce1c0824SLorenzo Stoakes  */
TEST_F(guard_regions,mremap_expand)1019ce1c0824SLorenzo Stoakes TEST_F(guard_regions, mremap_expand)
1020ce1c0824SLorenzo Stoakes {
1021ce1c0824SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
1022ce1c0824SLorenzo Stoakes 	char *ptr, *ptr_new;
1023ce1c0824SLorenzo Stoakes 
1024272f37d3SLorenzo Stoakes 	/* Map 10 pages... */
1025272f37d3SLorenzo Stoakes 	ptr = mmap_(self, variant, NULL, 10 * page_size,
1026ce1c0824SLorenzo Stoakes 		    PROT_READ | PROT_WRITE, 0, 0);
1027ce1c0824SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
1028ce1c0824SLorenzo Stoakes 	/* ...But unmap the last 5 so we can ensure we can expand into them. */
1029ce1c0824SLorenzo Stoakes 	ASSERT_EQ(munmap(&ptr[5 * page_size], 5 * page_size), 0);
1030ce1c0824SLorenzo Stoakes 
1031ce1c0824SLorenzo Stoakes 	/* Place guard markers at both ends of the 5 page span. */
1032ce1c0824SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, page_size, MADV_GUARD_INSTALL), 0);
1033ce1c0824SLorenzo Stoakes 	ASSERT_EQ(madvise(&ptr[4 * page_size], page_size, MADV_GUARD_INSTALL), 0);
1034ce1c0824SLorenzo Stoakes 
1035ce1c0824SLorenzo Stoakes 	/* Make sure the guarding is in effect. */
1036ce1c0824SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(ptr));
1037ce1c0824SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(&ptr[4 * page_size]));
1038ce1c0824SLorenzo Stoakes 
1039ce1c0824SLorenzo Stoakes 	/* Now expand to 10 pages. */
1040ce1c0824SLorenzo Stoakes 	ptr = mremap(ptr, 5 * page_size, 10 * page_size, 0);
1041ce1c0824SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
1042ce1c0824SLorenzo Stoakes 
1043ce1c0824SLorenzo Stoakes 	/*
1044ce1c0824SLorenzo Stoakes 	 * Make sure the guard markers are retained in their original positions.
1045ce1c0824SLorenzo Stoakes 	 */
1046ce1c0824SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(ptr));
1047ce1c0824SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(&ptr[4 * page_size]));
1048ce1c0824SLorenzo Stoakes 
1049272f37d3SLorenzo Stoakes 	/* Reserve a region which we can move to and expand into. */
1050ce1c0824SLorenzo Stoakes 	ptr_new = mmap_(self, variant, NULL, 20 * page_size, PROT_NONE, 0, 0);
1051ce1c0824SLorenzo Stoakes 	ASSERT_NE(ptr_new, MAP_FAILED);
1052ce1c0824SLorenzo Stoakes 
1053ce1c0824SLorenzo Stoakes 	/* Now move and expand into it. */
1054ce1c0824SLorenzo Stoakes 	ptr = mremap(ptr, 10 * page_size, 20 * page_size,
1055ce1c0824SLorenzo Stoakes 		     MREMAP_MAYMOVE | MREMAP_FIXED, ptr_new);
1056ce1c0824SLorenzo Stoakes 	ASSERT_EQ(ptr, ptr_new);
1057ce1c0824SLorenzo Stoakes 
1058ce1c0824SLorenzo Stoakes 	/*
1059ce1c0824SLorenzo Stoakes 	 * Again, make sure the guard markers are retained in their original positions.
1060ce1c0824SLorenzo Stoakes 	 */
1061ce1c0824SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(ptr));
1062ce1c0824SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(&ptr[4 * page_size]));
1063ce1c0824SLorenzo Stoakes 
1064ce1c0824SLorenzo Stoakes 	/*
1065ce1c0824SLorenzo Stoakes 	 * A real user would have to remove guard markers, but would reasonably
1066ce1c0824SLorenzo Stoakes 	 * expect all characteristics of the mapping to be retained, including
1067ce1c0824SLorenzo Stoakes 	 * guard markers.
1068ce1c0824SLorenzo Stoakes 	 */
1069ce1c0824SLorenzo Stoakes 
1070ce1c0824SLorenzo Stoakes 	/* Cleanup. */
1071ce1c0824SLorenzo Stoakes 	munmap(ptr, 20 * page_size);
1072ce1c0824SLorenzo Stoakes }
1073ce1c0824SLorenzo Stoakes /*
1074ce1c0824SLorenzo Stoakes  * Assert that moving, extending and shrinking memory via mremap() retains
1075ce1c0824SLorenzo Stoakes  * guard markers where possible.
1076ce1c0824SLorenzo Stoakes  *
1077ce1c0824SLorenzo Stoakes  * Shrinking will result in markers that are shrunk over being removed. Again,
1078ce1c0824SLorenzo Stoakes  * if the user were using a PROT_NONE mapping they'd have to manually fix this
1079ce1c0824SLorenzo Stoakes  * up also so this is OK.
1080ce1c0824SLorenzo Stoakes  */
TEST_F(guard_regions,mremap_shrink)1081ce1c0824SLorenzo Stoakes TEST_F(guard_regions, mremap_shrink)
1082ce1c0824SLorenzo Stoakes {
1083ce1c0824SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
1084ce1c0824SLorenzo Stoakes 	char *ptr;
1085ce1c0824SLorenzo Stoakes 	int i;
1086ce1c0824SLorenzo Stoakes 
1087272f37d3SLorenzo Stoakes 	/* Map 5 pages. */
1088272f37d3SLorenzo Stoakes 	ptr = mmap_(self, variant, NULL, 5 * page_size,
1089ce1c0824SLorenzo Stoakes 		    PROT_READ | PROT_WRITE, 0, 0);
1090ce1c0824SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
1091ce1c0824SLorenzo Stoakes 
1092ce1c0824SLorenzo Stoakes 	/* Place guard markers at both ends of the 5 page span. */
1093ce1c0824SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, page_size, MADV_GUARD_INSTALL), 0);
1094ce1c0824SLorenzo Stoakes 	ASSERT_EQ(madvise(&ptr[4 * page_size], page_size, MADV_GUARD_INSTALL), 0);
1095ce1c0824SLorenzo Stoakes 
1096ce1c0824SLorenzo Stoakes 	/* Make sure the guarding is in effect. */
1097ce1c0824SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(ptr));
1098ce1c0824SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(&ptr[4 * page_size]));
1099ce1c0824SLorenzo Stoakes 
1100ce1c0824SLorenzo Stoakes 	/* Now shrink to 3 pages. */
1101ce1c0824SLorenzo Stoakes 	ptr = mremap(ptr, 5 * page_size, 3 * page_size, MREMAP_MAYMOVE);
1102ce1c0824SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
1103ce1c0824SLorenzo Stoakes 
1104ce1c0824SLorenzo Stoakes 	/* We expect the guard marker at the start to be retained... */
1105ce1c0824SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(ptr));
1106ce1c0824SLorenzo Stoakes 
1107ce1c0824SLorenzo Stoakes 	/* ...But remaining pages will not have guard markers. */
1108ce1c0824SLorenzo Stoakes 	for (i = 1; i < 3; i++) {
1109ce1c0824SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
1110ce1c0824SLorenzo Stoakes 
1111ce1c0824SLorenzo Stoakes 		ASSERT_TRUE(try_read_write_buf(curr));
1112ce1c0824SLorenzo Stoakes 	}
1113ce1c0824SLorenzo Stoakes 
1114ce1c0824SLorenzo Stoakes 	/*
1115ce1c0824SLorenzo Stoakes 	 * As with expansion, a real user would have to remove guard pages and
1116ce1c0824SLorenzo Stoakes 	 * fixup. But you'd have to do similar manual things with PROT_NONE
1117ce1c0824SLorenzo Stoakes 	 * mappings too.
1118ce1c0824SLorenzo Stoakes 	 */
1119ce1c0824SLorenzo Stoakes 
1120ce1c0824SLorenzo Stoakes 	/*
1121ce1c0824SLorenzo Stoakes 	 * If we expand back to the original size, the end marker will, of
1122ce1c0824SLorenzo Stoakes 	 * course, no longer be present.
1123ce1c0824SLorenzo Stoakes 	 */
1124ce1c0824SLorenzo Stoakes 	ptr = mremap(ptr, 3 * page_size, 5 * page_size, 0);
1125ce1c0824SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
1126ce1c0824SLorenzo Stoakes 
1127ce1c0824SLorenzo Stoakes 	/* Again, we expect the guard marker at the start to be retained... */
1128ce1c0824SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(ptr));
1129ce1c0824SLorenzo Stoakes 
1130ce1c0824SLorenzo Stoakes 	/* ...But remaining pages will not have guard markers. */
1131ce1c0824SLorenzo Stoakes 	for (i = 1; i < 5; i++) {
1132ce1c0824SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
1133ce1c0824SLorenzo Stoakes 
1134ce1c0824SLorenzo Stoakes 		ASSERT_TRUE(try_read_write_buf(curr));
1135ce1c0824SLorenzo Stoakes 	}
1136ce1c0824SLorenzo Stoakes 
1137ce1c0824SLorenzo Stoakes 	/* Cleanup. */
1138ce1c0824SLorenzo Stoakes 	munmap(ptr, 5 * page_size);
1139ce1c0824SLorenzo Stoakes }
1140ce1c0824SLorenzo Stoakes 
1141ce1c0824SLorenzo Stoakes /*
1142ce1c0824SLorenzo Stoakes  * Assert that forking a process with VMAs that do not have VM_WIPEONFORK set
1143ce1c0824SLorenzo Stoakes  * retain guard pages.
1144ce1c0824SLorenzo Stoakes  */
TEST_F(guard_regions,fork)1145ce1c0824SLorenzo Stoakes TEST_F(guard_regions, fork)
1146ce1c0824SLorenzo Stoakes {
1147ce1c0824SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
1148ce1c0824SLorenzo Stoakes 	char *ptr;
1149ce1c0824SLorenzo Stoakes 	pid_t pid;
1150ce1c0824SLorenzo Stoakes 	int i;
1151ce1c0824SLorenzo Stoakes 
1152272f37d3SLorenzo Stoakes 	/* Map 10 pages. */
1153272f37d3SLorenzo Stoakes 	ptr = mmap_(self, variant, NULL, 10 * page_size,
1154ce1c0824SLorenzo Stoakes 		    PROT_READ | PROT_WRITE, 0, 0);
1155ce1c0824SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
1156ce1c0824SLorenzo Stoakes 
1157ce1c0824SLorenzo Stoakes 	/* Establish guard pages in the first 5 pages. */
1158ce1c0824SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 5 * page_size, MADV_GUARD_INSTALL), 0);
1159ce1c0824SLorenzo Stoakes 
1160ce1c0824SLorenzo Stoakes 	pid = fork();
1161ce1c0824SLorenzo Stoakes 	ASSERT_NE(pid, -1);
1162ce1c0824SLorenzo Stoakes 	if (!pid) {
1163ce1c0824SLorenzo Stoakes 		/* This is the child process now. */
1164ce1c0824SLorenzo Stoakes 
1165ce1c0824SLorenzo Stoakes 		/* Assert that the guarding is in effect. */
1166ce1c0824SLorenzo Stoakes 		for (i = 0; i < 10; i++) {
1167ce1c0824SLorenzo Stoakes 			char *curr = &ptr[i * page_size];
1168ce1c0824SLorenzo Stoakes 			bool result = try_read_write_buf(curr);
1169ce1c0824SLorenzo Stoakes 
1170ce1c0824SLorenzo Stoakes 			ASSERT_TRUE(i >= 5 ? result : !result);
1171ce1c0824SLorenzo Stoakes 		}
1172ce1c0824SLorenzo Stoakes 
1173ce1c0824SLorenzo Stoakes 		/* Now unguard the range.*/
1174ce1c0824SLorenzo Stoakes 		ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_REMOVE), 0);
1175ce1c0824SLorenzo Stoakes 
1176ce1c0824SLorenzo Stoakes 		exit(0);
1177ce1c0824SLorenzo Stoakes 	}
1178ce1c0824SLorenzo Stoakes 
1179ce1c0824SLorenzo Stoakes 	/* Parent process. */
1180ce1c0824SLorenzo Stoakes 
1181ce1c0824SLorenzo Stoakes 	/* Parent simply waits on child. */
1182ce1c0824SLorenzo Stoakes 	waitpid(pid, NULL, 0);
1183ce1c0824SLorenzo Stoakes 
1184ce1c0824SLorenzo Stoakes 	/* Child unguard does not impact parent page table state. */
1185ce1c0824SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
1186ce1c0824SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
1187ce1c0824SLorenzo Stoakes 		bool result = try_read_write_buf(curr);
1188ce1c0824SLorenzo Stoakes 
1189ce1c0824SLorenzo Stoakes 		ASSERT_TRUE(i >= 5 ? result : !result);
1190ce1c0824SLorenzo Stoakes 	}
1191ce1c0824SLorenzo Stoakes 
1192ce1c0824SLorenzo Stoakes 	/* Cleanup. */
1193ce1c0824SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
1194ce1c0824SLorenzo Stoakes }
1195ce1c0824SLorenzo Stoakes 
1196ce1c0824SLorenzo Stoakes /*
1197ce1c0824SLorenzo Stoakes  * Assert expected behaviour after we fork populated ranges of anonymous memory
1198ce1c0824SLorenzo Stoakes  * and then guard and unguard the range.
1199ce1c0824SLorenzo Stoakes  */
TEST_F(guard_regions,fork_cow)1200ce1c0824SLorenzo Stoakes TEST_F(guard_regions, fork_cow)
1201ce1c0824SLorenzo Stoakes {
1202ce1c0824SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
1203ce1c0824SLorenzo Stoakes 	char *ptr;
1204ce1c0824SLorenzo Stoakes 	pid_t pid;
1205ce1c0824SLorenzo Stoakes 	int i;
1206272f37d3SLorenzo Stoakes 
1207272f37d3SLorenzo Stoakes 	if (variant->backing != ANON_BACKED)
1208272f37d3SLorenzo Stoakes 		SKIP(return, "CoW only supported on anon mappings");
1209ce1c0824SLorenzo Stoakes 
1210272f37d3SLorenzo Stoakes 	/* Map 10 pages. */
1211272f37d3SLorenzo Stoakes 	ptr = mmap_(self, variant, NULL, 10 * page_size,
1212ce1c0824SLorenzo Stoakes 		    PROT_READ | PROT_WRITE, 0, 0);
1213ce1c0824SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
1214ce1c0824SLorenzo Stoakes 
1215ce1c0824SLorenzo Stoakes 	/* Populate range. */
1216ce1c0824SLorenzo Stoakes 	for (i = 0; i < 10 * page_size; i++) {
1217ce1c0824SLorenzo Stoakes 		char chr = 'a' + (i % 26);
1218ce1c0824SLorenzo Stoakes 
1219ce1c0824SLorenzo Stoakes 		ptr[i] = chr;
1220ce1c0824SLorenzo Stoakes 	}
1221ce1c0824SLorenzo Stoakes 
1222ce1c0824SLorenzo Stoakes 	pid = fork();
1223ce1c0824SLorenzo Stoakes 	ASSERT_NE(pid, -1);
1224ce1c0824SLorenzo Stoakes 	if (!pid) {
1225ce1c0824SLorenzo Stoakes 		/* This is the child process now. */
1226ce1c0824SLorenzo Stoakes 
1227ce1c0824SLorenzo Stoakes 		/* Ensure the range is as expected. */
1228ce1c0824SLorenzo Stoakes 		for (i = 0; i < 10 * page_size; i++) {
1229ce1c0824SLorenzo Stoakes 			char expected = 'a' + (i % 26);
1230ce1c0824SLorenzo Stoakes 			char actual = ptr[i];
1231ce1c0824SLorenzo Stoakes 
1232ce1c0824SLorenzo Stoakes 			ASSERT_EQ(actual, expected);
1233ce1c0824SLorenzo Stoakes 		}
1234ce1c0824SLorenzo Stoakes 
1235ce1c0824SLorenzo Stoakes 		/* Establish guard pages across the whole range. */
1236ce1c0824SLorenzo Stoakes 		ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_INSTALL), 0);
1237ce1c0824SLorenzo Stoakes 		/* Remove it. */
1238ce1c0824SLorenzo Stoakes 		ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_REMOVE), 0);
1239ce1c0824SLorenzo Stoakes 
1240ce1c0824SLorenzo Stoakes 		/*
1241ce1c0824SLorenzo Stoakes 		 * By removing the guard pages, the page tables will be
1242ce1c0824SLorenzo Stoakes 		 * cleared. Assert that we are looking at the zero page now.
1243ce1c0824SLorenzo Stoakes 		 */
1244ce1c0824SLorenzo Stoakes 		for (i = 0; i < 10 * page_size; i++) {
1245ce1c0824SLorenzo Stoakes 			char actual = ptr[i];
1246ce1c0824SLorenzo Stoakes 
1247ce1c0824SLorenzo Stoakes 			ASSERT_EQ(actual, '\0');
1248ce1c0824SLorenzo Stoakes 		}
1249ce1c0824SLorenzo Stoakes 
1250ce1c0824SLorenzo Stoakes 		exit(0);
1251ce1c0824SLorenzo Stoakes 	}
1252ce1c0824SLorenzo Stoakes 
1253ce1c0824SLorenzo Stoakes 	/* Parent process. */
1254ce1c0824SLorenzo Stoakes 
1255ce1c0824SLorenzo Stoakes 	/* Parent simply waits on child. */
1256ce1c0824SLorenzo Stoakes 	waitpid(pid, NULL, 0);
1257ce1c0824SLorenzo Stoakes 
1258ce1c0824SLorenzo Stoakes 	/* Ensure the range is unchanged in parent anon range. */
1259ce1c0824SLorenzo Stoakes 	for (i = 0; i < 10 * page_size; i++) {
1260ce1c0824SLorenzo Stoakes 		char expected = 'a' + (i % 26);
1261ce1c0824SLorenzo Stoakes 		char actual = ptr[i];
1262ce1c0824SLorenzo Stoakes 
1263ce1c0824SLorenzo Stoakes 		ASSERT_EQ(actual, expected);
1264ce1c0824SLorenzo Stoakes 	}
1265ce1c0824SLorenzo Stoakes 
1266ce1c0824SLorenzo Stoakes 	/* Cleanup. */
1267ce1c0824SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
1268ce1c0824SLorenzo Stoakes }
1269ce1c0824SLorenzo Stoakes 
1270ce1c0824SLorenzo Stoakes /*
1271ce1c0824SLorenzo Stoakes  * Assert that forking a process with VMAs that do have VM_WIPEONFORK set
1272ce1c0824SLorenzo Stoakes  * behave as expected.
1273ce1c0824SLorenzo Stoakes  */
TEST_F(guard_regions,fork_wipeonfork)1274ce1c0824SLorenzo Stoakes TEST_F(guard_regions, fork_wipeonfork)
1275ce1c0824SLorenzo Stoakes {
1276ce1c0824SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
1277ce1c0824SLorenzo Stoakes 	char *ptr;
1278ce1c0824SLorenzo Stoakes 	pid_t pid;
1279ce1c0824SLorenzo Stoakes 	int i;
1280272f37d3SLorenzo Stoakes 
1281272f37d3SLorenzo Stoakes 	if (variant->backing != ANON_BACKED)
1282272f37d3SLorenzo Stoakes 		SKIP(return, "Wipe on fork only supported on anon mappings");
1283ce1c0824SLorenzo Stoakes 
1284272f37d3SLorenzo Stoakes 	/* Map 10 pages. */
1285272f37d3SLorenzo Stoakes 	ptr = mmap_(self, variant, NULL, 10 * page_size,
1286ce1c0824SLorenzo Stoakes 		    PROT_READ | PROT_WRITE, 0, 0);
1287ce1c0824SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
1288ce1c0824SLorenzo Stoakes 
1289ce1c0824SLorenzo Stoakes 	/* Mark wipe on fork. */
1290ce1c0824SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_WIPEONFORK), 0);
1291ce1c0824SLorenzo Stoakes 
1292ce1c0824SLorenzo Stoakes 	/* Guard the first 5 pages. */
1293ce1c0824SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 5 * page_size, MADV_GUARD_INSTALL), 0);
1294ce1c0824SLorenzo Stoakes 
1295ce1c0824SLorenzo Stoakes 	pid = fork();
1296ce1c0824SLorenzo Stoakes 	ASSERT_NE(pid, -1);
1297ce1c0824SLorenzo Stoakes 	if (!pid) {
1298ce1c0824SLorenzo Stoakes 		/* This is the child process now. */
1299ce1c0824SLorenzo Stoakes 
1300ce1c0824SLorenzo Stoakes 		/* Guard will have been wiped. */
1301ce1c0824SLorenzo Stoakes 		for (i = 0; i < 10; i++) {
1302ce1c0824SLorenzo Stoakes 			char *curr = &ptr[i * page_size];
1303ce1c0824SLorenzo Stoakes 
1304ce1c0824SLorenzo Stoakes 			ASSERT_TRUE(try_read_write_buf(curr));
1305ce1c0824SLorenzo Stoakes 		}
1306ce1c0824SLorenzo Stoakes 
1307ce1c0824SLorenzo Stoakes 		exit(0);
1308ce1c0824SLorenzo Stoakes 	}
1309ce1c0824SLorenzo Stoakes 
1310ce1c0824SLorenzo Stoakes 	/* Parent process. */
1311ce1c0824SLorenzo Stoakes 
1312ce1c0824SLorenzo Stoakes 	waitpid(pid, NULL, 0);
1313ce1c0824SLorenzo Stoakes 
1314ce1c0824SLorenzo Stoakes 	/* Guard markers should be in effect.*/
1315ce1c0824SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
1316ce1c0824SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
1317ce1c0824SLorenzo Stoakes 		bool result = try_read_write_buf(curr);
1318ce1c0824SLorenzo Stoakes 
1319ce1c0824SLorenzo Stoakes 		ASSERT_TRUE(i >= 5 ? result : !result);
1320ce1c0824SLorenzo Stoakes 	}
1321ce1c0824SLorenzo Stoakes 
1322ce1c0824SLorenzo Stoakes 	/* Cleanup. */
1323ce1c0824SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
1324ce1c0824SLorenzo Stoakes }
1325ce1c0824SLorenzo Stoakes 
1326ce1c0824SLorenzo Stoakes /* Ensure that MADV_FREE retains guard entries as expected. */
TEST_F(guard_regions,lazyfree)1327ce1c0824SLorenzo Stoakes TEST_F(guard_regions, lazyfree)
1328ce1c0824SLorenzo Stoakes {
1329ce1c0824SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
1330ce1c0824SLorenzo Stoakes 	char *ptr;
1331ce1c0824SLorenzo Stoakes 	int i;
1332272f37d3SLorenzo Stoakes 
1333272f37d3SLorenzo Stoakes 	if (variant->backing != ANON_BACKED)
1334272f37d3SLorenzo Stoakes 		SKIP(return, "MADV_FREE only supported on anon mappings");
1335ce1c0824SLorenzo Stoakes 
1336272f37d3SLorenzo Stoakes 	/* Map 10 pages. */
1337272f37d3SLorenzo Stoakes 	ptr = mmap_(self, variant, NULL, 10 * page_size,
1338ce1c0824SLorenzo Stoakes 		    PROT_READ | PROT_WRITE, 0, 0);
1339ce1c0824SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
1340ce1c0824SLorenzo Stoakes 
1341ce1c0824SLorenzo Stoakes 	/* Guard range. */
1342ce1c0824SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_INSTALL), 0);
1343ce1c0824SLorenzo Stoakes 
1344ce1c0824SLorenzo Stoakes 	/* Ensure guarded. */
1345ce1c0824SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
1346ce1c0824SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
1347ce1c0824SLorenzo Stoakes 
1348ce1c0824SLorenzo Stoakes 		ASSERT_FALSE(try_read_write_buf(curr));
1349ce1c0824SLorenzo Stoakes 	}
1350ce1c0824SLorenzo Stoakes 
1351ce1c0824SLorenzo Stoakes 	/* Lazyfree range. */
1352ce1c0824SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_FREE), 0);
1353ce1c0824SLorenzo Stoakes 
1354ce1c0824SLorenzo Stoakes 	/* This should leave the guard markers in place. */
1355ce1c0824SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
1356ce1c0824SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
1357ce1c0824SLorenzo Stoakes 
1358ce1c0824SLorenzo Stoakes 		ASSERT_FALSE(try_read_write_buf(curr));
1359ce1c0824SLorenzo Stoakes 	}
1360ce1c0824SLorenzo Stoakes 
1361ce1c0824SLorenzo Stoakes 	/* Cleanup. */
1362ce1c0824SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
1363ce1c0824SLorenzo Stoakes }
1364ce1c0824SLorenzo Stoakes 
1365ce1c0824SLorenzo Stoakes /* Ensure that MADV_POPULATE_READ, MADV_POPULATE_WRITE behave as expected. */
TEST_F(guard_regions,populate)1366ce1c0824SLorenzo Stoakes TEST_F(guard_regions, populate)
1367ce1c0824SLorenzo Stoakes {
1368ce1c0824SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
1369ce1c0824SLorenzo Stoakes 	char *ptr;
1370ce1c0824SLorenzo Stoakes 
1371272f37d3SLorenzo Stoakes 	/* Map 10 pages. */
1372272f37d3SLorenzo Stoakes 	ptr = mmap_(self, variant, NULL, 10 * page_size,
1373ce1c0824SLorenzo Stoakes 		    PROT_READ | PROT_WRITE, 0, 0);
1374ce1c0824SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
1375ce1c0824SLorenzo Stoakes 
1376ce1c0824SLorenzo Stoakes 	/* Guard range. */
1377ce1c0824SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_INSTALL), 0);
1378ce1c0824SLorenzo Stoakes 
1379ce1c0824SLorenzo Stoakes 	/* Populate read should error out... */
1380ce1c0824SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_POPULATE_READ), -1);
1381ce1c0824SLorenzo Stoakes 	ASSERT_EQ(errno, EFAULT);
1382ce1c0824SLorenzo Stoakes 
1383ce1c0824SLorenzo Stoakes 	/* ...as should populate write. */
1384ce1c0824SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_POPULATE_WRITE), -1);
1385ce1c0824SLorenzo Stoakes 	ASSERT_EQ(errno, EFAULT);
1386ce1c0824SLorenzo Stoakes 
1387ce1c0824SLorenzo Stoakes 	/* Cleanup. */
1388ce1c0824SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
1389ce1c0824SLorenzo Stoakes }
1390ce1c0824SLorenzo Stoakes 
1391ce1c0824SLorenzo Stoakes /* Ensure that MADV_COLD, MADV_PAGEOUT do not remove guard markers. */
TEST_F(guard_regions,cold_pageout)1392ce1c0824SLorenzo Stoakes TEST_F(guard_regions, cold_pageout)
1393ce1c0824SLorenzo Stoakes {
1394ce1c0824SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
1395ce1c0824SLorenzo Stoakes 	char *ptr;
1396ce1c0824SLorenzo Stoakes 	int i;
1397ce1c0824SLorenzo Stoakes 
1398272f37d3SLorenzo Stoakes 	/* Map 10 pages. */
1399272f37d3SLorenzo Stoakes 	ptr = mmap_(self, variant, NULL, 10 * page_size,
1400ce1c0824SLorenzo Stoakes 		    PROT_READ | PROT_WRITE, 0, 0);
1401ce1c0824SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
1402ce1c0824SLorenzo Stoakes 
1403ce1c0824SLorenzo Stoakes 	/* Guard range. */
1404ce1c0824SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_INSTALL), 0);
1405ce1c0824SLorenzo Stoakes 
1406ce1c0824SLorenzo Stoakes 	/* Ensured guarded. */
1407ce1c0824SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
1408ce1c0824SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
1409ce1c0824SLorenzo Stoakes 
1410ce1c0824SLorenzo Stoakes 		ASSERT_FALSE(try_read_write_buf(curr));
1411ce1c0824SLorenzo Stoakes 	}
1412ce1c0824SLorenzo Stoakes 
1413ce1c0824SLorenzo Stoakes 	/* Now mark cold. This should have no impact on guard markers. */
1414ce1c0824SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_COLD), 0);
1415ce1c0824SLorenzo Stoakes 
1416ce1c0824SLorenzo Stoakes 	/* Should remain guarded. */
1417ce1c0824SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
1418ce1c0824SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
1419ce1c0824SLorenzo Stoakes 
1420ce1c0824SLorenzo Stoakes 		ASSERT_FALSE(try_read_write_buf(curr));
1421ce1c0824SLorenzo Stoakes 	}
1422ce1c0824SLorenzo Stoakes 
1423ce1c0824SLorenzo Stoakes 	/* OK, now page out. This should equally, have no effect on markers. */
1424ce1c0824SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_PAGEOUT), 0);
1425ce1c0824SLorenzo Stoakes 
1426ce1c0824SLorenzo Stoakes 	/* Should remain guarded. */
1427ce1c0824SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
1428ce1c0824SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
1429ce1c0824SLorenzo Stoakes 
1430ce1c0824SLorenzo Stoakes 		ASSERT_FALSE(try_read_write_buf(curr));
1431ce1c0824SLorenzo Stoakes 	}
1432ce1c0824SLorenzo Stoakes 
1433ce1c0824SLorenzo Stoakes 	/* Cleanup. */
1434ce1c0824SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
1435ce1c0824SLorenzo Stoakes }
1436ce1c0824SLorenzo Stoakes 
1437ce1c0824SLorenzo Stoakes /* Ensure that guard pages do not break userfaultd. */
TEST_F(guard_regions,uffd)1438ce1c0824SLorenzo Stoakes TEST_F(guard_regions, uffd)
1439ce1c0824SLorenzo Stoakes {
1440ce1c0824SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
1441ce1c0824SLorenzo Stoakes 	int uffd;
1442ce1c0824SLorenzo Stoakes 	char *ptr;
1443ce1c0824SLorenzo Stoakes 	int i;
1444ce1c0824SLorenzo Stoakes 	struct uffdio_api api = {
1445ce1c0824SLorenzo Stoakes 		.api = UFFD_API,
1446ce1c0824SLorenzo Stoakes 		.features = 0,
1447ce1c0824SLorenzo Stoakes 	};
1448ce1c0824SLorenzo Stoakes 	struct uffdio_register reg;
1449ce1c0824SLorenzo Stoakes 	struct uffdio_range range;
1450272f37d3SLorenzo Stoakes 
1451272f37d3SLorenzo Stoakes 	if (!is_anon_backed(variant))
1452272f37d3SLorenzo Stoakes 		SKIP(return, "uffd only works on anon backing");
1453ce1c0824SLorenzo Stoakes 
1454ce1c0824SLorenzo Stoakes 	/* Set up uffd. */
1455ce1c0824SLorenzo Stoakes 	uffd = userfaultfd(0);
1456ce1c0824SLorenzo Stoakes 	if (uffd == -1) {
1457ce1c0824SLorenzo Stoakes 		switch (errno) {
1458ce1c0824SLorenzo Stoakes 		case EPERM:
1459ce1c0824SLorenzo Stoakes 			SKIP(return, "No userfaultfd permissions, try running as root.");
1460ce1c0824SLorenzo Stoakes 			break;
1461ce1c0824SLorenzo Stoakes 		case ENOSYS:
1462272f37d3SLorenzo Stoakes 			SKIP(return, "userfaultfd is not supported/not enabled.");
1463272f37d3SLorenzo Stoakes 			break;
1464ce1c0824SLorenzo Stoakes 		default:
1465ce1c0824SLorenzo Stoakes 			ksft_exit_fail_msg("userfaultfd failed with %s\n",
1466ce1c0824SLorenzo Stoakes 					   strerror(errno));
1467ce1c0824SLorenzo Stoakes 			break;
1468ce1c0824SLorenzo Stoakes 		}
1469ce1c0824SLorenzo Stoakes 	}
1470ce1c0824SLorenzo Stoakes 
1471ce1c0824SLorenzo Stoakes 	ASSERT_NE(uffd, -1);
1472ce1c0824SLorenzo Stoakes 
1473ce1c0824SLorenzo Stoakes 	ASSERT_EQ(ioctl(uffd, UFFDIO_API, &api), 0);
1474ce1c0824SLorenzo Stoakes 
1475ce1c0824SLorenzo Stoakes 	/* Map 10 pages. */
1476ce1c0824SLorenzo Stoakes 	ptr = mmap_(self, variant, NULL, 10 * page_size,
1477ce1c0824SLorenzo Stoakes 		    PROT_READ | PROT_WRITE, 0, 0);
1478ce1c0824SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
1479ce1c0824SLorenzo Stoakes 
1480ce1c0824SLorenzo Stoakes 	/* Register the range with uffd. */
1481ce1c0824SLorenzo Stoakes 	range.start = (unsigned long)ptr;
1482ce1c0824SLorenzo Stoakes 	range.len = 10 * page_size;
1483ce1c0824SLorenzo Stoakes 	reg.range = range;
1484ce1c0824SLorenzo Stoakes 	reg.mode = UFFDIO_REGISTER_MODE_MISSING;
1485ce1c0824SLorenzo Stoakes 	ASSERT_EQ(ioctl(uffd, UFFDIO_REGISTER, &reg), 0);
1486ce1c0824SLorenzo Stoakes 
1487ce1c0824SLorenzo Stoakes 	/* Guard the range. This should not trigger the uffd. */
1488ce1c0824SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_INSTALL), 0);
14890b6d4853SLorenzo Stoakes 
14900b6d4853SLorenzo Stoakes 	/* The guarding should behave as usual with no uffd intervention. */
14910b6d4853SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
14920b6d4853SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
14930b6d4853SLorenzo Stoakes 
14940b6d4853SLorenzo Stoakes 		ASSERT_FALSE(try_read_write_buf(curr));
14950b6d4853SLorenzo Stoakes 	}
14960b6d4853SLorenzo Stoakes 
14970b6d4853SLorenzo Stoakes 	/* Cleanup. */
14980b6d4853SLorenzo Stoakes 	ASSERT_EQ(ioctl(uffd, UFFDIO_UNREGISTER, &range), 0);
14990b6d4853SLorenzo Stoakes 	close(uffd);
15000b6d4853SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
15010b6d4853SLorenzo Stoakes }
15020b6d4853SLorenzo Stoakes 
15030b6d4853SLorenzo Stoakes /*
15040b6d4853SLorenzo Stoakes  * Mark a region within a file-backed mapping using MADV_SEQUENTIAL so we
15050b6d4853SLorenzo Stoakes  * aggressively read-ahead, then install guard regions and assert that it
15060b6d4853SLorenzo Stoakes  * behaves correctly.
15070b6d4853SLorenzo Stoakes  *
15080b6d4853SLorenzo Stoakes  * We page out using MADV_PAGEOUT before checking guard regions so we drop page
15090b6d4853SLorenzo Stoakes  * cache folios, meaning we maximise the possibility of some broken readahead.
15100b6d4853SLorenzo Stoakes  */
TEST_F(guard_regions,madvise_sequential)15110b6d4853SLorenzo Stoakes TEST_F(guard_regions, madvise_sequential)
15120b6d4853SLorenzo Stoakes {
15130b6d4853SLorenzo Stoakes 	char *ptr;
15140b6d4853SLorenzo Stoakes 	int i;
15150b6d4853SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
15160b6d4853SLorenzo Stoakes 
15170b6d4853SLorenzo Stoakes 	if (variant->backing == ANON_BACKED)
15180b6d4853SLorenzo Stoakes 		SKIP(return, "MADV_SEQUENTIAL meaningful only for file-backed");
15190b6d4853SLorenzo Stoakes 
15200b6d4853SLorenzo Stoakes 	ptr = mmap_(self, variant, NULL, 10 * page_size,
15210b6d4853SLorenzo Stoakes 		    PROT_READ | PROT_WRITE, 0, 0);
15220b6d4853SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
15230b6d4853SLorenzo Stoakes 
15240b6d4853SLorenzo Stoakes 	/* Establish a pattern of data in the file. */
15250b6d4853SLorenzo Stoakes 	set_pattern(ptr, 10, page_size);
15260b6d4853SLorenzo Stoakes 	ASSERT_TRUE(check_pattern(ptr, 10, page_size));
15270b6d4853SLorenzo Stoakes 
15280b6d4853SLorenzo Stoakes 	/* Mark it as being accessed sequentially. */
15290b6d4853SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_SEQUENTIAL), 0);
15300b6d4853SLorenzo Stoakes 
15310b6d4853SLorenzo Stoakes 	/* Mark every other page a guard page. */
15320b6d4853SLorenzo Stoakes 	for (i = 0; i < 10; i += 2) {
15330b6d4853SLorenzo Stoakes 		char *ptr2 = &ptr[i * page_size];
15340b6d4853SLorenzo Stoakes 
15350b6d4853SLorenzo Stoakes 		ASSERT_EQ(madvise(ptr2, page_size, MADV_GUARD_INSTALL), 0);
15360b6d4853SLorenzo Stoakes 	}
15370b6d4853SLorenzo Stoakes 
15380b6d4853SLorenzo Stoakes 	/* Now page it out. */
15390b6d4853SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_PAGEOUT), 0);
15400b6d4853SLorenzo Stoakes 
15410b6d4853SLorenzo Stoakes 	/* Now make sure pages are as expected. */
15420b6d4853SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
15430b6d4853SLorenzo Stoakes 		char *chrp = &ptr[i * page_size];
15440b6d4853SLorenzo Stoakes 
15450b6d4853SLorenzo Stoakes 		if (i % 2 == 0) {
15460b6d4853SLorenzo Stoakes 			bool result = try_read_write_buf(chrp);
15470b6d4853SLorenzo Stoakes 
15480b6d4853SLorenzo Stoakes 			ASSERT_FALSE(result);
15490b6d4853SLorenzo Stoakes 		} else {
15500b6d4853SLorenzo Stoakes 			ASSERT_EQ(*chrp, 'a' + i);
15510b6d4853SLorenzo Stoakes 		}
15520b6d4853SLorenzo Stoakes 	}
15530b6d4853SLorenzo Stoakes 
15540b6d4853SLorenzo Stoakes 	/* Now remove guard pages. */
15550b6d4853SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_REMOVE), 0);
15560b6d4853SLorenzo Stoakes 
15570b6d4853SLorenzo Stoakes 	/* Now make sure all data is as expected. */
15580b6d4853SLorenzo Stoakes 	if (!check_pattern(ptr, 10, page_size))
15590b6d4853SLorenzo Stoakes 		ASSERT_TRUE(false);
15600b6d4853SLorenzo Stoakes 
15610b6d4853SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
15620b6d4853SLorenzo Stoakes }
15630b6d4853SLorenzo Stoakes 
15640b6d4853SLorenzo Stoakes /*
15650b6d4853SLorenzo Stoakes  * Check that file-backed mappings implement guard regions with MAP_PRIVATE
15660b6d4853SLorenzo Stoakes  * correctly.
15670b6d4853SLorenzo Stoakes  */
TEST_F(guard_regions,map_private)15680b6d4853SLorenzo Stoakes TEST_F(guard_regions, map_private)
15690b6d4853SLorenzo Stoakes {
15700b6d4853SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
15710b6d4853SLorenzo Stoakes 	char *ptr_shared, *ptr_private;
15720b6d4853SLorenzo Stoakes 	int i;
15730b6d4853SLorenzo Stoakes 
15740b6d4853SLorenzo Stoakes 	if (variant->backing == ANON_BACKED)
15750b6d4853SLorenzo Stoakes 		SKIP(return, "MAP_PRIVATE test specific to file-backed");
15760b6d4853SLorenzo Stoakes 
15770b6d4853SLorenzo Stoakes 	ptr_shared = mmap_(self, variant, NULL, 10 * page_size, PROT_READ | PROT_WRITE, 0, 0);
15780b6d4853SLorenzo Stoakes 	ASSERT_NE(ptr_shared, MAP_FAILED);
15790b6d4853SLorenzo Stoakes 
15800b6d4853SLorenzo Stoakes 	/* Manually mmap(), do not use mmap_() wrapper so we can force MAP_PRIVATE. */
15810b6d4853SLorenzo Stoakes 	ptr_private = mmap(NULL, 10 * page_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, self->fd, 0);
15820b6d4853SLorenzo Stoakes 	ASSERT_NE(ptr_private, MAP_FAILED);
15830b6d4853SLorenzo Stoakes 
15840b6d4853SLorenzo Stoakes 	/* Set pattern in shared mapping. */
15850b6d4853SLorenzo Stoakes 	set_pattern(ptr_shared, 10, page_size);
15860b6d4853SLorenzo Stoakes 
15870b6d4853SLorenzo Stoakes 	/* Install guard regions in every other page in the shared mapping. */
15880b6d4853SLorenzo Stoakes 	for (i = 0; i < 10; i += 2) {
15890b6d4853SLorenzo Stoakes 		char *ptr = &ptr_shared[i * page_size];
15900b6d4853SLorenzo Stoakes 
15910b6d4853SLorenzo Stoakes 		ASSERT_EQ(madvise(ptr, page_size, MADV_GUARD_INSTALL), 0);
15920b6d4853SLorenzo Stoakes 	}
15930b6d4853SLorenzo Stoakes 
15940b6d4853SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
15950b6d4853SLorenzo Stoakes 		/* Every even shared page should be guarded. */
15960b6d4853SLorenzo Stoakes 		ASSERT_EQ(try_read_buf(&ptr_shared[i * page_size]), i % 2 != 0);
15970b6d4853SLorenzo Stoakes 		/* Private mappings should always be readable. */
15980b6d4853SLorenzo Stoakes 		ASSERT_TRUE(try_read_buf(&ptr_private[i * page_size]));
15990b6d4853SLorenzo Stoakes 	}
16000b6d4853SLorenzo Stoakes 
16010b6d4853SLorenzo Stoakes 	/* Install guard regions in every other page in the private mapping. */
16020b6d4853SLorenzo Stoakes 	for (i = 0; i < 10; i += 2) {
16030b6d4853SLorenzo Stoakes 		char *ptr = &ptr_private[i * page_size];
16040b6d4853SLorenzo Stoakes 
16050b6d4853SLorenzo Stoakes 		ASSERT_EQ(madvise(ptr, page_size, MADV_GUARD_INSTALL), 0);
16060b6d4853SLorenzo Stoakes 	}
16070b6d4853SLorenzo Stoakes 
16080b6d4853SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
16090b6d4853SLorenzo Stoakes 		/* Every even shared page should be guarded. */
16100b6d4853SLorenzo Stoakes 		ASSERT_EQ(try_read_buf(&ptr_shared[i * page_size]), i % 2 != 0);
16110b6d4853SLorenzo Stoakes 		/* Every odd private page should be guarded. */
16120b6d4853SLorenzo Stoakes 		ASSERT_EQ(try_read_buf(&ptr_private[i * page_size]), i % 2 != 0);
16130b6d4853SLorenzo Stoakes 	}
16140b6d4853SLorenzo Stoakes 
16150b6d4853SLorenzo Stoakes 	/* Remove guard regions from shared mapping. */
16160b6d4853SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr_shared, 10 * page_size, MADV_GUARD_REMOVE), 0);
16170b6d4853SLorenzo Stoakes 
16180b6d4853SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
16190b6d4853SLorenzo Stoakes 		/* Shared mappings should always be readable. */
16200b6d4853SLorenzo Stoakes 		ASSERT_TRUE(try_read_buf(&ptr_shared[i * page_size]));
16210b6d4853SLorenzo Stoakes 		/* Every even private page should be guarded. */
16220b6d4853SLorenzo Stoakes 		ASSERT_EQ(try_read_buf(&ptr_private[i * page_size]), i % 2 != 0);
16230b6d4853SLorenzo Stoakes 	}
16240b6d4853SLorenzo Stoakes 
16250b6d4853SLorenzo Stoakes 	/* Remove guard regions from private mapping. */
16260b6d4853SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr_private, 10 * page_size, MADV_GUARD_REMOVE), 0);
16270b6d4853SLorenzo Stoakes 
16280b6d4853SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
16290b6d4853SLorenzo Stoakes 		/* Shared mappings should always be readable. */
16300b6d4853SLorenzo Stoakes 		ASSERT_TRUE(try_read_buf(&ptr_shared[i * page_size]));
16310b6d4853SLorenzo Stoakes 		/* Private mappings should always be readable. */
16320b6d4853SLorenzo Stoakes 		ASSERT_TRUE(try_read_buf(&ptr_private[i * page_size]));
16330b6d4853SLorenzo Stoakes 	}
16340b6d4853SLorenzo Stoakes 
16350b6d4853SLorenzo Stoakes 	/* Ensure patterns are intact. */
16360b6d4853SLorenzo Stoakes 	ASSERT_TRUE(check_pattern(ptr_shared, 10, page_size));
16370b6d4853SLorenzo Stoakes 	ASSERT_TRUE(check_pattern(ptr_private, 10, page_size));
16380b6d4853SLorenzo Stoakes 
16390b6d4853SLorenzo Stoakes 	/* Now write out every other page to MAP_PRIVATE. */
16400b6d4853SLorenzo Stoakes 	for (i = 0; i < 10; i += 2) {
16410b6d4853SLorenzo Stoakes 		char *ptr = &ptr_private[i * page_size];
16420b6d4853SLorenzo Stoakes 
16430b6d4853SLorenzo Stoakes 		memset(ptr, 'a' + i, page_size);
16440b6d4853SLorenzo Stoakes 	}
16450b6d4853SLorenzo Stoakes 
16460b6d4853SLorenzo Stoakes 	/*
16470b6d4853SLorenzo Stoakes 	 * At this point the mapping is:
16480b6d4853SLorenzo Stoakes 	 *
16490b6d4853SLorenzo Stoakes 	 * 0123456789
16500b6d4853SLorenzo Stoakes 	 * SPSPSPSPSP
16510b6d4853SLorenzo Stoakes 	 *
16520b6d4853SLorenzo Stoakes 	 * Where S = shared, P = private mappings.
16530b6d4853SLorenzo Stoakes 	 */
16540b6d4853SLorenzo Stoakes 
16550b6d4853SLorenzo Stoakes 	/* Now mark the beginning of the mapping guarded. */
16560b6d4853SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr_private, 5 * page_size, MADV_GUARD_INSTALL), 0);
16570b6d4853SLorenzo Stoakes 
16580b6d4853SLorenzo Stoakes 	/*
16590b6d4853SLorenzo Stoakes 	 * This renders the mapping:
16600b6d4853SLorenzo Stoakes 	 *
16610b6d4853SLorenzo Stoakes 	 * 0123456789
16620b6d4853SLorenzo Stoakes 	 * xxxxxPSPSP
16630b6d4853SLorenzo Stoakes 	 */
16640b6d4853SLorenzo Stoakes 
16650b6d4853SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
16660b6d4853SLorenzo Stoakes 		char *ptr = &ptr_private[i * page_size];
16670b6d4853SLorenzo Stoakes 
16680b6d4853SLorenzo Stoakes 		/* Ensure guard regions as expected. */
16690b6d4853SLorenzo Stoakes 		ASSERT_EQ(try_read_buf(ptr), i >= 5);
16700b6d4853SLorenzo Stoakes 		/* The shared mapping should always succeed. */
16710b6d4853SLorenzo Stoakes 		ASSERT_TRUE(try_read_buf(&ptr_shared[i * page_size]));
16720b6d4853SLorenzo Stoakes 	}
16730b6d4853SLorenzo Stoakes 
16740b6d4853SLorenzo Stoakes 	/* Remove the guard regions altogether. */
16750b6d4853SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr_private, 10 * page_size, MADV_GUARD_REMOVE), 0);
16760b6d4853SLorenzo Stoakes 
16770b6d4853SLorenzo Stoakes 	/*
16780b6d4853SLorenzo Stoakes 	 *
16790b6d4853SLorenzo Stoakes 	 * We now expect the mapping to be:
16800b6d4853SLorenzo Stoakes 	 *
16810b6d4853SLorenzo Stoakes 	 * 0123456789
16820b6d4853SLorenzo Stoakes 	 * SSSSSPSPSP
16830b6d4853SLorenzo Stoakes 	 *
16840b6d4853SLorenzo Stoakes 	 * As we removed guard regions, the private pages from the first 5 will
16850b6d4853SLorenzo Stoakes 	 * have been zapped, so on fault will reestablish the shared mapping.
16860b6d4853SLorenzo Stoakes 	 */
16870b6d4853SLorenzo Stoakes 
16880b6d4853SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
16890b6d4853SLorenzo Stoakes 		char *ptr = &ptr_private[i * page_size];
16900b6d4853SLorenzo Stoakes 
16910b6d4853SLorenzo Stoakes 		/*
16920b6d4853SLorenzo Stoakes 		 * Assert that shared mappings in the MAP_PRIVATE mapping match
16930b6d4853SLorenzo Stoakes 		 * the shared mapping.
16940b6d4853SLorenzo Stoakes 		 */
16950b6d4853SLorenzo Stoakes 		if (i < 5 || i % 2 == 0) {
16960b6d4853SLorenzo Stoakes 			char *ptr_s = &ptr_shared[i * page_size];
16970b6d4853SLorenzo Stoakes 
16980b6d4853SLorenzo Stoakes 			ASSERT_EQ(memcmp(ptr, ptr_s, page_size), 0);
16990b6d4853SLorenzo Stoakes 			continue;
17000b6d4853SLorenzo Stoakes 		}
17010b6d4853SLorenzo Stoakes 
17020b6d4853SLorenzo Stoakes 		/* Everything else is a private mapping. */
1703*a8efaddaSLorenzo Stoakes 		ASSERT_TRUE(is_buf_eq(ptr, page_size, 'a' + i));
17040b6d4853SLorenzo Stoakes 	}
17050b6d4853SLorenzo Stoakes 
17060b6d4853SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr_shared, 10 * page_size), 0);
17070b6d4853SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr_private, 10 * page_size), 0);
17080b6d4853SLorenzo Stoakes }
17090b6d4853SLorenzo Stoakes 
17100b6d4853SLorenzo Stoakes /* Test that guard regions established over a read-only mapping function correctly. */
TEST_F(guard_regions,readonly_file)17110b6d4853SLorenzo Stoakes TEST_F(guard_regions, readonly_file)
17120b6d4853SLorenzo Stoakes {
17130b6d4853SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
17140b6d4853SLorenzo Stoakes 	char *ptr;
17150b6d4853SLorenzo Stoakes 	int i;
17160b6d4853SLorenzo Stoakes 
17170b6d4853SLorenzo Stoakes 	if (variant->backing != LOCAL_FILE_BACKED)
17180b6d4853SLorenzo Stoakes 		SKIP(return, "Read-only test specific to file-backed");
17190b6d4853SLorenzo Stoakes 
17200b6d4853SLorenzo Stoakes 	/* Map shared so we can populate with pattern, populate it, unmap. */
17210b6d4853SLorenzo Stoakes 	ptr = mmap_(self, variant, NULL, 10 * page_size,
17220b6d4853SLorenzo Stoakes 		    PROT_READ | PROT_WRITE, 0, 0);
17230b6d4853SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
17240b6d4853SLorenzo Stoakes 	set_pattern(ptr, 10, page_size);
17250b6d4853SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
17260b6d4853SLorenzo Stoakes 	/* Close the fd so we can re-open read-only. */
17270b6d4853SLorenzo Stoakes 	ASSERT_EQ(close(self->fd), 0);
17280b6d4853SLorenzo Stoakes 
17290b6d4853SLorenzo Stoakes 	/* Re-open read-only. */
17300b6d4853SLorenzo Stoakes 	self->fd = open(self->path, O_RDONLY);
17310b6d4853SLorenzo Stoakes 	ASSERT_NE(self->fd, -1);
17320b6d4853SLorenzo Stoakes 	/* Re-map read-only. */
17330b6d4853SLorenzo Stoakes 	ptr = mmap_(self, variant, NULL, 10 * page_size, PROT_READ, 0, 0);
17340b6d4853SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
17350b6d4853SLorenzo Stoakes 
17360b6d4853SLorenzo Stoakes 	/* Mark every other page guarded. */
17370b6d4853SLorenzo Stoakes 	for (i = 0; i < 10; i += 2) {
17380b6d4853SLorenzo Stoakes 		char *ptr_pg = &ptr[i * page_size];
17390b6d4853SLorenzo Stoakes 
17400b6d4853SLorenzo Stoakes 		ASSERT_EQ(madvise(ptr_pg, page_size, MADV_GUARD_INSTALL), 0);
17410b6d4853SLorenzo Stoakes 	}
17420b6d4853SLorenzo Stoakes 
17430b6d4853SLorenzo Stoakes 	/* Assert that the guard regions are in place.*/
17440b6d4853SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
17450b6d4853SLorenzo Stoakes 		char *ptr_pg = &ptr[i * page_size];
17460b6d4853SLorenzo Stoakes 
17470b6d4853SLorenzo Stoakes 		ASSERT_EQ(try_read_buf(ptr_pg), i % 2 != 0);
17480b6d4853SLorenzo Stoakes 	}
17490b6d4853SLorenzo Stoakes 
17500b6d4853SLorenzo Stoakes 	/* Remove guard regions. */
17510b6d4853SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_REMOVE), 0);
17520b6d4853SLorenzo Stoakes 
17530b6d4853SLorenzo Stoakes 	/* Ensure the data is as expected. */
17540b6d4853SLorenzo Stoakes 	ASSERT_TRUE(check_pattern(ptr, 10, page_size));
17550b6d4853SLorenzo Stoakes 
17560b6d4853SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
17570b6d4853SLorenzo Stoakes }
17580b6d4853SLorenzo Stoakes 
TEST_F(guard_regions,fault_around)17590b6d4853SLorenzo Stoakes TEST_F(guard_regions, fault_around)
17600b6d4853SLorenzo Stoakes {
17610b6d4853SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
17620b6d4853SLorenzo Stoakes 	char *ptr;
17630b6d4853SLorenzo Stoakes 	int i;
17640b6d4853SLorenzo Stoakes 
17650b6d4853SLorenzo Stoakes 	if (variant->backing == ANON_BACKED)
17660b6d4853SLorenzo Stoakes 		SKIP(return, "Fault-around test specific to file-backed");
17670b6d4853SLorenzo Stoakes 
17680b6d4853SLorenzo Stoakes 	ptr = mmap_(self, variant, NULL, 10 * page_size,
17690b6d4853SLorenzo Stoakes 		    PROT_READ | PROT_WRITE, 0, 0);
17700b6d4853SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
17710b6d4853SLorenzo Stoakes 
17720b6d4853SLorenzo Stoakes 	/* Establish a pattern in the backing file. */
17730b6d4853SLorenzo Stoakes 	set_pattern(ptr, 10, page_size);
17740b6d4853SLorenzo Stoakes 
17750b6d4853SLorenzo Stoakes 	/*
17760b6d4853SLorenzo Stoakes 	 * Now drop it from the page cache so we get major faults when next we
17770b6d4853SLorenzo Stoakes 	 * map it.
17780b6d4853SLorenzo Stoakes 	 */
17790b6d4853SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_PAGEOUT), 0);
17800b6d4853SLorenzo Stoakes 
17810b6d4853SLorenzo Stoakes 	/* Unmap and remap 'to be sure'. */
17820b6d4853SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
17830b6d4853SLorenzo Stoakes 	ptr = mmap_(self, variant, NULL, 10 * page_size,
17840b6d4853SLorenzo Stoakes 		    PROT_READ | PROT_WRITE, 0, 0);
17850b6d4853SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
17860b6d4853SLorenzo Stoakes 
17870b6d4853SLorenzo Stoakes 	/* Now make every even page guarded. */
17880b6d4853SLorenzo Stoakes 	for (i = 0; i < 10; i += 2) {
17890b6d4853SLorenzo Stoakes 		char *ptr_p = &ptr[i * page_size];
17900b6d4853SLorenzo Stoakes 
17910b6d4853SLorenzo Stoakes 		ASSERT_EQ(madvise(ptr_p, page_size, MADV_GUARD_INSTALL), 0);
17920b6d4853SLorenzo Stoakes 	}
17930b6d4853SLorenzo Stoakes 
17940b6d4853SLorenzo Stoakes 	/* Now fault in every odd page. This should trigger fault-around. */
17950b6d4853SLorenzo Stoakes 	for (i = 1; i < 10; i += 2) {
17960b6d4853SLorenzo Stoakes 		char *ptr_p = &ptr[i * page_size];
17970b6d4853SLorenzo Stoakes 
17980b6d4853SLorenzo Stoakes 		ASSERT_TRUE(try_read_buf(ptr_p));
17990b6d4853SLorenzo Stoakes 	}
18000b6d4853SLorenzo Stoakes 
18010b6d4853SLorenzo Stoakes 	/* Finally, ensure that guard regions are intact as expected. */
18020b6d4853SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
18030b6d4853SLorenzo Stoakes 		char *ptr_p = &ptr[i * page_size];
18040b6d4853SLorenzo Stoakes 
18050b6d4853SLorenzo Stoakes 		ASSERT_EQ(try_read_buf(ptr_p), i % 2 != 0);
18060b6d4853SLorenzo Stoakes 	}
18070b6d4853SLorenzo Stoakes 
18080b6d4853SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
18090b6d4853SLorenzo Stoakes }
18100b6d4853SLorenzo Stoakes 
TEST_F(guard_regions,truncation)18110b6d4853SLorenzo Stoakes TEST_F(guard_regions, truncation)
18120b6d4853SLorenzo Stoakes {
18130b6d4853SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
18140b6d4853SLorenzo Stoakes 	char *ptr;
18150b6d4853SLorenzo Stoakes 	int i;
18160b6d4853SLorenzo Stoakes 
18170b6d4853SLorenzo Stoakes 	if (variant->backing == ANON_BACKED)
18180b6d4853SLorenzo Stoakes 		SKIP(return, "Truncation test specific to file-backed");
18190b6d4853SLorenzo Stoakes 
18200b6d4853SLorenzo Stoakes 	ptr = mmap_(self, variant, NULL, 10 * page_size,
18210b6d4853SLorenzo Stoakes 		    PROT_READ | PROT_WRITE, 0, 0);
18220b6d4853SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
18230b6d4853SLorenzo Stoakes 
18240b6d4853SLorenzo Stoakes 	/*
18250b6d4853SLorenzo Stoakes 	 * Establish a pattern in the backing file, just so there is data
18260b6d4853SLorenzo Stoakes 	 * there.
18270b6d4853SLorenzo Stoakes 	 */
18280b6d4853SLorenzo Stoakes 	set_pattern(ptr, 10, page_size);
18290b6d4853SLorenzo Stoakes 
18300b6d4853SLorenzo Stoakes 	/* Now make every even page guarded. */
18310b6d4853SLorenzo Stoakes 	for (i = 0; i < 10; i += 2) {
18320b6d4853SLorenzo Stoakes 		char *ptr_p = &ptr[i * page_size];
18330b6d4853SLorenzo Stoakes 
18340b6d4853SLorenzo Stoakes 		ASSERT_EQ(madvise(ptr_p, page_size, MADV_GUARD_INSTALL), 0);
18350b6d4853SLorenzo Stoakes 	}
18360b6d4853SLorenzo Stoakes 
18370b6d4853SLorenzo Stoakes 	/* Now assert things are as expected. */
18380b6d4853SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
18390b6d4853SLorenzo Stoakes 		char *ptr_p = &ptr[i * page_size];
18400b6d4853SLorenzo Stoakes 
18410b6d4853SLorenzo Stoakes 		ASSERT_EQ(try_read_write_buf(ptr_p), i % 2 != 0);
18420b6d4853SLorenzo Stoakes 	}
18430b6d4853SLorenzo Stoakes 
18440b6d4853SLorenzo Stoakes 	/* Now truncate to actually used size (initialised to 100). */
18450b6d4853SLorenzo Stoakes 	ASSERT_EQ(ftruncate(self->fd, 10 * page_size), 0);
18460b6d4853SLorenzo Stoakes 
18470b6d4853SLorenzo Stoakes 	/* Here the guard regions will remain intact. */
18480b6d4853SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
18490b6d4853SLorenzo Stoakes 		char *ptr_p = &ptr[i * page_size];
18500b6d4853SLorenzo Stoakes 
18510b6d4853SLorenzo Stoakes 		ASSERT_EQ(try_read_write_buf(ptr_p), i % 2 != 0);
18520b6d4853SLorenzo Stoakes 	}
18530b6d4853SLorenzo Stoakes 
18540b6d4853SLorenzo Stoakes 	/* Now truncate to half the size, then truncate again to the full size. */
18550b6d4853SLorenzo Stoakes 	ASSERT_EQ(ftruncate(self->fd, 5 * page_size), 0);
18560b6d4853SLorenzo Stoakes 	ASSERT_EQ(ftruncate(self->fd, 10 * page_size), 0);
18570b6d4853SLorenzo Stoakes 
18580b6d4853SLorenzo Stoakes 	/* Again, guard pages will remain intact. */
18590b6d4853SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
18600b6d4853SLorenzo Stoakes 		char *ptr_p = &ptr[i * page_size];
18610b6d4853SLorenzo Stoakes 
18620b6d4853SLorenzo Stoakes 		ASSERT_EQ(try_read_write_buf(ptr_p), i % 2 != 0);
18630b6d4853SLorenzo Stoakes 	}
18640b6d4853SLorenzo Stoakes 
18650b6d4853SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
18660b6d4853SLorenzo Stoakes }
18670b6d4853SLorenzo Stoakes 
TEST_F(guard_regions,hole_punch)18680b6d4853SLorenzo Stoakes TEST_F(guard_regions, hole_punch)
18690b6d4853SLorenzo Stoakes {
18700b6d4853SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
18710b6d4853SLorenzo Stoakes 	char *ptr;
18720b6d4853SLorenzo Stoakes 	int i;
18730b6d4853SLorenzo Stoakes 
18740b6d4853SLorenzo Stoakes 	if (variant->backing == ANON_BACKED)
18750b6d4853SLorenzo Stoakes 		SKIP(return, "Truncation test specific to file-backed");
18760b6d4853SLorenzo Stoakes 
18770b6d4853SLorenzo Stoakes 	/* Establish pattern in mapping. */
18780b6d4853SLorenzo Stoakes 	ptr = mmap_(self, variant, NULL, 10 * page_size,
18790b6d4853SLorenzo Stoakes 		    PROT_READ | PROT_WRITE, 0, 0);
18800b6d4853SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
18810b6d4853SLorenzo Stoakes 	set_pattern(ptr, 10, page_size);
18820b6d4853SLorenzo Stoakes 
18830b6d4853SLorenzo Stoakes 	/* Install a guard region in the middle of the mapping. */
18840b6d4853SLorenzo Stoakes 	ASSERT_EQ(madvise(&ptr[3 * page_size], 4 * page_size,
18850b6d4853SLorenzo Stoakes 			  MADV_GUARD_INSTALL), 0);
18860b6d4853SLorenzo Stoakes 
18870b6d4853SLorenzo Stoakes 	/*
18880b6d4853SLorenzo Stoakes 	 * The buffer will now be:
18890b6d4853SLorenzo Stoakes 	 *
18900b6d4853SLorenzo Stoakes 	 * 0123456789
18910b6d4853SLorenzo Stoakes 	 * ***xxxx***
18920b6d4853SLorenzo Stoakes 	 *
18930b6d4853SLorenzo Stoakes 	 * Where * is data and x is the guard region.
18940b6d4853SLorenzo Stoakes 	 */
18950b6d4853SLorenzo Stoakes 
18960b6d4853SLorenzo Stoakes 	/* Ensure established. */
18970b6d4853SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
18980b6d4853SLorenzo Stoakes 		char *ptr_p = &ptr[i * page_size];
18990b6d4853SLorenzo Stoakes 
19000b6d4853SLorenzo Stoakes 		ASSERT_EQ(try_read_buf(ptr_p), i < 3 || i >= 7);
19010b6d4853SLorenzo Stoakes 	}
19020b6d4853SLorenzo Stoakes 
19030b6d4853SLorenzo Stoakes 	/* Now hole punch the guarded region. */
19040b6d4853SLorenzo Stoakes 	ASSERT_EQ(madvise(&ptr[3 * page_size], 4 * page_size,
19050b6d4853SLorenzo Stoakes 			  MADV_REMOVE), 0);
19060b6d4853SLorenzo Stoakes 
19070b6d4853SLorenzo Stoakes 	/* Ensure guard regions remain. */
19080b6d4853SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
19090b6d4853SLorenzo Stoakes 		char *ptr_p = &ptr[i * page_size];
19100b6d4853SLorenzo Stoakes 
19110b6d4853SLorenzo Stoakes 		ASSERT_EQ(try_read_buf(ptr_p), i < 3 || i >= 7);
19120b6d4853SLorenzo Stoakes 	}
19130b6d4853SLorenzo Stoakes 
19140b6d4853SLorenzo Stoakes 	/* Now remove guard region throughout. */
19150b6d4853SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_REMOVE), 0);
19160b6d4853SLorenzo Stoakes 
19170b6d4853SLorenzo Stoakes 	/* Check that the pattern exists in non-hole punched region. */
19180b6d4853SLorenzo Stoakes 	ASSERT_TRUE(check_pattern(ptr, 3, page_size));
19190b6d4853SLorenzo Stoakes 	/* Check that hole punched region is zeroed. */
19200b6d4853SLorenzo Stoakes 	ASSERT_TRUE(is_buf_eq(&ptr[3 * page_size], 4 * page_size, '\0'));
19210b6d4853SLorenzo Stoakes 	/* Check that the pattern exists in the remainder of the file. */
19220b6d4853SLorenzo Stoakes 	ASSERT_TRUE(check_pattern_offset(ptr, 3, page_size, 7));
19230b6d4853SLorenzo Stoakes 
19240b6d4853SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
19250b6d4853SLorenzo Stoakes }
19260b6d4853SLorenzo Stoakes 
19270b6d4853SLorenzo Stoakes /*
19280b6d4853SLorenzo Stoakes  * Ensure that a memfd works correctly with guard regions, that we can write
19290b6d4853SLorenzo Stoakes  * seal it then open the mapping read-only and still establish guard regions
19300b6d4853SLorenzo Stoakes  * within, remove those guard regions and have everything work correctly.
19310b6d4853SLorenzo Stoakes  */
TEST_F(guard_regions,memfd_write_seal)19320b6d4853SLorenzo Stoakes TEST_F(guard_regions, memfd_write_seal)
19330b6d4853SLorenzo Stoakes {
19340b6d4853SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
19350b6d4853SLorenzo Stoakes 	char *ptr;
19360b6d4853SLorenzo Stoakes 	int i;
19370b6d4853SLorenzo Stoakes 
19380b6d4853SLorenzo Stoakes 	if (variant->backing != SHMEM_BACKED)
19390b6d4853SLorenzo Stoakes 		SKIP(return, "memfd write seal test specific to shmem");
19400b6d4853SLorenzo Stoakes 
19410b6d4853SLorenzo Stoakes 	/* OK, we need a memfd, so close existing one. */
19420b6d4853SLorenzo Stoakes 	ASSERT_EQ(close(self->fd), 0);
19430b6d4853SLorenzo Stoakes 
19440b6d4853SLorenzo Stoakes 	/* Create and truncate memfd. */
19450b6d4853SLorenzo Stoakes 	self->fd = memfd_create("guard_regions_memfd_seals_test",
19460b6d4853SLorenzo Stoakes 				MFD_ALLOW_SEALING);
19470b6d4853SLorenzo Stoakes 	ASSERT_NE(self->fd, -1);
19480b6d4853SLorenzo Stoakes 	ASSERT_EQ(ftruncate(self->fd, 10 * page_size), 0);
19490b6d4853SLorenzo Stoakes 
19500b6d4853SLorenzo Stoakes 	/* Map, set pattern, unmap. */
19510b6d4853SLorenzo Stoakes 	ptr = mmap_(self, variant, NULL, 10 * page_size, PROT_READ | PROT_WRITE, 0, 0);
19520b6d4853SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
19530b6d4853SLorenzo Stoakes 	set_pattern(ptr, 10, page_size);
19540b6d4853SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
19550b6d4853SLorenzo Stoakes 
19560b6d4853SLorenzo Stoakes 	/* Write-seal the memfd. */
19570b6d4853SLorenzo Stoakes 	ASSERT_EQ(fcntl(self->fd, F_ADD_SEALS, F_SEAL_WRITE), 0);
19580b6d4853SLorenzo Stoakes 
19590b6d4853SLorenzo Stoakes 	/* Now map the memfd readonly. */
19600b6d4853SLorenzo Stoakes 	ptr = mmap_(self, variant, NULL, 10 * page_size, PROT_READ, 0, 0);
19610b6d4853SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
19620b6d4853SLorenzo Stoakes 
19630b6d4853SLorenzo Stoakes 	/* Ensure pattern is as expected. */
19640b6d4853SLorenzo Stoakes 	ASSERT_TRUE(check_pattern(ptr, 10, page_size));
19650b6d4853SLorenzo Stoakes 
19660b6d4853SLorenzo Stoakes 	/* Now make every even page guarded. */
19670b6d4853SLorenzo Stoakes 	for (i = 0; i < 10; i += 2) {
19680b6d4853SLorenzo Stoakes 		char *ptr_p = &ptr[i * page_size];
19690b6d4853SLorenzo Stoakes 
19700b6d4853SLorenzo Stoakes 		ASSERT_EQ(madvise(ptr_p, page_size, MADV_GUARD_INSTALL), 0);
19710b6d4853SLorenzo Stoakes 	}
19720b6d4853SLorenzo Stoakes 
19730b6d4853SLorenzo Stoakes 	/* Now assert things are as expected. */
19740b6d4853SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
19750b6d4853SLorenzo Stoakes 		char *ptr_p = &ptr[i * page_size];
19760b6d4853SLorenzo Stoakes 
19770b6d4853SLorenzo Stoakes 		ASSERT_EQ(try_read_buf(ptr_p), i % 2 != 0);
19780b6d4853SLorenzo Stoakes 	}
19790b6d4853SLorenzo Stoakes 
19800b6d4853SLorenzo Stoakes 	/* Now remove guard regions. */
19810b6d4853SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_REMOVE), 0);
19820b6d4853SLorenzo Stoakes 
19830b6d4853SLorenzo Stoakes 	/* Ensure pattern is as expected. */
19840b6d4853SLorenzo Stoakes 	ASSERT_TRUE(check_pattern(ptr, 10, page_size));
19850b6d4853SLorenzo Stoakes 
19860b6d4853SLorenzo Stoakes 	/* Ensure write seal intact. */
19870b6d4853SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
19880b6d4853SLorenzo Stoakes 		char *ptr_p = &ptr[i * page_size];
19890b6d4853SLorenzo Stoakes 
19900b6d4853SLorenzo Stoakes 		ASSERT_FALSE(try_write_buf(ptr_p));
19910b6d4853SLorenzo Stoakes 	}
19920b6d4853SLorenzo Stoakes 
19930b6d4853SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
19940b6d4853SLorenzo Stoakes }
19950b6d4853SLorenzo Stoakes 
19960b6d4853SLorenzo Stoakes 
19970b6d4853SLorenzo Stoakes /*
19980b6d4853SLorenzo Stoakes  * Since we are now permitted to establish guard regions in read-only anonymous
19990b6d4853SLorenzo Stoakes  * mappings, for the sake of thoroughness, though it probably has no practical
20000b6d4853SLorenzo Stoakes  * use, test that guard regions function with a mapping to the anonymous zero
20010b6d4853SLorenzo Stoakes  * page.
20020b6d4853SLorenzo Stoakes  */
TEST_F(guard_regions,anon_zeropage)20030b6d4853SLorenzo Stoakes TEST_F(guard_regions, anon_zeropage)
20040b6d4853SLorenzo Stoakes {
20050b6d4853SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
20060b6d4853SLorenzo Stoakes 	char *ptr;
20070b6d4853SLorenzo Stoakes 	int i;
20080b6d4853SLorenzo Stoakes 
20090b6d4853SLorenzo Stoakes 	if (!is_anon_backed(variant))
20100b6d4853SLorenzo Stoakes 		SKIP(return, "anon zero page test specific to anon/shmem");
20110b6d4853SLorenzo Stoakes 
20120b6d4853SLorenzo Stoakes 	/* Obtain a read-only i.e. anon zero page mapping. */
20130b6d4853SLorenzo Stoakes 	ptr = mmap_(self, variant, NULL, 10 * page_size, PROT_READ, 0, 0);
20140b6d4853SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
20150b6d4853SLorenzo Stoakes 
20160b6d4853SLorenzo Stoakes 	/* Now make every even page guarded. */
20170b6d4853SLorenzo Stoakes 	for (i = 0; i < 10; i += 2) {
20180b6d4853SLorenzo Stoakes 		char *ptr_p = &ptr[i * page_size];
20190b6d4853SLorenzo Stoakes 
20200b6d4853SLorenzo Stoakes 		ASSERT_EQ(madvise(ptr_p, page_size, MADV_GUARD_INSTALL), 0);
20210b6d4853SLorenzo Stoakes 	}
20220b6d4853SLorenzo Stoakes 
20230b6d4853SLorenzo Stoakes 	/* Now assert things are as expected. */
20240b6d4853SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
20250b6d4853SLorenzo Stoakes 		char *ptr_p = &ptr[i * page_size];
20260b6d4853SLorenzo Stoakes 
20270b6d4853SLorenzo Stoakes 		ASSERT_EQ(try_read_buf(ptr_p), i % 2 != 0);
20280b6d4853SLorenzo Stoakes 	}
20290b6d4853SLorenzo Stoakes 
20300b6d4853SLorenzo Stoakes 	/* Now remove all guard regions. */
20310b6d4853SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_REMOVE), 0);
2032f3b92176SLorenzo Stoakes 
2033f3b92176SLorenzo Stoakes 	/* Now assert things are as expected. */
2034f3b92176SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
2035f3b92176SLorenzo Stoakes 		char *ptr_p = &ptr[i * page_size];
2036f3b92176SLorenzo Stoakes 
2037f3b92176SLorenzo Stoakes 		ASSERT_TRUE(try_read_buf(ptr_p));
2038f3b92176SLorenzo Stoakes 	}
2039f3b92176SLorenzo Stoakes 
2040f3b92176SLorenzo Stoakes 	/* Ensure zero page...*/
2041f3b92176SLorenzo Stoakes 	ASSERT_TRUE(is_buf_eq(ptr, 10 * page_size, '\0'));
2042f3b92176SLorenzo Stoakes 
2043f3b92176SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
2044f3b92176SLorenzo Stoakes }
2045f3b92176SLorenzo Stoakes 
2046f3b92176SLorenzo Stoakes /*
2047f3b92176SLorenzo Stoakes  * Assert that /proc/$pid/pagemap correctly identifies guard region ranges.
2048f3b92176SLorenzo Stoakes  */
TEST_F(guard_regions,pagemap)2049f3b92176SLorenzo Stoakes TEST_F(guard_regions, pagemap)
2050f3b92176SLorenzo Stoakes {
2051f3b92176SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
2052f3b92176SLorenzo Stoakes 	int proc_fd;
2053f3b92176SLorenzo Stoakes 	char *ptr;
2054f3b92176SLorenzo Stoakes 	int i;
2055f3b92176SLorenzo Stoakes 
2056f3b92176SLorenzo Stoakes 	proc_fd = open("/proc/self/pagemap", O_RDONLY);
2057f3b92176SLorenzo Stoakes 	ASSERT_NE(proc_fd, -1);
2058f3b92176SLorenzo Stoakes 
2059f3b92176SLorenzo Stoakes 	ptr = mmap_(self, variant, NULL, 10 * page_size,
2060f3b92176SLorenzo Stoakes 		    PROT_READ | PROT_WRITE, 0, 0);
2061f3b92176SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
2062f3b92176SLorenzo Stoakes 
2063f3b92176SLorenzo Stoakes 	/* Read from pagemap, and assert no guard regions are detected. */
2064f3b92176SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
2065f3b92176SLorenzo Stoakes 		char *ptr_p = &ptr[i * page_size];
2066f3b92176SLorenzo Stoakes 		unsigned long entry = pagemap_get_entry(proc_fd, ptr_p);
2067f3b92176SLorenzo Stoakes 		unsigned long masked = entry & PM_GUARD_REGION;
2068f3b92176SLorenzo Stoakes 
2069f3b92176SLorenzo Stoakes 		ASSERT_EQ(masked, 0);
2070f3b92176SLorenzo Stoakes 	}
2071f3b92176SLorenzo Stoakes 
2072f3b92176SLorenzo Stoakes 	/* Install a guard region in every other page. */
2073f3b92176SLorenzo Stoakes 	for (i = 0; i < 10; i += 2) {
2074f3b92176SLorenzo Stoakes 		char *ptr_p = &ptr[i * page_size];
2075f3b92176SLorenzo Stoakes 
2076f3b92176SLorenzo Stoakes 		ASSERT_EQ(madvise(ptr_p, page_size, MADV_GUARD_INSTALL), 0);
2077f3b92176SLorenzo Stoakes 	}
2078ce1c0824SLorenzo Stoakes 
2079 	/* Re-read from pagemap, and assert guard regions are detected. */
2080 	for (i = 0; i < 10; i++) {
2081 		char *ptr_p = &ptr[i * page_size];
2082 		unsigned long entry = pagemap_get_entry(proc_fd, ptr_p);
2083 		unsigned long masked = entry & PM_GUARD_REGION;
2084 
2085 		ASSERT_EQ(masked, i % 2 == 0 ? PM_GUARD_REGION : 0);
2086 	}
2087 
2088 	ASSERT_EQ(close(proc_fd), 0);
2089 	ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
2090 }
2091 
2092 /*
2093  * Assert that PAGEMAP_SCAN correctly reports guard region ranges.
2094  */
TEST_F(guard_regions,pagemap_scan)2095 TEST_F(guard_regions, pagemap_scan)
2096 {
2097 	const unsigned long page_size = self->page_size;
2098 	struct page_region pm_regs[10];
2099 	struct pm_scan_arg pm_scan_args = {
2100 		.size = sizeof(struct pm_scan_arg),
2101 		.category_anyof_mask = PAGE_IS_GUARD,
2102 		.return_mask = PAGE_IS_GUARD,
2103 		.vec = (long)&pm_regs,
2104 		.vec_len = ARRAY_SIZE(pm_regs),
2105 	};
2106 	int proc_fd, i;
2107 	char *ptr;
2108 
2109 	proc_fd = open("/proc/self/pagemap", O_RDONLY);
2110 	ASSERT_NE(proc_fd, -1);
2111 
2112 	ptr = mmap_(self, variant, NULL, 10 * page_size,
2113 		    PROT_READ | PROT_WRITE, 0, 0);
2114 	ASSERT_NE(ptr, MAP_FAILED);
2115 
2116 	pm_scan_args.start = (long)ptr;
2117 	pm_scan_args.end = (long)ptr + 10 * page_size;
2118 	ASSERT_EQ(ioctl(proc_fd, PAGEMAP_SCAN, &pm_scan_args), 0);
2119 	ASSERT_EQ(pm_scan_args.walk_end, (long)ptr + 10 * page_size);
2120 
2121 	/* Install a guard region in every other page. */
2122 	for (i = 0; i < 10; i += 2) {
2123 		char *ptr_p = &ptr[i * page_size];
2124 
2125 		ASSERT_EQ(syscall(__NR_madvise, ptr_p, page_size, MADV_GUARD_INSTALL), 0);
2126 	}
2127 
2128 	/*
2129 	 * Assert ioctl() returns the count of located regions, where each
2130 	 * region spans every other page within the range of 10 pages.
2131 	 */
2132 	ASSERT_EQ(ioctl(proc_fd, PAGEMAP_SCAN, &pm_scan_args), 5);
2133 	ASSERT_EQ(pm_scan_args.walk_end, (long)ptr + 10 * page_size);
2134 
2135 	/* Re-read from pagemap, and assert guard regions are detected. */
2136 	for (i = 0; i < 5; i++) {
2137 		long ptr_p = (long)&ptr[2 * i * page_size];
2138 
2139 		ASSERT_EQ(pm_regs[i].start, ptr_p);
2140 		ASSERT_EQ(pm_regs[i].end, ptr_p + page_size);
2141 		ASSERT_EQ(pm_regs[i].categories, PAGE_IS_GUARD);
2142 	}
2143 
2144 	ASSERT_EQ(close(proc_fd), 0);
2145 	ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
2146 }
2147 
2148 TEST_HARNESS_MAIN
2149