xref: /linux/tools/testing/selftests/mm/guard-pages.c (revision df00ded23a6b4df888237333b1f86067d24113b2)
1876320d7SLorenzo Stoakes // SPDX-License-Identifier: GPL-2.0-or-later
2876320d7SLorenzo Stoakes 
3876320d7SLorenzo Stoakes #define _GNU_SOURCE
4876320d7SLorenzo Stoakes #include "../kselftest_harness.h"
5876320d7SLorenzo Stoakes #include <asm-generic/mman.h> /* Force the import of the tools version. */
6876320d7SLorenzo Stoakes #include <assert.h>
7876320d7SLorenzo Stoakes #include <errno.h>
8876320d7SLorenzo Stoakes #include <fcntl.h>
9876320d7SLorenzo Stoakes #include <linux/userfaultfd.h>
10876320d7SLorenzo Stoakes #include <setjmp.h>
11876320d7SLorenzo Stoakes #include <signal.h>
12876320d7SLorenzo Stoakes #include <stdbool.h>
13876320d7SLorenzo Stoakes #include <stdio.h>
14876320d7SLorenzo Stoakes #include <stdlib.h>
15876320d7SLorenzo Stoakes #include <string.h>
16876320d7SLorenzo Stoakes #include <sys/ioctl.h>
17876320d7SLorenzo Stoakes #include <sys/mman.h>
18876320d7SLorenzo Stoakes #include <sys/syscall.h>
19876320d7SLorenzo Stoakes #include <sys/uio.h>
20876320d7SLorenzo Stoakes #include <unistd.h>
21876320d7SLorenzo Stoakes 
22*62d648c4SLorenzo Stoakes #include "../pidfd/pidfd.h"
23*62d648c4SLorenzo Stoakes 
24876320d7SLorenzo Stoakes /*
25876320d7SLorenzo Stoakes  * Ignore the checkpatch warning, as per the C99 standard, section 7.14.1.1:
26876320d7SLorenzo Stoakes  *
27876320d7SLorenzo Stoakes  * "If the signal occurs other than as the result of calling the abort or raise
28876320d7SLorenzo Stoakes  *  function, the behavior is undefined if the signal handler refers to any
29876320d7SLorenzo Stoakes  *  object with static storage duration other than by assigning a value to an
30876320d7SLorenzo Stoakes  *  object declared as volatile sig_atomic_t"
31876320d7SLorenzo Stoakes  */
32876320d7SLorenzo Stoakes static volatile sig_atomic_t signal_jump_set;
33876320d7SLorenzo Stoakes static sigjmp_buf signal_jmp_buf;
34876320d7SLorenzo Stoakes 
35876320d7SLorenzo Stoakes /*
36876320d7SLorenzo Stoakes  * Ignore the checkpatch warning, we must read from x but don't want to do
37876320d7SLorenzo Stoakes  * anything with it in order to trigger a read page fault. We therefore must use
38876320d7SLorenzo Stoakes  * volatile to stop the compiler from optimising this away.
39876320d7SLorenzo Stoakes  */
40876320d7SLorenzo Stoakes #define FORCE_READ(x) (*(volatile typeof(x) *)x)
41876320d7SLorenzo Stoakes 
42876320d7SLorenzo Stoakes static int userfaultfd(int flags)
43876320d7SLorenzo Stoakes {
44876320d7SLorenzo Stoakes 	return syscall(SYS_userfaultfd, flags);
45876320d7SLorenzo Stoakes }
46876320d7SLorenzo Stoakes 
47876320d7SLorenzo Stoakes static void handle_fatal(int c)
48876320d7SLorenzo Stoakes {
49876320d7SLorenzo Stoakes 	if (!signal_jump_set)
50876320d7SLorenzo Stoakes 		return;
51876320d7SLorenzo Stoakes 
52876320d7SLorenzo Stoakes 	siglongjmp(signal_jmp_buf, c);
53876320d7SLorenzo Stoakes }
54876320d7SLorenzo Stoakes 
5519b65ffaSLorenzo Stoakes static ssize_t sys_process_madvise(int pidfd, const struct iovec *iovec,
5619b65ffaSLorenzo Stoakes 				   size_t n, int advice, unsigned int flags)
5719b65ffaSLorenzo Stoakes {
5819b65ffaSLorenzo Stoakes 	return syscall(__NR_process_madvise, pidfd, iovec, n, advice, flags);
5919b65ffaSLorenzo Stoakes }
6019b65ffaSLorenzo Stoakes 
61876320d7SLorenzo Stoakes /*
62876320d7SLorenzo Stoakes  * Enable our signal catcher and try to read/write the specified buffer. The
63876320d7SLorenzo Stoakes  * return value indicates whether the read/write succeeds without a fatal
64876320d7SLorenzo Stoakes  * signal.
65876320d7SLorenzo Stoakes  */
66876320d7SLorenzo Stoakes static bool try_access_buf(char *ptr, bool write)
67876320d7SLorenzo Stoakes {
68876320d7SLorenzo Stoakes 	bool failed;
69876320d7SLorenzo Stoakes 
70876320d7SLorenzo Stoakes 	/* Tell signal handler to jump back here on fatal signal. */
71876320d7SLorenzo Stoakes 	signal_jump_set = true;
72876320d7SLorenzo Stoakes 	/* If a fatal signal arose, we will jump back here and failed is set. */
73876320d7SLorenzo Stoakes 	failed = sigsetjmp(signal_jmp_buf, 0) != 0;
74876320d7SLorenzo Stoakes 
75876320d7SLorenzo Stoakes 	if (!failed) {
76876320d7SLorenzo Stoakes 		if (write)
77876320d7SLorenzo Stoakes 			*ptr = 'x';
78876320d7SLorenzo Stoakes 		else
79876320d7SLorenzo Stoakes 			FORCE_READ(ptr);
80876320d7SLorenzo Stoakes 	}
81876320d7SLorenzo Stoakes 
82876320d7SLorenzo Stoakes 	signal_jump_set = false;
83876320d7SLorenzo Stoakes 	return !failed;
84876320d7SLorenzo Stoakes }
85876320d7SLorenzo Stoakes 
86876320d7SLorenzo Stoakes /* Try and read from a buffer, return true if no fatal signal. */
87876320d7SLorenzo Stoakes static bool try_read_buf(char *ptr)
88876320d7SLorenzo Stoakes {
89876320d7SLorenzo Stoakes 	return try_access_buf(ptr, false);
90876320d7SLorenzo Stoakes }
91876320d7SLorenzo Stoakes 
92876320d7SLorenzo Stoakes /* Try and write to a buffer, return true if no fatal signal. */
93876320d7SLorenzo Stoakes static bool try_write_buf(char *ptr)
94876320d7SLorenzo Stoakes {
95876320d7SLorenzo Stoakes 	return try_access_buf(ptr, true);
96876320d7SLorenzo Stoakes }
97876320d7SLorenzo Stoakes 
98876320d7SLorenzo Stoakes /*
99876320d7SLorenzo Stoakes  * Try and BOTH read from AND write to a buffer, return true if BOTH operations
100876320d7SLorenzo Stoakes  * succeed.
101876320d7SLorenzo Stoakes  */
102876320d7SLorenzo Stoakes static bool try_read_write_buf(char *ptr)
103876320d7SLorenzo Stoakes {
104876320d7SLorenzo Stoakes 	return try_read_buf(ptr) && try_write_buf(ptr);
105876320d7SLorenzo Stoakes }
106876320d7SLorenzo Stoakes 
107876320d7SLorenzo Stoakes FIXTURE(guard_pages)
108876320d7SLorenzo Stoakes {
109876320d7SLorenzo Stoakes 	unsigned long page_size;
110876320d7SLorenzo Stoakes };
111876320d7SLorenzo Stoakes 
112876320d7SLorenzo Stoakes FIXTURE_SETUP(guard_pages)
113876320d7SLorenzo Stoakes {
114876320d7SLorenzo Stoakes 	struct sigaction act = {
115876320d7SLorenzo Stoakes 		.sa_handler = &handle_fatal,
116876320d7SLorenzo Stoakes 		.sa_flags = SA_NODEFER,
117876320d7SLorenzo Stoakes 	};
118876320d7SLorenzo Stoakes 
119876320d7SLorenzo Stoakes 	sigemptyset(&act.sa_mask);
120876320d7SLorenzo Stoakes 	if (sigaction(SIGSEGV, &act, NULL))
121876320d7SLorenzo Stoakes 		ksft_exit_fail_perror("sigaction");
122876320d7SLorenzo Stoakes 
123876320d7SLorenzo Stoakes 	self->page_size = (unsigned long)sysconf(_SC_PAGESIZE);
124876320d7SLorenzo Stoakes };
125876320d7SLorenzo Stoakes 
126876320d7SLorenzo Stoakes FIXTURE_TEARDOWN(guard_pages)
127876320d7SLorenzo Stoakes {
128876320d7SLorenzo Stoakes 	struct sigaction act = {
129876320d7SLorenzo Stoakes 		.sa_handler = SIG_DFL,
130876320d7SLorenzo Stoakes 		.sa_flags = SA_NODEFER,
131876320d7SLorenzo Stoakes 	};
132876320d7SLorenzo Stoakes 
133876320d7SLorenzo Stoakes 	sigemptyset(&act.sa_mask);
134876320d7SLorenzo Stoakes 	sigaction(SIGSEGV, &act, NULL);
135876320d7SLorenzo Stoakes }
136876320d7SLorenzo Stoakes 
137876320d7SLorenzo Stoakes TEST_F(guard_pages, basic)
138876320d7SLorenzo Stoakes {
139876320d7SLorenzo Stoakes 	const unsigned long NUM_PAGES = 10;
140876320d7SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
141876320d7SLorenzo Stoakes 	char *ptr;
142876320d7SLorenzo Stoakes 	int i;
143876320d7SLorenzo Stoakes 
144876320d7SLorenzo Stoakes 	ptr = mmap(NULL, NUM_PAGES * page_size, PROT_READ | PROT_WRITE,
145876320d7SLorenzo Stoakes 		   MAP_PRIVATE | MAP_ANON, -1, 0);
146876320d7SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
147876320d7SLorenzo Stoakes 
148876320d7SLorenzo Stoakes 	/* Trivially assert we can touch the first page. */
149876320d7SLorenzo Stoakes 	ASSERT_TRUE(try_read_write_buf(ptr));
150876320d7SLorenzo Stoakes 
151876320d7SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, page_size, MADV_GUARD_INSTALL), 0);
152876320d7SLorenzo Stoakes 
153876320d7SLorenzo Stoakes 	/* Establish that 1st page SIGSEGV's. */
154876320d7SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(ptr));
155876320d7SLorenzo Stoakes 
156876320d7SLorenzo Stoakes 	/* Ensure we can touch everything else.*/
157876320d7SLorenzo Stoakes 	for (i = 1; i < NUM_PAGES; i++) {
158876320d7SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
159876320d7SLorenzo Stoakes 
160876320d7SLorenzo Stoakes 		ASSERT_TRUE(try_read_write_buf(curr));
161876320d7SLorenzo Stoakes 	}
162876320d7SLorenzo Stoakes 
163876320d7SLorenzo Stoakes 	/* Establish a guard page at the end of the mapping. */
164876320d7SLorenzo Stoakes 	ASSERT_EQ(madvise(&ptr[(NUM_PAGES - 1) * page_size], page_size,
165876320d7SLorenzo Stoakes 			  MADV_GUARD_INSTALL), 0);
166876320d7SLorenzo Stoakes 
167876320d7SLorenzo Stoakes 	/* Check that both guard pages result in SIGSEGV. */
168876320d7SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(ptr));
169876320d7SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(&ptr[(NUM_PAGES - 1) * page_size]));
170876320d7SLorenzo Stoakes 
171876320d7SLorenzo Stoakes 	/* Remove the first guard page. */
172876320d7SLorenzo Stoakes 	ASSERT_FALSE(madvise(ptr, page_size, MADV_GUARD_REMOVE));
173876320d7SLorenzo Stoakes 
174876320d7SLorenzo Stoakes 	/* Make sure we can touch it. */
175876320d7SLorenzo Stoakes 	ASSERT_TRUE(try_read_write_buf(ptr));
176876320d7SLorenzo Stoakes 
177876320d7SLorenzo Stoakes 	/* Remove the last guard page. */
178876320d7SLorenzo Stoakes 	ASSERT_FALSE(madvise(&ptr[(NUM_PAGES - 1) * page_size], page_size,
179876320d7SLorenzo Stoakes 			     MADV_GUARD_REMOVE));
180876320d7SLorenzo Stoakes 
181876320d7SLorenzo Stoakes 	/* Make sure we can touch it. */
182876320d7SLorenzo Stoakes 	ASSERT_TRUE(try_read_write_buf(&ptr[(NUM_PAGES - 1) * page_size]));
183876320d7SLorenzo Stoakes 
184876320d7SLorenzo Stoakes 	/*
185876320d7SLorenzo Stoakes 	 *  Test setting a _range_ of pages, namely the first 3. The first of
186876320d7SLorenzo Stoakes 	 *  these be faulted in, so this also tests that we can install guard
187876320d7SLorenzo Stoakes 	 *  pages over backed pages.
188876320d7SLorenzo Stoakes 	 */
189876320d7SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 3 * page_size, MADV_GUARD_INSTALL), 0);
190876320d7SLorenzo Stoakes 
191876320d7SLorenzo Stoakes 	/* Make sure they are all guard pages. */
192876320d7SLorenzo Stoakes 	for (i = 0; i < 3; i++) {
193876320d7SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
194876320d7SLorenzo Stoakes 
195876320d7SLorenzo Stoakes 		ASSERT_FALSE(try_read_write_buf(curr));
196876320d7SLorenzo Stoakes 	}
197876320d7SLorenzo Stoakes 
198876320d7SLorenzo Stoakes 	/* Make sure the rest are not. */
199876320d7SLorenzo Stoakes 	for (i = 3; i < NUM_PAGES; i++) {
200876320d7SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
201876320d7SLorenzo Stoakes 
202876320d7SLorenzo Stoakes 		ASSERT_TRUE(try_read_write_buf(curr));
203876320d7SLorenzo Stoakes 	}
204876320d7SLorenzo Stoakes 
205876320d7SLorenzo Stoakes 	/* Remove guard pages. */
206876320d7SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, NUM_PAGES * page_size, MADV_GUARD_REMOVE), 0);
207876320d7SLorenzo Stoakes 
208876320d7SLorenzo Stoakes 	/* Now make sure we can touch everything. */
209876320d7SLorenzo Stoakes 	for (i = 0; i < NUM_PAGES; i++) {
210876320d7SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
211876320d7SLorenzo Stoakes 
212876320d7SLorenzo Stoakes 		ASSERT_TRUE(try_read_write_buf(curr));
213876320d7SLorenzo Stoakes 	}
214876320d7SLorenzo Stoakes 
215876320d7SLorenzo Stoakes 	/*
216876320d7SLorenzo Stoakes 	 * Now remove all guard pages, make sure we don't remove existing
217876320d7SLorenzo Stoakes 	 * entries.
218876320d7SLorenzo Stoakes 	 */
219876320d7SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, NUM_PAGES * page_size, MADV_GUARD_REMOVE), 0);
220876320d7SLorenzo Stoakes 
221876320d7SLorenzo Stoakes 	for (i = 0; i < NUM_PAGES * page_size; i += page_size) {
222876320d7SLorenzo Stoakes 		char chr = ptr[i];
223876320d7SLorenzo Stoakes 
224876320d7SLorenzo Stoakes 		ASSERT_EQ(chr, 'x');
225876320d7SLorenzo Stoakes 	}
226876320d7SLorenzo Stoakes 
227876320d7SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr, NUM_PAGES * page_size), 0);
228876320d7SLorenzo Stoakes }
229876320d7SLorenzo Stoakes 
230876320d7SLorenzo Stoakes /* Assert that operations applied across multiple VMAs work as expected. */
231876320d7SLorenzo Stoakes TEST_F(guard_pages, multi_vma)
232876320d7SLorenzo Stoakes {
233876320d7SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
234876320d7SLorenzo Stoakes 	char *ptr_region, *ptr, *ptr1, *ptr2, *ptr3;
235876320d7SLorenzo Stoakes 	int i;
236876320d7SLorenzo Stoakes 
237876320d7SLorenzo Stoakes 	/* Reserve a 100 page region over which we can install VMAs. */
238876320d7SLorenzo Stoakes 	ptr_region = mmap(NULL, 100 * page_size, PROT_NONE,
239876320d7SLorenzo Stoakes 			  MAP_ANON | MAP_PRIVATE, -1, 0);
240876320d7SLorenzo Stoakes 	ASSERT_NE(ptr_region, MAP_FAILED);
241876320d7SLorenzo Stoakes 
242876320d7SLorenzo Stoakes 	/* Place a VMA of 10 pages size at the start of the region. */
243876320d7SLorenzo Stoakes 	ptr1 = mmap(ptr_region, 10 * page_size, PROT_READ | PROT_WRITE,
244876320d7SLorenzo Stoakes 		    MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
245876320d7SLorenzo Stoakes 	ASSERT_NE(ptr1, MAP_FAILED);
246876320d7SLorenzo Stoakes 
247876320d7SLorenzo Stoakes 	/* Place a VMA of 5 pages size 50 pages into the region. */
248876320d7SLorenzo Stoakes 	ptr2 = mmap(&ptr_region[50 * page_size], 5 * page_size,
249876320d7SLorenzo Stoakes 		    PROT_READ | PROT_WRITE,
250876320d7SLorenzo Stoakes 		    MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
251876320d7SLorenzo Stoakes 	ASSERT_NE(ptr2, MAP_FAILED);
252876320d7SLorenzo Stoakes 
253876320d7SLorenzo Stoakes 	/* Place a VMA of 20 pages size at the end of the region. */
254876320d7SLorenzo Stoakes 	ptr3 = mmap(&ptr_region[80 * page_size], 20 * page_size,
255876320d7SLorenzo Stoakes 		    PROT_READ | PROT_WRITE,
256876320d7SLorenzo Stoakes 		    MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
257876320d7SLorenzo Stoakes 	ASSERT_NE(ptr3, MAP_FAILED);
258876320d7SLorenzo Stoakes 
259876320d7SLorenzo Stoakes 	/* Unmap gaps. */
260876320d7SLorenzo Stoakes 	ASSERT_EQ(munmap(&ptr_region[10 * page_size], 40 * page_size), 0);
261876320d7SLorenzo Stoakes 	ASSERT_EQ(munmap(&ptr_region[55 * page_size], 25 * page_size), 0);
262876320d7SLorenzo Stoakes 
263876320d7SLorenzo Stoakes 	/*
264876320d7SLorenzo Stoakes 	 * We end up with VMAs like this:
265876320d7SLorenzo Stoakes 	 *
266876320d7SLorenzo Stoakes 	 * 0    10 .. 50   55 .. 80   100
267876320d7SLorenzo Stoakes 	 * [---]      [---]      [---]
268876320d7SLorenzo Stoakes 	 */
269876320d7SLorenzo Stoakes 
270876320d7SLorenzo Stoakes 	/*
271876320d7SLorenzo Stoakes 	 * Now mark the whole range as guard pages and make sure all VMAs are as
272876320d7SLorenzo Stoakes 	 * such.
273876320d7SLorenzo Stoakes 	 */
274876320d7SLorenzo Stoakes 
275876320d7SLorenzo Stoakes 	/*
276876320d7SLorenzo Stoakes 	 * madvise() is certifiable and lets you perform operations over gaps,
277876320d7SLorenzo Stoakes 	 * everything works, but it indicates an error and errno is set to
278876320d7SLorenzo Stoakes 	 * -ENOMEM. Also if anything runs out of memory it is set to
279876320d7SLorenzo Stoakes 	 * -ENOMEM. You are meant to guess which is which.
280876320d7SLorenzo Stoakes 	 */
281876320d7SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr_region, 100 * page_size, MADV_GUARD_INSTALL), -1);
282876320d7SLorenzo Stoakes 	ASSERT_EQ(errno, ENOMEM);
283876320d7SLorenzo Stoakes 
284876320d7SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
285876320d7SLorenzo Stoakes 		char *curr = &ptr1[i * page_size];
286876320d7SLorenzo Stoakes 
287876320d7SLorenzo Stoakes 		ASSERT_FALSE(try_read_write_buf(curr));
288876320d7SLorenzo Stoakes 	}
289876320d7SLorenzo Stoakes 
290876320d7SLorenzo Stoakes 	for (i = 0; i < 5; i++) {
291876320d7SLorenzo Stoakes 		char *curr = &ptr2[i * page_size];
292876320d7SLorenzo Stoakes 
293876320d7SLorenzo Stoakes 		ASSERT_FALSE(try_read_write_buf(curr));
294876320d7SLorenzo Stoakes 	}
295876320d7SLorenzo Stoakes 
296876320d7SLorenzo Stoakes 	for (i = 0; i < 20; i++) {
297876320d7SLorenzo Stoakes 		char *curr = &ptr3[i * page_size];
298876320d7SLorenzo Stoakes 
299876320d7SLorenzo Stoakes 		ASSERT_FALSE(try_read_write_buf(curr));
300876320d7SLorenzo Stoakes 	}
301876320d7SLorenzo Stoakes 
302876320d7SLorenzo Stoakes 	/* Now remove guar pages over range and assert the opposite. */
303876320d7SLorenzo Stoakes 
304876320d7SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr_region, 100 * page_size, MADV_GUARD_REMOVE), -1);
305876320d7SLorenzo Stoakes 	ASSERT_EQ(errno, ENOMEM);
306876320d7SLorenzo Stoakes 
307876320d7SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
308876320d7SLorenzo Stoakes 		char *curr = &ptr1[i * page_size];
309876320d7SLorenzo Stoakes 
310876320d7SLorenzo Stoakes 		ASSERT_TRUE(try_read_write_buf(curr));
311876320d7SLorenzo Stoakes 	}
312876320d7SLorenzo Stoakes 
313876320d7SLorenzo Stoakes 	for (i = 0; i < 5; i++) {
314876320d7SLorenzo Stoakes 		char *curr = &ptr2[i * page_size];
315876320d7SLorenzo Stoakes 
316876320d7SLorenzo Stoakes 		ASSERT_TRUE(try_read_write_buf(curr));
317876320d7SLorenzo Stoakes 	}
318876320d7SLorenzo Stoakes 
319876320d7SLorenzo Stoakes 	for (i = 0; i < 20; i++) {
320876320d7SLorenzo Stoakes 		char *curr = &ptr3[i * page_size];
321876320d7SLorenzo Stoakes 
322876320d7SLorenzo Stoakes 		ASSERT_TRUE(try_read_write_buf(curr));
323876320d7SLorenzo Stoakes 	}
324876320d7SLorenzo Stoakes 
325876320d7SLorenzo Stoakes 	/* Now map incompatible VMAs in the gaps. */
326876320d7SLorenzo Stoakes 	ptr = mmap(&ptr_region[10 * page_size], 40 * page_size,
327876320d7SLorenzo Stoakes 		   PROT_READ | PROT_WRITE | PROT_EXEC,
328876320d7SLorenzo Stoakes 		   MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
329876320d7SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
330876320d7SLorenzo Stoakes 	ptr = mmap(&ptr_region[55 * page_size], 25 * page_size,
331876320d7SLorenzo Stoakes 		   PROT_READ | PROT_WRITE | PROT_EXEC,
332876320d7SLorenzo Stoakes 		   MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
333876320d7SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
334876320d7SLorenzo Stoakes 
335876320d7SLorenzo Stoakes 	/*
336876320d7SLorenzo Stoakes 	 * We end up with VMAs like this:
337876320d7SLorenzo Stoakes 	 *
338876320d7SLorenzo Stoakes 	 * 0    10 .. 50   55 .. 80   100
339876320d7SLorenzo Stoakes 	 * [---][xxxx][---][xxxx][---]
340876320d7SLorenzo Stoakes 	 *
341876320d7SLorenzo Stoakes 	 * Where 'x' signifies VMAs that cannot be merged with those adjacent to
342876320d7SLorenzo Stoakes 	 * them.
343876320d7SLorenzo Stoakes 	 */
344876320d7SLorenzo Stoakes 
345876320d7SLorenzo Stoakes 	/* Multiple VMAs adjacent to one another should result in no error. */
346876320d7SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr_region, 100 * page_size, MADV_GUARD_INSTALL), 0);
347876320d7SLorenzo Stoakes 	for (i = 0; i < 100; i++) {
348876320d7SLorenzo Stoakes 		char *curr = &ptr_region[i * page_size];
349876320d7SLorenzo Stoakes 
350876320d7SLorenzo Stoakes 		ASSERT_FALSE(try_read_write_buf(curr));
351876320d7SLorenzo Stoakes 	}
352876320d7SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr_region, 100 * page_size, MADV_GUARD_REMOVE), 0);
353876320d7SLorenzo Stoakes 	for (i = 0; i < 100; i++) {
354876320d7SLorenzo Stoakes 		char *curr = &ptr_region[i * page_size];
355876320d7SLorenzo Stoakes 
356876320d7SLorenzo Stoakes 		ASSERT_TRUE(try_read_write_buf(curr));
357876320d7SLorenzo Stoakes 	}
358876320d7SLorenzo Stoakes 
359876320d7SLorenzo Stoakes 	/* Cleanup. */
360876320d7SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr_region, 100 * page_size), 0);
361876320d7SLorenzo Stoakes }
362876320d7SLorenzo Stoakes 
363876320d7SLorenzo Stoakes /*
364876320d7SLorenzo Stoakes  * Assert that batched operations performed using process_madvise() work as
365876320d7SLorenzo Stoakes  * expected.
366876320d7SLorenzo Stoakes  */
367876320d7SLorenzo Stoakes TEST_F(guard_pages, process_madvise)
368876320d7SLorenzo Stoakes {
369876320d7SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
370876320d7SLorenzo Stoakes 	char *ptr_region, *ptr1, *ptr2, *ptr3;
371876320d7SLorenzo Stoakes 	ssize_t count;
372876320d7SLorenzo Stoakes 	struct iovec vec[6];
373876320d7SLorenzo Stoakes 
374876320d7SLorenzo Stoakes 	/* Reserve region to map over. */
375876320d7SLorenzo Stoakes 	ptr_region = mmap(NULL, 100 * page_size, PROT_NONE,
376876320d7SLorenzo Stoakes 			  MAP_ANON | MAP_PRIVATE, -1, 0);
377876320d7SLorenzo Stoakes 	ASSERT_NE(ptr_region, MAP_FAILED);
378876320d7SLorenzo Stoakes 
379876320d7SLorenzo Stoakes 	/*
380876320d7SLorenzo Stoakes 	 * 10 pages offset 1 page into reserve region. We MAP_POPULATE so we
381876320d7SLorenzo Stoakes 	 * overwrite existing entries and test this code path against
382876320d7SLorenzo Stoakes 	 * overwriting existing entries.
383876320d7SLorenzo Stoakes 	 */
384876320d7SLorenzo Stoakes 	ptr1 = mmap(&ptr_region[page_size], 10 * page_size,
385876320d7SLorenzo Stoakes 		    PROT_READ | PROT_WRITE,
386876320d7SLorenzo Stoakes 		    MAP_FIXED | MAP_ANON | MAP_PRIVATE | MAP_POPULATE, -1, 0);
387876320d7SLorenzo Stoakes 	ASSERT_NE(ptr1, MAP_FAILED);
388876320d7SLorenzo Stoakes 	/* We want guard markers at start/end of each VMA. */
389876320d7SLorenzo Stoakes 	vec[0].iov_base = ptr1;
390876320d7SLorenzo Stoakes 	vec[0].iov_len = page_size;
391876320d7SLorenzo Stoakes 	vec[1].iov_base = &ptr1[9 * page_size];
392876320d7SLorenzo Stoakes 	vec[1].iov_len = page_size;
393876320d7SLorenzo Stoakes 
394876320d7SLorenzo Stoakes 	/* 5 pages offset 50 pages into reserve region. */
395876320d7SLorenzo Stoakes 	ptr2 = mmap(&ptr_region[50 * page_size], 5 * page_size,
396876320d7SLorenzo Stoakes 		    PROT_READ | PROT_WRITE,
397876320d7SLorenzo Stoakes 		    MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
398876320d7SLorenzo Stoakes 	ASSERT_NE(ptr2, MAP_FAILED);
399876320d7SLorenzo Stoakes 	vec[2].iov_base = ptr2;
400876320d7SLorenzo Stoakes 	vec[2].iov_len = page_size;
401876320d7SLorenzo Stoakes 	vec[3].iov_base = &ptr2[4 * page_size];
402876320d7SLorenzo Stoakes 	vec[3].iov_len = page_size;
403876320d7SLorenzo Stoakes 
404876320d7SLorenzo Stoakes 	/* 20 pages offset 79 pages into reserve region. */
405876320d7SLorenzo Stoakes 	ptr3 = mmap(&ptr_region[79 * page_size], 20 * page_size,
406876320d7SLorenzo Stoakes 		    PROT_READ | PROT_WRITE,
407876320d7SLorenzo Stoakes 		    MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
408876320d7SLorenzo Stoakes 	ASSERT_NE(ptr3, MAP_FAILED);
409876320d7SLorenzo Stoakes 	vec[4].iov_base = ptr3;
410876320d7SLorenzo Stoakes 	vec[4].iov_len = page_size;
411876320d7SLorenzo Stoakes 	vec[5].iov_base = &ptr3[19 * page_size];
412876320d7SLorenzo Stoakes 	vec[5].iov_len = page_size;
413876320d7SLorenzo Stoakes 
414876320d7SLorenzo Stoakes 	/* Free surrounding VMAs. */
415876320d7SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr_region, page_size), 0);
416876320d7SLorenzo Stoakes 	ASSERT_EQ(munmap(&ptr_region[11 * page_size], 39 * page_size), 0);
417876320d7SLorenzo Stoakes 	ASSERT_EQ(munmap(&ptr_region[55 * page_size], 24 * page_size), 0);
418876320d7SLorenzo Stoakes 	ASSERT_EQ(munmap(&ptr_region[99 * page_size], page_size), 0);
419876320d7SLorenzo Stoakes 
420876320d7SLorenzo Stoakes 	/* Now guard in one step. */
421*62d648c4SLorenzo Stoakes 	count = sys_process_madvise(PIDFD_SELF, vec, 6, MADV_GUARD_INSTALL, 0);
422876320d7SLorenzo Stoakes 
423876320d7SLorenzo Stoakes 	/* OK we don't have permission to do this, skip. */
424876320d7SLorenzo Stoakes 	if (count == -1 && errno == EPERM)
425876320d7SLorenzo Stoakes 		ksft_exit_skip("No process_madvise() permissions, try running as root.\n");
426876320d7SLorenzo Stoakes 
427876320d7SLorenzo Stoakes 	/* Returns the number of bytes advised. */
428876320d7SLorenzo Stoakes 	ASSERT_EQ(count, 6 * page_size);
429876320d7SLorenzo Stoakes 
430876320d7SLorenzo Stoakes 	/* Now make sure the guarding was applied. */
431876320d7SLorenzo Stoakes 
432876320d7SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(ptr1));
433876320d7SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(&ptr1[9 * page_size]));
434876320d7SLorenzo Stoakes 
435876320d7SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(ptr2));
436876320d7SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(&ptr2[4 * page_size]));
437876320d7SLorenzo Stoakes 
438876320d7SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(ptr3));
439876320d7SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(&ptr3[19 * page_size]));
440876320d7SLorenzo Stoakes 
441876320d7SLorenzo Stoakes 	/* Now do the same with unguard... */
442*62d648c4SLorenzo Stoakes 	count = sys_process_madvise(PIDFD_SELF, vec, 6, MADV_GUARD_REMOVE, 0);
443876320d7SLorenzo Stoakes 
444876320d7SLorenzo Stoakes 	/* ...and everything should now succeed. */
445876320d7SLorenzo Stoakes 
446876320d7SLorenzo Stoakes 	ASSERT_TRUE(try_read_write_buf(ptr1));
447876320d7SLorenzo Stoakes 	ASSERT_TRUE(try_read_write_buf(&ptr1[9 * page_size]));
448876320d7SLorenzo Stoakes 
449876320d7SLorenzo Stoakes 	ASSERT_TRUE(try_read_write_buf(ptr2));
450876320d7SLorenzo Stoakes 	ASSERT_TRUE(try_read_write_buf(&ptr2[4 * page_size]));
451876320d7SLorenzo Stoakes 
452876320d7SLorenzo Stoakes 	ASSERT_TRUE(try_read_write_buf(ptr3));
453876320d7SLorenzo Stoakes 	ASSERT_TRUE(try_read_write_buf(&ptr3[19 * page_size]));
454876320d7SLorenzo Stoakes 
455876320d7SLorenzo Stoakes 	/* Cleanup. */
456876320d7SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr1, 10 * page_size), 0);
457876320d7SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr2, 5 * page_size), 0);
458876320d7SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr3, 20 * page_size), 0);
459876320d7SLorenzo Stoakes }
460876320d7SLorenzo Stoakes 
461876320d7SLorenzo Stoakes /* Assert that unmapping ranges does not leave guard markers behind. */
462876320d7SLorenzo Stoakes TEST_F(guard_pages, munmap)
463876320d7SLorenzo Stoakes {
464876320d7SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
465876320d7SLorenzo Stoakes 	char *ptr, *ptr_new1, *ptr_new2;
466876320d7SLorenzo Stoakes 
467876320d7SLorenzo Stoakes 	ptr = mmap(NULL, 10 * page_size, PROT_READ | PROT_WRITE,
468876320d7SLorenzo Stoakes 		   MAP_ANON | MAP_PRIVATE, -1, 0);
469876320d7SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
470876320d7SLorenzo Stoakes 
471876320d7SLorenzo Stoakes 	/* Guard first and last pages. */
472876320d7SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, page_size, MADV_GUARD_INSTALL), 0);
473876320d7SLorenzo Stoakes 	ASSERT_EQ(madvise(&ptr[9 * page_size], page_size, MADV_GUARD_INSTALL), 0);
474876320d7SLorenzo Stoakes 
475876320d7SLorenzo Stoakes 	/* Assert that they are guarded. */
476876320d7SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(ptr));
477876320d7SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(&ptr[9 * page_size]));
478876320d7SLorenzo Stoakes 
479876320d7SLorenzo Stoakes 	/* Unmap them. */
480876320d7SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr, page_size), 0);
481876320d7SLorenzo Stoakes 	ASSERT_EQ(munmap(&ptr[9 * page_size], page_size), 0);
482876320d7SLorenzo Stoakes 
483876320d7SLorenzo Stoakes 	/* Map over them.*/
484876320d7SLorenzo Stoakes 	ptr_new1 = mmap(ptr, page_size, PROT_READ | PROT_WRITE,
485876320d7SLorenzo Stoakes 			MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
486876320d7SLorenzo Stoakes 	ASSERT_NE(ptr_new1, MAP_FAILED);
487876320d7SLorenzo Stoakes 	ptr_new2 = mmap(&ptr[9 * page_size], page_size, PROT_READ | PROT_WRITE,
488876320d7SLorenzo Stoakes 			MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
489876320d7SLorenzo Stoakes 	ASSERT_NE(ptr_new2, MAP_FAILED);
490876320d7SLorenzo Stoakes 
491876320d7SLorenzo Stoakes 	/* Assert that they are now not guarded. */
492876320d7SLorenzo Stoakes 	ASSERT_TRUE(try_read_write_buf(ptr_new1));
493876320d7SLorenzo Stoakes 	ASSERT_TRUE(try_read_write_buf(ptr_new2));
494876320d7SLorenzo Stoakes 
495876320d7SLorenzo Stoakes 	/* Cleanup. */
496876320d7SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
497876320d7SLorenzo Stoakes }
498876320d7SLorenzo Stoakes 
499876320d7SLorenzo Stoakes /* Assert that mprotect() operations have no bearing on guard markers. */
500876320d7SLorenzo Stoakes TEST_F(guard_pages, mprotect)
501876320d7SLorenzo Stoakes {
502876320d7SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
503876320d7SLorenzo Stoakes 	char *ptr;
504876320d7SLorenzo Stoakes 	int i;
505876320d7SLorenzo Stoakes 
506876320d7SLorenzo Stoakes 	ptr = mmap(NULL, 10 * page_size, PROT_READ | PROT_WRITE,
507876320d7SLorenzo Stoakes 		   MAP_ANON | MAP_PRIVATE, -1, 0);
508876320d7SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
509876320d7SLorenzo Stoakes 
510876320d7SLorenzo Stoakes 	/* Guard the middle of the range. */
511876320d7SLorenzo Stoakes 	ASSERT_EQ(madvise(&ptr[5 * page_size], 2 * page_size,
512876320d7SLorenzo Stoakes 			  MADV_GUARD_INSTALL), 0);
513876320d7SLorenzo Stoakes 
514876320d7SLorenzo Stoakes 	/* Assert that it is indeed guarded. */
515876320d7SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(&ptr[5 * page_size]));
516876320d7SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(&ptr[6 * page_size]));
517876320d7SLorenzo Stoakes 
518876320d7SLorenzo Stoakes 	/* Now make these pages read-only. */
519876320d7SLorenzo Stoakes 	ASSERT_EQ(mprotect(&ptr[5 * page_size], 2 * page_size, PROT_READ), 0);
520876320d7SLorenzo Stoakes 
521876320d7SLorenzo Stoakes 	/* Make sure the range is still guarded. */
522876320d7SLorenzo Stoakes 	ASSERT_FALSE(try_read_buf(&ptr[5 * page_size]));
523876320d7SLorenzo Stoakes 	ASSERT_FALSE(try_read_buf(&ptr[6 * page_size]));
524876320d7SLorenzo Stoakes 
525876320d7SLorenzo Stoakes 	/* Make sure we can guard again without issue.*/
526876320d7SLorenzo Stoakes 	ASSERT_EQ(madvise(&ptr[5 * page_size], 2 * page_size,
527876320d7SLorenzo Stoakes 			  MADV_GUARD_INSTALL), 0);
528876320d7SLorenzo Stoakes 
529876320d7SLorenzo Stoakes 	/* Make sure the range is, yet again, still guarded. */
530876320d7SLorenzo Stoakes 	ASSERT_FALSE(try_read_buf(&ptr[5 * page_size]));
531876320d7SLorenzo Stoakes 	ASSERT_FALSE(try_read_buf(&ptr[6 * page_size]));
532876320d7SLorenzo Stoakes 
533876320d7SLorenzo Stoakes 	/* Now unguard the whole range. */
534876320d7SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_REMOVE), 0);
535876320d7SLorenzo Stoakes 
536876320d7SLorenzo Stoakes 	/* Make sure the whole range is readable. */
537876320d7SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
538876320d7SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
539876320d7SLorenzo Stoakes 
540876320d7SLorenzo Stoakes 		ASSERT_TRUE(try_read_buf(curr));
541876320d7SLorenzo Stoakes 	}
542876320d7SLorenzo Stoakes 
543876320d7SLorenzo Stoakes 	/* Cleanup. */
544876320d7SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
545876320d7SLorenzo Stoakes }
546876320d7SLorenzo Stoakes 
547876320d7SLorenzo Stoakes /* Split and merge VMAs and make sure guard pages still behave. */
548876320d7SLorenzo Stoakes TEST_F(guard_pages, split_merge)
549876320d7SLorenzo Stoakes {
550876320d7SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
551876320d7SLorenzo Stoakes 	char *ptr, *ptr_new;
552876320d7SLorenzo Stoakes 	int i;
553876320d7SLorenzo Stoakes 
554876320d7SLorenzo Stoakes 	ptr = mmap(NULL, 10 * page_size, PROT_READ | PROT_WRITE,
555876320d7SLorenzo Stoakes 		   MAP_ANON | MAP_PRIVATE, -1, 0);
556876320d7SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
557876320d7SLorenzo Stoakes 
558876320d7SLorenzo Stoakes 	/* Guard the whole range. */
559876320d7SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_INSTALL), 0);
560876320d7SLorenzo Stoakes 
561876320d7SLorenzo Stoakes 	/* Make sure the whole range is guarded. */
562876320d7SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
563876320d7SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
564876320d7SLorenzo Stoakes 
565876320d7SLorenzo Stoakes 		ASSERT_FALSE(try_read_write_buf(curr));
566876320d7SLorenzo Stoakes 	}
567876320d7SLorenzo Stoakes 
568876320d7SLorenzo Stoakes 	/* Now unmap some pages in the range so we split. */
569876320d7SLorenzo Stoakes 	ASSERT_EQ(munmap(&ptr[2 * page_size], page_size), 0);
570876320d7SLorenzo Stoakes 	ASSERT_EQ(munmap(&ptr[5 * page_size], page_size), 0);
571876320d7SLorenzo Stoakes 	ASSERT_EQ(munmap(&ptr[8 * page_size], page_size), 0);
572876320d7SLorenzo Stoakes 
573876320d7SLorenzo Stoakes 	/* Make sure the remaining ranges are guarded post-split. */
574876320d7SLorenzo Stoakes 	for (i = 0; i < 2; i++) {
575876320d7SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
576876320d7SLorenzo Stoakes 
577876320d7SLorenzo Stoakes 		ASSERT_FALSE(try_read_write_buf(curr));
578876320d7SLorenzo Stoakes 	}
579876320d7SLorenzo Stoakes 	for (i = 2; i < 5; i++) {
580876320d7SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
581876320d7SLorenzo Stoakes 
582876320d7SLorenzo Stoakes 		ASSERT_FALSE(try_read_write_buf(curr));
583876320d7SLorenzo Stoakes 	}
584876320d7SLorenzo Stoakes 	for (i = 6; i < 8; i++) {
585876320d7SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
586876320d7SLorenzo Stoakes 
587876320d7SLorenzo Stoakes 		ASSERT_FALSE(try_read_write_buf(curr));
588876320d7SLorenzo Stoakes 	}
589876320d7SLorenzo Stoakes 	for (i = 9; i < 10; i++) {
590876320d7SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
591876320d7SLorenzo Stoakes 
592876320d7SLorenzo Stoakes 		ASSERT_FALSE(try_read_write_buf(curr));
593876320d7SLorenzo Stoakes 	}
594876320d7SLorenzo Stoakes 
595876320d7SLorenzo Stoakes 	/* Now map them again - the unmap will have cleared the guards. */
596876320d7SLorenzo Stoakes 	ptr_new = mmap(&ptr[2 * page_size], page_size, PROT_READ | PROT_WRITE,
597876320d7SLorenzo Stoakes 		       MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
598876320d7SLorenzo Stoakes 	ASSERT_NE(ptr_new, MAP_FAILED);
599876320d7SLorenzo Stoakes 	ptr_new = mmap(&ptr[5 * page_size], page_size, PROT_READ | PROT_WRITE,
600876320d7SLorenzo Stoakes 		       MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
601876320d7SLorenzo Stoakes 	ASSERT_NE(ptr_new, MAP_FAILED);
602876320d7SLorenzo Stoakes 	ptr_new = mmap(&ptr[8 * page_size], page_size, PROT_READ | PROT_WRITE,
603876320d7SLorenzo Stoakes 		       MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
604876320d7SLorenzo Stoakes 	ASSERT_NE(ptr_new, MAP_FAILED);
605876320d7SLorenzo Stoakes 
606876320d7SLorenzo Stoakes 	/* Now make sure guard pages are established. */
607876320d7SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
608876320d7SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
609876320d7SLorenzo Stoakes 		bool result = try_read_write_buf(curr);
610876320d7SLorenzo Stoakes 		bool expect_true = i == 2 || i == 5 || i == 8;
611876320d7SLorenzo Stoakes 
612876320d7SLorenzo Stoakes 		ASSERT_TRUE(expect_true ? result : !result);
613876320d7SLorenzo Stoakes 	}
614876320d7SLorenzo Stoakes 
615876320d7SLorenzo Stoakes 	/* Now guard everything again. */
616876320d7SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_INSTALL), 0);
617876320d7SLorenzo Stoakes 
618876320d7SLorenzo Stoakes 	/* Make sure the whole range is guarded. */
619876320d7SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
620876320d7SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
621876320d7SLorenzo Stoakes 
622876320d7SLorenzo Stoakes 		ASSERT_FALSE(try_read_write_buf(curr));
623876320d7SLorenzo Stoakes 	}
624876320d7SLorenzo Stoakes 
625876320d7SLorenzo Stoakes 	/* Now split the range into three. */
626876320d7SLorenzo Stoakes 	ASSERT_EQ(mprotect(ptr, 3 * page_size, PROT_READ), 0);
627876320d7SLorenzo Stoakes 	ASSERT_EQ(mprotect(&ptr[7 * page_size], 3 * page_size, PROT_READ), 0);
628876320d7SLorenzo Stoakes 
629876320d7SLorenzo Stoakes 	/* Make sure the whole range is guarded for read. */
630876320d7SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
631876320d7SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
632876320d7SLorenzo Stoakes 
633876320d7SLorenzo Stoakes 		ASSERT_FALSE(try_read_buf(curr));
634876320d7SLorenzo Stoakes 	}
635876320d7SLorenzo Stoakes 
636876320d7SLorenzo Stoakes 	/* Now reset protection bits so we merge the whole thing. */
637876320d7SLorenzo Stoakes 	ASSERT_EQ(mprotect(ptr, 3 * page_size, PROT_READ | PROT_WRITE), 0);
638876320d7SLorenzo Stoakes 	ASSERT_EQ(mprotect(&ptr[7 * page_size], 3 * page_size,
639876320d7SLorenzo Stoakes 			   PROT_READ | PROT_WRITE), 0);
640876320d7SLorenzo Stoakes 
641876320d7SLorenzo Stoakes 	/* Make sure the whole range is still guarded. */
642876320d7SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
643876320d7SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
644876320d7SLorenzo Stoakes 
645876320d7SLorenzo Stoakes 		ASSERT_FALSE(try_read_write_buf(curr));
646876320d7SLorenzo Stoakes 	}
647876320d7SLorenzo Stoakes 
648876320d7SLorenzo Stoakes 	/* Split range into 3 again... */
649876320d7SLorenzo Stoakes 	ASSERT_EQ(mprotect(ptr, 3 * page_size, PROT_READ), 0);
650876320d7SLorenzo Stoakes 	ASSERT_EQ(mprotect(&ptr[7 * page_size], 3 * page_size, PROT_READ), 0);
651876320d7SLorenzo Stoakes 
652876320d7SLorenzo Stoakes 	/* ...and unguard the whole range. */
653876320d7SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_REMOVE), 0);
654876320d7SLorenzo Stoakes 
655876320d7SLorenzo Stoakes 	/* Make sure the whole range is remedied for read. */
656876320d7SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
657876320d7SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
658876320d7SLorenzo Stoakes 
659876320d7SLorenzo Stoakes 		ASSERT_TRUE(try_read_buf(curr));
660876320d7SLorenzo Stoakes 	}
661876320d7SLorenzo Stoakes 
662876320d7SLorenzo Stoakes 	/* Merge them again. */
663876320d7SLorenzo Stoakes 	ASSERT_EQ(mprotect(ptr, 3 * page_size, PROT_READ | PROT_WRITE), 0);
664876320d7SLorenzo Stoakes 	ASSERT_EQ(mprotect(&ptr[7 * page_size], 3 * page_size,
665876320d7SLorenzo Stoakes 			   PROT_READ | PROT_WRITE), 0);
666876320d7SLorenzo Stoakes 
667876320d7SLorenzo Stoakes 	/* Now ensure the merged range is remedied for read/write. */
668876320d7SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
669876320d7SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
670876320d7SLorenzo Stoakes 
671876320d7SLorenzo Stoakes 		ASSERT_TRUE(try_read_write_buf(curr));
672876320d7SLorenzo Stoakes 	}
673876320d7SLorenzo Stoakes 
674876320d7SLorenzo Stoakes 	/* Cleanup. */
675876320d7SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
676876320d7SLorenzo Stoakes }
677876320d7SLorenzo Stoakes 
678876320d7SLorenzo Stoakes /* Assert that MADV_DONTNEED does not remove guard markers. */
679876320d7SLorenzo Stoakes TEST_F(guard_pages, dontneed)
680876320d7SLorenzo Stoakes {
681876320d7SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
682876320d7SLorenzo Stoakes 	char *ptr;
683876320d7SLorenzo Stoakes 	int i;
684876320d7SLorenzo Stoakes 
685876320d7SLorenzo Stoakes 	ptr = mmap(NULL, 10 * page_size, PROT_READ | PROT_WRITE,
686876320d7SLorenzo Stoakes 		   MAP_ANON | MAP_PRIVATE, -1, 0);
687876320d7SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
688876320d7SLorenzo Stoakes 
689876320d7SLorenzo Stoakes 	/* Back the whole range. */
690876320d7SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
691876320d7SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
692876320d7SLorenzo Stoakes 
693876320d7SLorenzo Stoakes 		*curr = 'y';
694876320d7SLorenzo Stoakes 	}
695876320d7SLorenzo Stoakes 
696876320d7SLorenzo Stoakes 	/* Guard every other page. */
697876320d7SLorenzo Stoakes 	for (i = 0; i < 10; i += 2) {
698876320d7SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
699876320d7SLorenzo Stoakes 		int res = madvise(curr, page_size, MADV_GUARD_INSTALL);
700876320d7SLorenzo Stoakes 
701876320d7SLorenzo Stoakes 		ASSERT_EQ(res, 0);
702876320d7SLorenzo Stoakes 	}
703876320d7SLorenzo Stoakes 
704876320d7SLorenzo Stoakes 	/* Indicate that we don't need any of the range. */
705876320d7SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_DONTNEED), 0);
706876320d7SLorenzo Stoakes 
707876320d7SLorenzo Stoakes 	/* Check to ensure guard markers are still in place. */
708876320d7SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
709876320d7SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
710876320d7SLorenzo Stoakes 		bool result = try_read_buf(curr);
711876320d7SLorenzo Stoakes 
712876320d7SLorenzo Stoakes 		if (i % 2 == 0) {
713876320d7SLorenzo Stoakes 			ASSERT_FALSE(result);
714876320d7SLorenzo Stoakes 		} else {
715876320d7SLorenzo Stoakes 			ASSERT_TRUE(result);
716876320d7SLorenzo Stoakes 			/* Make sure we really did get reset to zero page. */
717876320d7SLorenzo Stoakes 			ASSERT_EQ(*curr, '\0');
718876320d7SLorenzo Stoakes 		}
719876320d7SLorenzo Stoakes 
720876320d7SLorenzo Stoakes 		/* Now write... */
721876320d7SLorenzo Stoakes 		result = try_write_buf(&ptr[i * page_size]);
722876320d7SLorenzo Stoakes 
723876320d7SLorenzo Stoakes 		/* ...and make sure same result. */
724876320d7SLorenzo Stoakes 		ASSERT_TRUE(i % 2 != 0 ? result : !result);
725876320d7SLorenzo Stoakes 	}
726876320d7SLorenzo Stoakes 
727876320d7SLorenzo Stoakes 	/* Cleanup. */
728876320d7SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
729876320d7SLorenzo Stoakes }
730876320d7SLorenzo Stoakes 
731876320d7SLorenzo Stoakes /* Assert that mlock()'ed pages work correctly with guard markers. */
732876320d7SLorenzo Stoakes TEST_F(guard_pages, mlock)
733876320d7SLorenzo Stoakes {
734876320d7SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
735876320d7SLorenzo Stoakes 	char *ptr;
736876320d7SLorenzo Stoakes 	int i;
737876320d7SLorenzo Stoakes 
738876320d7SLorenzo Stoakes 	ptr = mmap(NULL, 10 * page_size, PROT_READ | PROT_WRITE,
739876320d7SLorenzo Stoakes 		   MAP_ANON | MAP_PRIVATE, -1, 0);
740876320d7SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
741876320d7SLorenzo Stoakes 
742876320d7SLorenzo Stoakes 	/* Populate. */
743876320d7SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
744876320d7SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
745876320d7SLorenzo Stoakes 
746876320d7SLorenzo Stoakes 		*curr = 'y';
747876320d7SLorenzo Stoakes 	}
748876320d7SLorenzo Stoakes 
749876320d7SLorenzo Stoakes 	/* Lock. */
750876320d7SLorenzo Stoakes 	ASSERT_EQ(mlock(ptr, 10 * page_size), 0);
751876320d7SLorenzo Stoakes 
752876320d7SLorenzo Stoakes 	/* Now try to guard, should fail with EINVAL. */
753876320d7SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_INSTALL), -1);
754876320d7SLorenzo Stoakes 	ASSERT_EQ(errno, EINVAL);
755876320d7SLorenzo Stoakes 
756876320d7SLorenzo Stoakes 	/* OK unlock. */
757876320d7SLorenzo Stoakes 	ASSERT_EQ(munlock(ptr, 10 * page_size), 0);
758876320d7SLorenzo Stoakes 
759876320d7SLorenzo Stoakes 	/* Guard first half of range, should now succeed. */
760876320d7SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 5 * page_size, MADV_GUARD_INSTALL), 0);
761876320d7SLorenzo Stoakes 
762876320d7SLorenzo Stoakes 	/* Make sure guard works. */
763876320d7SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
764876320d7SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
765876320d7SLorenzo Stoakes 		bool result = try_read_write_buf(curr);
766876320d7SLorenzo Stoakes 
767876320d7SLorenzo Stoakes 		if (i < 5) {
768876320d7SLorenzo Stoakes 			ASSERT_FALSE(result);
769876320d7SLorenzo Stoakes 		} else {
770876320d7SLorenzo Stoakes 			ASSERT_TRUE(result);
771876320d7SLorenzo Stoakes 			ASSERT_EQ(*curr, 'x');
772876320d7SLorenzo Stoakes 		}
773876320d7SLorenzo Stoakes 	}
774876320d7SLorenzo Stoakes 
775876320d7SLorenzo Stoakes 	/*
776876320d7SLorenzo Stoakes 	 * Now lock the latter part of the range. We can't lock the guard pages,
777876320d7SLorenzo Stoakes 	 * as this would result in the pages being populated and the guarding
778876320d7SLorenzo Stoakes 	 * would cause this to error out.
779876320d7SLorenzo Stoakes 	 */
780876320d7SLorenzo Stoakes 	ASSERT_EQ(mlock(&ptr[5 * page_size], 5 * page_size), 0);
781876320d7SLorenzo Stoakes 
782876320d7SLorenzo Stoakes 	/*
783876320d7SLorenzo Stoakes 	 * Now remove guard pages, we permit mlock()'d ranges to have guard
784876320d7SLorenzo Stoakes 	 * pages removed as it is a non-destructive operation.
785876320d7SLorenzo Stoakes 	 */
786876320d7SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_REMOVE), 0);
787876320d7SLorenzo Stoakes 
788876320d7SLorenzo Stoakes 	/* Now check that no guard pages remain. */
789876320d7SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
790876320d7SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
791876320d7SLorenzo Stoakes 
792876320d7SLorenzo Stoakes 		ASSERT_TRUE(try_read_write_buf(curr));
793876320d7SLorenzo Stoakes 	}
794876320d7SLorenzo Stoakes 
795876320d7SLorenzo Stoakes 	/* Cleanup. */
796876320d7SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
797876320d7SLorenzo Stoakes }
798876320d7SLorenzo Stoakes 
799876320d7SLorenzo Stoakes /*
800876320d7SLorenzo Stoakes  * Assert that moving, extending and shrinking memory via mremap() retains
801876320d7SLorenzo Stoakes  * guard markers where possible.
802876320d7SLorenzo Stoakes  *
803876320d7SLorenzo Stoakes  * - Moving a mapping alone should retain markers as they are.
804876320d7SLorenzo Stoakes  */
805876320d7SLorenzo Stoakes TEST_F(guard_pages, mremap_move)
806876320d7SLorenzo Stoakes {
807876320d7SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
808876320d7SLorenzo Stoakes 	char *ptr, *ptr_new;
809876320d7SLorenzo Stoakes 
810876320d7SLorenzo Stoakes 	/* Map 5 pages. */
811876320d7SLorenzo Stoakes 	ptr = mmap(NULL, 5 * page_size, PROT_READ | PROT_WRITE,
812876320d7SLorenzo Stoakes 		   MAP_ANON | MAP_PRIVATE, -1, 0);
813876320d7SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
814876320d7SLorenzo Stoakes 
815876320d7SLorenzo Stoakes 	/* Place guard markers at both ends of the 5 page span. */
816876320d7SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, page_size, MADV_GUARD_INSTALL), 0);
817876320d7SLorenzo Stoakes 	ASSERT_EQ(madvise(&ptr[4 * page_size], page_size, MADV_GUARD_INSTALL), 0);
818876320d7SLorenzo Stoakes 
819876320d7SLorenzo Stoakes 	/* Make sure the guard pages are in effect. */
820876320d7SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(ptr));
821876320d7SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(&ptr[4 * page_size]));
822876320d7SLorenzo Stoakes 
823876320d7SLorenzo Stoakes 	/* Map a new region we will move this range into. Doing this ensures
824876320d7SLorenzo Stoakes 	 * that we have reserved a range to map into.
825876320d7SLorenzo Stoakes 	 */
826876320d7SLorenzo Stoakes 	ptr_new = mmap(NULL, 5 * page_size, PROT_NONE, MAP_ANON | MAP_PRIVATE,
827876320d7SLorenzo Stoakes 		       -1, 0);
828876320d7SLorenzo Stoakes 	ASSERT_NE(ptr_new, MAP_FAILED);
829876320d7SLorenzo Stoakes 
830876320d7SLorenzo Stoakes 	ASSERT_EQ(mremap(ptr, 5 * page_size, 5 * page_size,
831876320d7SLorenzo Stoakes 			 MREMAP_MAYMOVE | MREMAP_FIXED, ptr_new), ptr_new);
832876320d7SLorenzo Stoakes 
833876320d7SLorenzo Stoakes 	/* Make sure the guard markers are retained. */
834876320d7SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(ptr_new));
835876320d7SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(&ptr_new[4 * page_size]));
836876320d7SLorenzo Stoakes 
837876320d7SLorenzo Stoakes 	/*
838876320d7SLorenzo Stoakes 	 * Clean up - we only need reference the new pointer as we overwrote the
839876320d7SLorenzo Stoakes 	 * PROT_NONE range and moved the existing one.
840876320d7SLorenzo Stoakes 	 */
841876320d7SLorenzo Stoakes 	munmap(ptr_new, 5 * page_size);
842876320d7SLorenzo Stoakes }
843876320d7SLorenzo Stoakes 
844876320d7SLorenzo Stoakes /*
845876320d7SLorenzo Stoakes  * Assert that moving, extending and shrinking memory via mremap() retains
846876320d7SLorenzo Stoakes  * guard markers where possible.
847876320d7SLorenzo Stoakes  *
848876320d7SLorenzo Stoakes  * Expanding should retain guard pages, only now in different position. The user
849876320d7SLorenzo Stoakes  * will have to remove guard pages manually to fix up (they'd have to do the
850876320d7SLorenzo Stoakes  * same if it were a PROT_NONE mapping).
851876320d7SLorenzo Stoakes  */
852876320d7SLorenzo Stoakes TEST_F(guard_pages, mremap_expand)
853876320d7SLorenzo Stoakes {
854876320d7SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
855876320d7SLorenzo Stoakes 	char *ptr, *ptr_new;
856876320d7SLorenzo Stoakes 
857876320d7SLorenzo Stoakes 	/* Map 10 pages... */
858876320d7SLorenzo Stoakes 	ptr = mmap(NULL, 10 * page_size, PROT_READ | PROT_WRITE,
859876320d7SLorenzo Stoakes 		   MAP_ANON | MAP_PRIVATE, -1, 0);
860876320d7SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
861876320d7SLorenzo Stoakes 	/* ...But unmap the last 5 so we can ensure we can expand into them. */
862876320d7SLorenzo Stoakes 	ASSERT_EQ(munmap(&ptr[5 * page_size], 5 * page_size), 0);
863876320d7SLorenzo Stoakes 
864876320d7SLorenzo Stoakes 	/* Place guard markers at both ends of the 5 page span. */
865876320d7SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, page_size, MADV_GUARD_INSTALL), 0);
866876320d7SLorenzo Stoakes 	ASSERT_EQ(madvise(&ptr[4 * page_size], page_size, MADV_GUARD_INSTALL), 0);
867876320d7SLorenzo Stoakes 
868876320d7SLorenzo Stoakes 	/* Make sure the guarding is in effect. */
869876320d7SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(ptr));
870876320d7SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(&ptr[4 * page_size]));
871876320d7SLorenzo Stoakes 
872876320d7SLorenzo Stoakes 	/* Now expand to 10 pages. */
873876320d7SLorenzo Stoakes 	ptr = mremap(ptr, 5 * page_size, 10 * page_size, 0);
874876320d7SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
875876320d7SLorenzo Stoakes 
876876320d7SLorenzo Stoakes 	/*
877876320d7SLorenzo Stoakes 	 * Make sure the guard markers are retained in their original positions.
878876320d7SLorenzo Stoakes 	 */
879876320d7SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(ptr));
880876320d7SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(&ptr[4 * page_size]));
881876320d7SLorenzo Stoakes 
882876320d7SLorenzo Stoakes 	/* Reserve a region which we can move to and expand into. */
883876320d7SLorenzo Stoakes 	ptr_new = mmap(NULL, 20 * page_size, PROT_NONE,
884876320d7SLorenzo Stoakes 		       MAP_ANON | MAP_PRIVATE, -1, 0);
885876320d7SLorenzo Stoakes 	ASSERT_NE(ptr_new, MAP_FAILED);
886876320d7SLorenzo Stoakes 
887876320d7SLorenzo Stoakes 	/* Now move and expand into it. */
888876320d7SLorenzo Stoakes 	ptr = mremap(ptr, 10 * page_size, 20 * page_size,
889876320d7SLorenzo Stoakes 		     MREMAP_MAYMOVE | MREMAP_FIXED, ptr_new);
890876320d7SLorenzo Stoakes 	ASSERT_EQ(ptr, ptr_new);
891876320d7SLorenzo Stoakes 
892876320d7SLorenzo Stoakes 	/*
893876320d7SLorenzo Stoakes 	 * Again, make sure the guard markers are retained in their original positions.
894876320d7SLorenzo Stoakes 	 */
895876320d7SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(ptr));
896876320d7SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(&ptr[4 * page_size]));
897876320d7SLorenzo Stoakes 
898876320d7SLorenzo Stoakes 	/*
899876320d7SLorenzo Stoakes 	 * A real user would have to remove guard markers, but would reasonably
900876320d7SLorenzo Stoakes 	 * expect all characteristics of the mapping to be retained, including
901876320d7SLorenzo Stoakes 	 * guard markers.
902876320d7SLorenzo Stoakes 	 */
903876320d7SLorenzo Stoakes 
904876320d7SLorenzo Stoakes 	/* Cleanup. */
905876320d7SLorenzo Stoakes 	munmap(ptr, 20 * page_size);
906876320d7SLorenzo Stoakes }
907876320d7SLorenzo Stoakes /*
908876320d7SLorenzo Stoakes  * Assert that moving, extending and shrinking memory via mremap() retains
909876320d7SLorenzo Stoakes  * guard markers where possible.
910876320d7SLorenzo Stoakes  *
911876320d7SLorenzo Stoakes  * Shrinking will result in markers that are shrunk over being removed. Again,
912876320d7SLorenzo Stoakes  * if the user were using a PROT_NONE mapping they'd have to manually fix this
913876320d7SLorenzo Stoakes  * up also so this is OK.
914876320d7SLorenzo Stoakes  */
915876320d7SLorenzo Stoakes TEST_F(guard_pages, mremap_shrink)
916876320d7SLorenzo Stoakes {
917876320d7SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
918876320d7SLorenzo Stoakes 	char *ptr;
919876320d7SLorenzo Stoakes 	int i;
920876320d7SLorenzo Stoakes 
921876320d7SLorenzo Stoakes 	/* Map 5 pages. */
922876320d7SLorenzo Stoakes 	ptr = mmap(NULL, 5 * page_size, PROT_READ | PROT_WRITE,
923876320d7SLorenzo Stoakes 		   MAP_ANON | MAP_PRIVATE, -1, 0);
924876320d7SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
925876320d7SLorenzo Stoakes 
926876320d7SLorenzo Stoakes 	/* Place guard markers at both ends of the 5 page span. */
927876320d7SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, page_size, MADV_GUARD_INSTALL), 0);
928876320d7SLorenzo Stoakes 	ASSERT_EQ(madvise(&ptr[4 * page_size], page_size, MADV_GUARD_INSTALL), 0);
929876320d7SLorenzo Stoakes 
930876320d7SLorenzo Stoakes 	/* Make sure the guarding is in effect. */
931876320d7SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(ptr));
932876320d7SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(&ptr[4 * page_size]));
933876320d7SLorenzo Stoakes 
934876320d7SLorenzo Stoakes 	/* Now shrink to 3 pages. */
935876320d7SLorenzo Stoakes 	ptr = mremap(ptr, 5 * page_size, 3 * page_size, MREMAP_MAYMOVE);
936876320d7SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
937876320d7SLorenzo Stoakes 
938876320d7SLorenzo Stoakes 	/* We expect the guard marker at the start to be retained... */
939876320d7SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(ptr));
940876320d7SLorenzo Stoakes 
941876320d7SLorenzo Stoakes 	/* ...But remaining pages will not have guard markers. */
942876320d7SLorenzo Stoakes 	for (i = 1; i < 3; i++) {
943876320d7SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
944876320d7SLorenzo Stoakes 
945876320d7SLorenzo Stoakes 		ASSERT_TRUE(try_read_write_buf(curr));
946876320d7SLorenzo Stoakes 	}
947876320d7SLorenzo Stoakes 
948876320d7SLorenzo Stoakes 	/*
949876320d7SLorenzo Stoakes 	 * As with expansion, a real user would have to remove guard pages and
950876320d7SLorenzo Stoakes 	 * fixup. But you'd have to do similar manual things with PROT_NONE
951876320d7SLorenzo Stoakes 	 * mappings too.
952876320d7SLorenzo Stoakes 	 */
953876320d7SLorenzo Stoakes 
954876320d7SLorenzo Stoakes 	/*
955876320d7SLorenzo Stoakes 	 * If we expand back to the original size, the end marker will, of
956876320d7SLorenzo Stoakes 	 * course, no longer be present.
957876320d7SLorenzo Stoakes 	 */
958876320d7SLorenzo Stoakes 	ptr = mremap(ptr, 3 * page_size, 5 * page_size, 0);
959876320d7SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
960876320d7SLorenzo Stoakes 
961876320d7SLorenzo Stoakes 	/* Again, we expect the guard marker at the start to be retained... */
962876320d7SLorenzo Stoakes 	ASSERT_FALSE(try_read_write_buf(ptr));
963876320d7SLorenzo Stoakes 
964876320d7SLorenzo Stoakes 	/* ...But remaining pages will not have guard markers. */
965876320d7SLorenzo Stoakes 	for (i = 1; i < 5; i++) {
966876320d7SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
967876320d7SLorenzo Stoakes 
968876320d7SLorenzo Stoakes 		ASSERT_TRUE(try_read_write_buf(curr));
969876320d7SLorenzo Stoakes 	}
970876320d7SLorenzo Stoakes 
971876320d7SLorenzo Stoakes 	/* Cleanup. */
972876320d7SLorenzo Stoakes 	munmap(ptr, 5 * page_size);
973876320d7SLorenzo Stoakes }
974876320d7SLorenzo Stoakes 
975876320d7SLorenzo Stoakes /*
976876320d7SLorenzo Stoakes  * Assert that forking a process with VMAs that do not have VM_WIPEONFORK set
977876320d7SLorenzo Stoakes  * retain guard pages.
978876320d7SLorenzo Stoakes  */
979876320d7SLorenzo Stoakes TEST_F(guard_pages, fork)
980876320d7SLorenzo Stoakes {
981876320d7SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
982876320d7SLorenzo Stoakes 	char *ptr;
983876320d7SLorenzo Stoakes 	pid_t pid;
984876320d7SLorenzo Stoakes 	int i;
985876320d7SLorenzo Stoakes 
986876320d7SLorenzo Stoakes 	/* Map 10 pages. */
987876320d7SLorenzo Stoakes 	ptr = mmap(NULL, 10 * page_size, PROT_READ | PROT_WRITE,
988876320d7SLorenzo Stoakes 		   MAP_ANON | MAP_PRIVATE, -1, 0);
989876320d7SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
990876320d7SLorenzo Stoakes 
99119b65ffaSLorenzo Stoakes 	/* Establish guard pages in the first 5 pages. */
992876320d7SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 5 * page_size, MADV_GUARD_INSTALL), 0);
993876320d7SLorenzo Stoakes 
994876320d7SLorenzo Stoakes 	pid = fork();
995876320d7SLorenzo Stoakes 	ASSERT_NE(pid, -1);
996876320d7SLorenzo Stoakes 	if (!pid) {
997876320d7SLorenzo Stoakes 		/* This is the child process now. */
998876320d7SLorenzo Stoakes 
999876320d7SLorenzo Stoakes 		/* Assert that the guarding is in effect. */
1000876320d7SLorenzo Stoakes 		for (i = 0; i < 10; i++) {
1001876320d7SLorenzo Stoakes 			char *curr = &ptr[i * page_size];
1002876320d7SLorenzo Stoakes 			bool result = try_read_write_buf(curr);
1003876320d7SLorenzo Stoakes 
1004876320d7SLorenzo Stoakes 			ASSERT_TRUE(i >= 5 ? result : !result);
1005876320d7SLorenzo Stoakes 		}
1006876320d7SLorenzo Stoakes 
1007876320d7SLorenzo Stoakes 		/* Now unguard the range.*/
1008876320d7SLorenzo Stoakes 		ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_REMOVE), 0);
1009876320d7SLorenzo Stoakes 
1010876320d7SLorenzo Stoakes 		exit(0);
1011876320d7SLorenzo Stoakes 	}
1012876320d7SLorenzo Stoakes 
1013876320d7SLorenzo Stoakes 	/* Parent process. */
1014876320d7SLorenzo Stoakes 
1015876320d7SLorenzo Stoakes 	/* Parent simply waits on child. */
1016876320d7SLorenzo Stoakes 	waitpid(pid, NULL, 0);
1017876320d7SLorenzo Stoakes 
1018876320d7SLorenzo Stoakes 	/* Child unguard does not impact parent page table state. */
1019876320d7SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
1020876320d7SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
1021876320d7SLorenzo Stoakes 		bool result = try_read_write_buf(curr);
1022876320d7SLorenzo Stoakes 
1023876320d7SLorenzo Stoakes 		ASSERT_TRUE(i >= 5 ? result : !result);
1024876320d7SLorenzo Stoakes 	}
1025876320d7SLorenzo Stoakes 
1026876320d7SLorenzo Stoakes 	/* Cleanup. */
1027876320d7SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
1028876320d7SLorenzo Stoakes }
1029876320d7SLorenzo Stoakes 
1030876320d7SLorenzo Stoakes /*
103119b65ffaSLorenzo Stoakes  * Assert expected behaviour after we fork populated ranges of anonymous memory
103219b65ffaSLorenzo Stoakes  * and then guard and unguard the range.
103319b65ffaSLorenzo Stoakes  */
103419b65ffaSLorenzo Stoakes TEST_F(guard_pages, fork_cow)
103519b65ffaSLorenzo Stoakes {
103619b65ffaSLorenzo Stoakes 	const unsigned long page_size = self->page_size;
103719b65ffaSLorenzo Stoakes 	char *ptr;
103819b65ffaSLorenzo Stoakes 	pid_t pid;
103919b65ffaSLorenzo Stoakes 	int i;
104019b65ffaSLorenzo Stoakes 
104119b65ffaSLorenzo Stoakes 	/* Map 10 pages. */
104219b65ffaSLorenzo Stoakes 	ptr = mmap(NULL, 10 * page_size, PROT_READ | PROT_WRITE,
104319b65ffaSLorenzo Stoakes 		   MAP_ANON | MAP_PRIVATE, -1, 0);
104419b65ffaSLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
104519b65ffaSLorenzo Stoakes 
104619b65ffaSLorenzo Stoakes 	/* Populate range. */
104719b65ffaSLorenzo Stoakes 	for (i = 0; i < 10 * page_size; i++) {
104819b65ffaSLorenzo Stoakes 		char chr = 'a' + (i % 26);
104919b65ffaSLorenzo Stoakes 
105019b65ffaSLorenzo Stoakes 		ptr[i] = chr;
105119b65ffaSLorenzo Stoakes 	}
105219b65ffaSLorenzo Stoakes 
105319b65ffaSLorenzo Stoakes 	pid = fork();
105419b65ffaSLorenzo Stoakes 	ASSERT_NE(pid, -1);
105519b65ffaSLorenzo Stoakes 	if (!pid) {
105619b65ffaSLorenzo Stoakes 		/* This is the child process now. */
105719b65ffaSLorenzo Stoakes 
105819b65ffaSLorenzo Stoakes 		/* Ensure the range is as expected. */
105919b65ffaSLorenzo Stoakes 		for (i = 0; i < 10 * page_size; i++) {
106019b65ffaSLorenzo Stoakes 			char expected = 'a' + (i % 26);
106119b65ffaSLorenzo Stoakes 			char actual = ptr[i];
106219b65ffaSLorenzo Stoakes 
106319b65ffaSLorenzo Stoakes 			ASSERT_EQ(actual, expected);
106419b65ffaSLorenzo Stoakes 		}
106519b65ffaSLorenzo Stoakes 
106619b65ffaSLorenzo Stoakes 		/* Establish guard pages across the whole range. */
106719b65ffaSLorenzo Stoakes 		ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_INSTALL), 0);
106819b65ffaSLorenzo Stoakes 		/* Remove it. */
106919b65ffaSLorenzo Stoakes 		ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_REMOVE), 0);
107019b65ffaSLorenzo Stoakes 
107119b65ffaSLorenzo Stoakes 		/*
107219b65ffaSLorenzo Stoakes 		 * By removing the guard pages, the page tables will be
107319b65ffaSLorenzo Stoakes 		 * cleared. Assert that we are looking at the zero page now.
107419b65ffaSLorenzo Stoakes 		 */
107519b65ffaSLorenzo Stoakes 		for (i = 0; i < 10 * page_size; i++) {
107619b65ffaSLorenzo Stoakes 			char actual = ptr[i];
107719b65ffaSLorenzo Stoakes 
107819b65ffaSLorenzo Stoakes 			ASSERT_EQ(actual, '\0');
107919b65ffaSLorenzo Stoakes 		}
108019b65ffaSLorenzo Stoakes 
108119b65ffaSLorenzo Stoakes 		exit(0);
108219b65ffaSLorenzo Stoakes 	}
108319b65ffaSLorenzo Stoakes 
108419b65ffaSLorenzo Stoakes 	/* Parent process. */
108519b65ffaSLorenzo Stoakes 
108619b65ffaSLorenzo Stoakes 	/* Parent simply waits on child. */
108719b65ffaSLorenzo Stoakes 	waitpid(pid, NULL, 0);
108819b65ffaSLorenzo Stoakes 
108919b65ffaSLorenzo Stoakes 	/* Ensure the range is unchanged in parent anon range. */
109019b65ffaSLorenzo Stoakes 	for (i = 0; i < 10 * page_size; i++) {
109119b65ffaSLorenzo Stoakes 		char expected = 'a' + (i % 26);
109219b65ffaSLorenzo Stoakes 		char actual = ptr[i];
109319b65ffaSLorenzo Stoakes 
109419b65ffaSLorenzo Stoakes 		ASSERT_EQ(actual, expected);
109519b65ffaSLorenzo Stoakes 	}
109619b65ffaSLorenzo Stoakes 
109719b65ffaSLorenzo Stoakes 	/* Cleanup. */
109819b65ffaSLorenzo Stoakes 	ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
109919b65ffaSLorenzo Stoakes }
110019b65ffaSLorenzo Stoakes 
110119b65ffaSLorenzo Stoakes /*
1102876320d7SLorenzo Stoakes  * Assert that forking a process with VMAs that do have VM_WIPEONFORK set
1103876320d7SLorenzo Stoakes  * behave as expected.
1104876320d7SLorenzo Stoakes  */
1105876320d7SLorenzo Stoakes TEST_F(guard_pages, fork_wipeonfork)
1106876320d7SLorenzo Stoakes {
1107876320d7SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
1108876320d7SLorenzo Stoakes 	char *ptr;
1109876320d7SLorenzo Stoakes 	pid_t pid;
1110876320d7SLorenzo Stoakes 	int i;
1111876320d7SLorenzo Stoakes 
1112876320d7SLorenzo Stoakes 	/* Map 10 pages. */
1113876320d7SLorenzo Stoakes 	ptr = mmap(NULL, 10 * page_size, PROT_READ | PROT_WRITE,
1114876320d7SLorenzo Stoakes 		   MAP_ANON | MAP_PRIVATE, -1, 0);
1115876320d7SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
1116876320d7SLorenzo Stoakes 
1117876320d7SLorenzo Stoakes 	/* Mark wipe on fork. */
1118876320d7SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_WIPEONFORK), 0);
1119876320d7SLorenzo Stoakes 
1120876320d7SLorenzo Stoakes 	/* Guard the first 5 pages. */
1121876320d7SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 5 * page_size, MADV_GUARD_INSTALL), 0);
1122876320d7SLorenzo Stoakes 
1123876320d7SLorenzo Stoakes 	pid = fork();
1124876320d7SLorenzo Stoakes 	ASSERT_NE(pid, -1);
1125876320d7SLorenzo Stoakes 	if (!pid) {
1126876320d7SLorenzo Stoakes 		/* This is the child process now. */
1127876320d7SLorenzo Stoakes 
1128876320d7SLorenzo Stoakes 		/* Guard will have been wiped. */
1129876320d7SLorenzo Stoakes 		for (i = 0; i < 10; i++) {
1130876320d7SLorenzo Stoakes 			char *curr = &ptr[i * page_size];
1131876320d7SLorenzo Stoakes 
1132876320d7SLorenzo Stoakes 			ASSERT_TRUE(try_read_write_buf(curr));
1133876320d7SLorenzo Stoakes 		}
1134876320d7SLorenzo Stoakes 
1135876320d7SLorenzo Stoakes 		exit(0);
1136876320d7SLorenzo Stoakes 	}
1137876320d7SLorenzo Stoakes 
1138876320d7SLorenzo Stoakes 	/* Parent process. */
1139876320d7SLorenzo Stoakes 
1140876320d7SLorenzo Stoakes 	waitpid(pid, NULL, 0);
1141876320d7SLorenzo Stoakes 
1142876320d7SLorenzo Stoakes 	/* Guard markers should be in effect.*/
1143876320d7SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
1144876320d7SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
1145876320d7SLorenzo Stoakes 		bool result = try_read_write_buf(curr);
1146876320d7SLorenzo Stoakes 
1147876320d7SLorenzo Stoakes 		ASSERT_TRUE(i >= 5 ? result : !result);
1148876320d7SLorenzo Stoakes 	}
1149876320d7SLorenzo Stoakes 
1150876320d7SLorenzo Stoakes 	/* Cleanup. */
1151876320d7SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
1152876320d7SLorenzo Stoakes }
1153876320d7SLorenzo Stoakes 
1154876320d7SLorenzo Stoakes /* Ensure that MADV_FREE retains guard entries as expected. */
1155876320d7SLorenzo Stoakes TEST_F(guard_pages, lazyfree)
1156876320d7SLorenzo Stoakes {
1157876320d7SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
1158876320d7SLorenzo Stoakes 	char *ptr;
1159876320d7SLorenzo Stoakes 	int i;
1160876320d7SLorenzo Stoakes 
1161876320d7SLorenzo Stoakes 	/* Map 10 pages. */
1162876320d7SLorenzo Stoakes 	ptr = mmap(NULL, 10 * page_size, PROT_READ | PROT_WRITE,
1163876320d7SLorenzo Stoakes 		   MAP_ANON | MAP_PRIVATE, -1, 0);
1164876320d7SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
1165876320d7SLorenzo Stoakes 
1166876320d7SLorenzo Stoakes 	/* Guard range. */
1167876320d7SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_INSTALL), 0);
1168876320d7SLorenzo Stoakes 
1169876320d7SLorenzo Stoakes 	/* Ensure guarded. */
1170876320d7SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
1171876320d7SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
1172876320d7SLorenzo Stoakes 
1173876320d7SLorenzo Stoakes 		ASSERT_FALSE(try_read_write_buf(curr));
1174876320d7SLorenzo Stoakes 	}
1175876320d7SLorenzo Stoakes 
1176876320d7SLorenzo Stoakes 	/* Lazyfree range. */
1177876320d7SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_FREE), 0);
1178876320d7SLorenzo Stoakes 
1179876320d7SLorenzo Stoakes 	/* This should leave the guard markers in place. */
1180876320d7SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
1181876320d7SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
1182876320d7SLorenzo Stoakes 
1183876320d7SLorenzo Stoakes 		ASSERT_FALSE(try_read_write_buf(curr));
1184876320d7SLorenzo Stoakes 	}
1185876320d7SLorenzo Stoakes 
1186876320d7SLorenzo Stoakes 	/* Cleanup. */
1187876320d7SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
1188876320d7SLorenzo Stoakes }
1189876320d7SLorenzo Stoakes 
1190876320d7SLorenzo Stoakes /* Ensure that MADV_POPULATE_READ, MADV_POPULATE_WRITE behave as expected. */
1191876320d7SLorenzo Stoakes TEST_F(guard_pages, populate)
1192876320d7SLorenzo Stoakes {
1193876320d7SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
1194876320d7SLorenzo Stoakes 	char *ptr;
1195876320d7SLorenzo Stoakes 
1196876320d7SLorenzo Stoakes 	/* Map 10 pages. */
1197876320d7SLorenzo Stoakes 	ptr = mmap(NULL, 10 * page_size, PROT_READ | PROT_WRITE,
1198876320d7SLorenzo Stoakes 		   MAP_ANON | MAP_PRIVATE, -1, 0);
1199876320d7SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
1200876320d7SLorenzo Stoakes 
1201876320d7SLorenzo Stoakes 	/* Guard range. */
1202876320d7SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_INSTALL), 0);
1203876320d7SLorenzo Stoakes 
1204876320d7SLorenzo Stoakes 	/* Populate read should error out... */
1205876320d7SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_POPULATE_READ), -1);
1206876320d7SLorenzo Stoakes 	ASSERT_EQ(errno, EFAULT);
1207876320d7SLorenzo Stoakes 
1208876320d7SLorenzo Stoakes 	/* ...as should populate write. */
1209876320d7SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_POPULATE_WRITE), -1);
1210876320d7SLorenzo Stoakes 	ASSERT_EQ(errno, EFAULT);
1211876320d7SLorenzo Stoakes 
1212876320d7SLorenzo Stoakes 	/* Cleanup. */
1213876320d7SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
1214876320d7SLorenzo Stoakes }
1215876320d7SLorenzo Stoakes 
1216876320d7SLorenzo Stoakes /* Ensure that MADV_COLD, MADV_PAGEOUT do not remove guard markers. */
1217876320d7SLorenzo Stoakes TEST_F(guard_pages, cold_pageout)
1218876320d7SLorenzo Stoakes {
1219876320d7SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
1220876320d7SLorenzo Stoakes 	char *ptr;
1221876320d7SLorenzo Stoakes 	int i;
1222876320d7SLorenzo Stoakes 
1223876320d7SLorenzo Stoakes 	/* Map 10 pages. */
1224876320d7SLorenzo Stoakes 	ptr = mmap(NULL, 10 * page_size, PROT_READ | PROT_WRITE,
1225876320d7SLorenzo Stoakes 		   MAP_ANON | MAP_PRIVATE, -1, 0);
1226876320d7SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
1227876320d7SLorenzo Stoakes 
1228876320d7SLorenzo Stoakes 	/* Guard range. */
1229876320d7SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_INSTALL), 0);
1230876320d7SLorenzo Stoakes 
1231876320d7SLorenzo Stoakes 	/* Ensured guarded. */
1232876320d7SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
1233876320d7SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
1234876320d7SLorenzo Stoakes 
1235876320d7SLorenzo Stoakes 		ASSERT_FALSE(try_read_write_buf(curr));
1236876320d7SLorenzo Stoakes 	}
1237876320d7SLorenzo Stoakes 
1238876320d7SLorenzo Stoakes 	/* Now mark cold. This should have no impact on guard markers. */
1239876320d7SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_COLD), 0);
1240876320d7SLorenzo Stoakes 
1241876320d7SLorenzo Stoakes 	/* Should remain guarded. */
1242876320d7SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
1243876320d7SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
1244876320d7SLorenzo Stoakes 
1245876320d7SLorenzo Stoakes 		ASSERT_FALSE(try_read_write_buf(curr));
1246876320d7SLorenzo Stoakes 	}
1247876320d7SLorenzo Stoakes 
1248876320d7SLorenzo Stoakes 	/* OK, now page out. This should equally, have no effect on markers. */
1249876320d7SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_PAGEOUT), 0);
1250876320d7SLorenzo Stoakes 
1251876320d7SLorenzo Stoakes 	/* Should remain guarded. */
1252876320d7SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
1253876320d7SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
1254876320d7SLorenzo Stoakes 
1255876320d7SLorenzo Stoakes 		ASSERT_FALSE(try_read_write_buf(curr));
1256876320d7SLorenzo Stoakes 	}
1257876320d7SLorenzo Stoakes 
1258876320d7SLorenzo Stoakes 	/* Cleanup. */
1259876320d7SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
1260876320d7SLorenzo Stoakes }
1261876320d7SLorenzo Stoakes 
1262876320d7SLorenzo Stoakes /* Ensure that guard pages do not break userfaultd. */
1263876320d7SLorenzo Stoakes TEST_F(guard_pages, uffd)
1264876320d7SLorenzo Stoakes {
1265876320d7SLorenzo Stoakes 	const unsigned long page_size = self->page_size;
1266876320d7SLorenzo Stoakes 	int uffd;
1267876320d7SLorenzo Stoakes 	char *ptr;
1268876320d7SLorenzo Stoakes 	int i;
1269876320d7SLorenzo Stoakes 	struct uffdio_api api = {
1270876320d7SLorenzo Stoakes 		.api = UFFD_API,
1271876320d7SLorenzo Stoakes 		.features = 0,
1272876320d7SLorenzo Stoakes 	};
1273876320d7SLorenzo Stoakes 	struct uffdio_register reg;
1274876320d7SLorenzo Stoakes 	struct uffdio_range range;
1275876320d7SLorenzo Stoakes 
1276876320d7SLorenzo Stoakes 	/* Set up uffd. */
1277876320d7SLorenzo Stoakes 	uffd = userfaultfd(0);
1278876320d7SLorenzo Stoakes 	if (uffd == -1 && errno == EPERM)
1279876320d7SLorenzo Stoakes 		ksft_exit_skip("No userfaultfd permissions, try running as root.\n");
1280876320d7SLorenzo Stoakes 	ASSERT_NE(uffd, -1);
1281876320d7SLorenzo Stoakes 
1282876320d7SLorenzo Stoakes 	ASSERT_EQ(ioctl(uffd, UFFDIO_API, &api), 0);
1283876320d7SLorenzo Stoakes 
1284876320d7SLorenzo Stoakes 	/* Map 10 pages. */
1285876320d7SLorenzo Stoakes 	ptr = mmap(NULL, 10 * page_size, PROT_READ | PROT_WRITE,
1286876320d7SLorenzo Stoakes 		   MAP_ANON | MAP_PRIVATE, -1, 0);
1287876320d7SLorenzo Stoakes 	ASSERT_NE(ptr, MAP_FAILED);
1288876320d7SLorenzo Stoakes 
1289876320d7SLorenzo Stoakes 	/* Register the range with uffd. */
1290876320d7SLorenzo Stoakes 	range.start = (unsigned long)ptr;
1291876320d7SLorenzo Stoakes 	range.len = 10 * page_size;
1292876320d7SLorenzo Stoakes 	reg.range = range;
1293876320d7SLorenzo Stoakes 	reg.mode = UFFDIO_REGISTER_MODE_MISSING;
1294876320d7SLorenzo Stoakes 	ASSERT_EQ(ioctl(uffd, UFFDIO_REGISTER, &reg), 0);
1295876320d7SLorenzo Stoakes 
1296876320d7SLorenzo Stoakes 	/* Guard the range. This should not trigger the uffd. */
1297876320d7SLorenzo Stoakes 	ASSERT_EQ(madvise(ptr, 10 * page_size, MADV_GUARD_INSTALL), 0);
1298876320d7SLorenzo Stoakes 
1299876320d7SLorenzo Stoakes 	/* The guarding should behave as usual with no uffd intervention. */
1300876320d7SLorenzo Stoakes 	for (i = 0; i < 10; i++) {
1301876320d7SLorenzo Stoakes 		char *curr = &ptr[i * page_size];
1302876320d7SLorenzo Stoakes 
1303876320d7SLorenzo Stoakes 		ASSERT_FALSE(try_read_write_buf(curr));
1304876320d7SLorenzo Stoakes 	}
1305876320d7SLorenzo Stoakes 
1306876320d7SLorenzo Stoakes 	/* Cleanup. */
1307876320d7SLorenzo Stoakes 	ASSERT_EQ(ioctl(uffd, UFFDIO_UNREGISTER, &range), 0);
1308876320d7SLorenzo Stoakes 	close(uffd);
1309876320d7SLorenzo Stoakes 	ASSERT_EQ(munmap(ptr, 10 * page_size), 0);
1310876320d7SLorenzo Stoakes }
1311876320d7SLorenzo Stoakes 
1312876320d7SLorenzo Stoakes TEST_HARNESS_MAIN
1313