xref: /linux/tools/testing/selftests/mm/merge.c (revision af0bc3ac9a9e830cb52b718ecb237c4e76a466be)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 
3 #define _GNU_SOURCE
4 #include "kselftest_harness.h"
5 #include <linux/prctl.h>
6 #include <fcntl.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <sys/mman.h>
11 #include <sys/prctl.h>
12 #include <sys/syscall.h>
13 #include <sys/wait.h>
14 #include <linux/perf_event.h>
15 #include "vm_util.h"
16 #include <linux/mman.h>
17 
18 FIXTURE(merge)
19 {
20 	unsigned int page_size;
21 	char *carveout;
22 	struct procmap_fd procmap;
23 };
24 
25 static char *map_carveout(unsigned int page_size)
26 {
27 	return mmap(NULL, 30 * page_size, PROT_NONE,
28 		    MAP_ANON | MAP_PRIVATE, -1, 0);
29 }
30 
31 static pid_t do_fork(struct procmap_fd *procmap)
32 {
33 	pid_t pid = fork();
34 
35 	if (pid == -1)
36 		return -1;
37 	if (pid != 0) {
38 		wait(NULL);
39 		return pid;
40 	}
41 
42 	/* Reopen for child. */
43 	if (close_procmap(procmap))
44 		return -1;
45 	if (open_self_procmap(procmap))
46 		return -1;
47 
48 	return 0;
49 }
50 
51 FIXTURE_SETUP(merge)
52 {
53 	self->page_size = psize();
54 	/* Carve out PROT_NONE region to map over. */
55 	self->carveout = map_carveout(self->page_size);
56 	ASSERT_NE(self->carveout, MAP_FAILED);
57 	/* Setup PROCMAP_QUERY interface. */
58 	ASSERT_EQ(open_self_procmap(&self->procmap), 0);
59 }
60 
61 FIXTURE_TEARDOWN(merge)
62 {
63 	ASSERT_EQ(munmap(self->carveout, 30 * self->page_size), 0);
64 	/* May fail for parent of forked process. */
65 	close_procmap(&self->procmap);
66 	/*
67 	 * Clear unconditionally, as some tests set this. It is no issue if this
68 	 * fails (KSM may be disabled for instance).
69 	 */
70 	prctl(PR_SET_MEMORY_MERGE, 0, 0, 0, 0);
71 }
72 
73 FIXTURE(merge_with_fork)
74 {
75 	unsigned int page_size;
76 	char *carveout;
77 	struct procmap_fd procmap;
78 };
79 
80 FIXTURE_VARIANT(merge_with_fork)
81 {
82 	bool forked;
83 };
84 
85 FIXTURE_VARIANT_ADD(merge_with_fork, forked)
86 {
87 	.forked = true,
88 };
89 
90 FIXTURE_VARIANT_ADD(merge_with_fork, unforked)
91 {
92 	.forked = false,
93 };
94 
95 FIXTURE_SETUP(merge_with_fork)
96 {
97 	self->page_size = psize();
98 	self->carveout = map_carveout(self->page_size);
99 	ASSERT_NE(self->carveout, MAP_FAILED);
100 	ASSERT_EQ(open_self_procmap(&self->procmap), 0);
101 }
102 
103 FIXTURE_TEARDOWN(merge_with_fork)
104 {
105 	ASSERT_EQ(munmap(self->carveout, 30 * self->page_size), 0);
106 	ASSERT_EQ(close_procmap(&self->procmap), 0);
107 	/* See above. */
108 	prctl(PR_SET_MEMORY_MERGE, 0, 0, 0, 0);
109 }
110 
111 TEST_F(merge, mprotect_unfaulted_left)
112 {
113 	unsigned int page_size = self->page_size;
114 	char *carveout = self->carveout;
115 	struct procmap_fd *procmap = &self->procmap;
116 	char *ptr;
117 
118 	/*
119 	 * Map 10 pages of R/W memory within. MAP_NORESERVE so we don't hit
120 	 * merge failure due to lack of VM_ACCOUNT flag by mistake.
121 	 *
122 	 * |-----------------------|
123 	 * |       unfaulted       |
124 	 * |-----------------------|
125 	 */
126 	ptr = mmap(&carveout[page_size], 10 * page_size, PROT_READ | PROT_WRITE,
127 		   MAP_ANON | MAP_PRIVATE | MAP_FIXED | MAP_NORESERVE, -1, 0);
128 	ASSERT_NE(ptr, MAP_FAILED);
129 	/*
130 	 * Now make the first 5 pages read-only, splitting the VMA:
131 	 *
132 	 *      RO          RW
133 	 * |-----------|-----------|
134 	 * | unfaulted | unfaulted |
135 	 * |-----------|-----------|
136 	 */
137 	ASSERT_EQ(mprotect(ptr, 5 * page_size, PROT_READ), 0);
138 	/*
139 	 * Fault in the first of the last 5 pages so it gets an anon_vma and
140 	 * thus the whole VMA becomes 'faulted':
141 	 *
142 	 *      RO          RW
143 	 * |-----------|-----------|
144 	 * | unfaulted |  faulted  |
145 	 * |-----------|-----------|
146 	 */
147 	ptr[5 * page_size] = 'x';
148 	/*
149 	 * Now mprotect() the RW region read-only, we should merge (though for
150 	 * ~15 years we did not! :):
151 	 *
152 	 *             RO
153 	 * |-----------------------|
154 	 * |        faulted        |
155 	 * |-----------------------|
156 	 */
157 	ASSERT_EQ(mprotect(&ptr[5 * page_size], 5 * page_size, PROT_READ), 0);
158 
159 	/* Assert that the merge succeeded using PROCMAP_QUERY. */
160 	ASSERT_TRUE(find_vma_procmap(procmap, ptr));
161 	ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr);
162 	ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr + 10 * page_size);
163 }
164 
165 TEST_F(merge, mprotect_unfaulted_right)
166 {
167 	unsigned int page_size = self->page_size;
168 	char *carveout = self->carveout;
169 	struct procmap_fd *procmap = &self->procmap;
170 	char *ptr;
171 
172 	/*
173 	 * |-----------------------|
174 	 * |       unfaulted       |
175 	 * |-----------------------|
176 	 */
177 	ptr = mmap(&carveout[page_size], 10 * page_size, PROT_READ | PROT_WRITE,
178 		   MAP_ANON | MAP_PRIVATE | MAP_FIXED | MAP_NORESERVE, -1, 0);
179 	ASSERT_NE(ptr, MAP_FAILED);
180 	/*
181 	 * Now make the last 5 pages read-only, splitting the VMA:
182 	 *
183 	 *      RW          RO
184 	 * |-----------|-----------|
185 	 * | unfaulted | unfaulted |
186 	 * |-----------|-----------|
187 	 */
188 	ASSERT_EQ(mprotect(&ptr[5 * page_size], 5 * page_size, PROT_READ), 0);
189 	/*
190 	 * Fault in the first of the first 5 pages so it gets an anon_vma and
191 	 * thus the whole VMA becomes 'faulted':
192 	 *
193 	 *      RW          RO
194 	 * |-----------|-----------|
195 	 * |  faulted  | unfaulted |
196 	 * |-----------|-----------|
197 	 */
198 	ptr[0] = 'x';
199 	/*
200 	 * Now mprotect() the RW region read-only, we should merge:
201 	 *
202 	 *             RO
203 	 * |-----------------------|
204 	 * |        faulted        |
205 	 * |-----------------------|
206 	 */
207 	ASSERT_EQ(mprotect(ptr, 5 * page_size, PROT_READ), 0);
208 
209 	/* Assert that the merge succeeded using PROCMAP_QUERY. */
210 	ASSERT_TRUE(find_vma_procmap(procmap, ptr));
211 	ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr);
212 	ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr + 10 * page_size);
213 }
214 
215 TEST_F(merge, mprotect_unfaulted_both)
216 {
217 	unsigned int page_size = self->page_size;
218 	char *carveout = self->carveout;
219 	struct procmap_fd *procmap = &self->procmap;
220 	char *ptr;
221 
222 	/*
223 	 * |-----------------------|
224 	 * |       unfaulted       |
225 	 * |-----------------------|
226 	 */
227 	ptr = mmap(&carveout[2 * page_size], 9 * page_size, PROT_READ | PROT_WRITE,
228 		   MAP_ANON | MAP_PRIVATE | MAP_FIXED | MAP_NORESERVE, -1, 0);
229 	ASSERT_NE(ptr, MAP_FAILED);
230 	/*
231 	 * Now make the first and last 3 pages read-only, splitting the VMA:
232 	 *
233 	 *      RO          RW          RO
234 	 * |-----------|-----------|-----------|
235 	 * | unfaulted | unfaulted | unfaulted |
236 	 * |-----------|-----------|-----------|
237 	 */
238 	ASSERT_EQ(mprotect(ptr, 3 * page_size, PROT_READ), 0);
239 	ASSERT_EQ(mprotect(&ptr[6 * page_size], 3 * page_size, PROT_READ), 0);
240 	/*
241 	 * Fault in the first of the middle 3 pages so it gets an anon_vma and
242 	 * thus the whole VMA becomes 'faulted':
243 	 *
244 	 *      RO          RW          RO
245 	 * |-----------|-----------|-----------|
246 	 * | unfaulted |  faulted  | unfaulted |
247 	 * |-----------|-----------|-----------|
248 	 */
249 	ptr[3 * page_size] = 'x';
250 	/*
251 	 * Now mprotect() the RW region read-only, we should merge:
252 	 *
253 	 *             RO
254 	 * |-----------------------|
255 	 * |        faulted        |
256 	 * |-----------------------|
257 	 */
258 	ASSERT_EQ(mprotect(&ptr[3 * page_size], 3 * page_size, PROT_READ), 0);
259 
260 	/* Assert that the merge succeeded using PROCMAP_QUERY. */
261 	ASSERT_TRUE(find_vma_procmap(procmap, ptr));
262 	ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr);
263 	ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr + 9 * page_size);
264 }
265 
266 TEST_F(merge, mprotect_faulted_left_unfaulted_right)
267 {
268 	unsigned int page_size = self->page_size;
269 	char *carveout = self->carveout;
270 	struct procmap_fd *procmap = &self->procmap;
271 	char *ptr;
272 
273 	/*
274 	 * |-----------------------|
275 	 * |       unfaulted       |
276 	 * |-----------------------|
277 	 */
278 	ptr = mmap(&carveout[2 * page_size], 9 * page_size, PROT_READ | PROT_WRITE,
279 		   MAP_ANON | MAP_PRIVATE | MAP_FIXED | MAP_NORESERVE, -1, 0);
280 	ASSERT_NE(ptr, MAP_FAILED);
281 	/*
282 	 * Now make the last 3 pages read-only, splitting the VMA:
283 	 *
284 	 *             RW               RO
285 	 * |-----------------------|-----------|
286 	 * |       unfaulted       | unfaulted |
287 	 * |-----------------------|-----------|
288 	 */
289 	ASSERT_EQ(mprotect(&ptr[6 * page_size], 3 * page_size, PROT_READ), 0);
290 	/*
291 	 * Fault in the first of the first 6 pages so it gets an anon_vma and
292 	 * thus the whole VMA becomes 'faulted':
293 	 *
294 	 *             RW               RO
295 	 * |-----------------------|-----------|
296 	 * |       unfaulted       | unfaulted |
297 	 * |-----------------------|-----------|
298 	 */
299 	ptr[0] = 'x';
300 	/*
301 	 * Now make the first 3 pages read-only, splitting the VMA:
302 	 *
303 	 *      RO          RW          RO
304 	 * |-----------|-----------|-----------|
305 	 * |  faulted  |  faulted  | unfaulted |
306 	 * |-----------|-----------|-----------|
307 	 */
308 	ASSERT_EQ(mprotect(ptr, 3 * page_size, PROT_READ), 0);
309 	/*
310 	 * Now mprotect() the RW region read-only, we should merge:
311 	 *
312 	 *             RO
313 	 * |-----------------------|
314 	 * |        faulted        |
315 	 * |-----------------------|
316 	 */
317 	ASSERT_EQ(mprotect(&ptr[3 * page_size], 3 * page_size, PROT_READ), 0);
318 
319 	/* Assert that the merge succeeded using PROCMAP_QUERY. */
320 	ASSERT_TRUE(find_vma_procmap(procmap, ptr));
321 	ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr);
322 	ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr + 9 * page_size);
323 }
324 
325 TEST_F(merge, mprotect_unfaulted_left_faulted_right)
326 {
327 	unsigned int page_size = self->page_size;
328 	char *carveout = self->carveout;
329 	struct procmap_fd *procmap = &self->procmap;
330 	char *ptr;
331 
332 	/*
333 	 * |-----------------------|
334 	 * |       unfaulted       |
335 	 * |-----------------------|
336 	 */
337 	ptr = mmap(&carveout[2 * page_size], 9 * page_size, PROT_READ | PROT_WRITE,
338 		   MAP_ANON | MAP_PRIVATE | MAP_FIXED | MAP_NORESERVE, -1, 0);
339 	ASSERT_NE(ptr, MAP_FAILED);
340 	/*
341 	 * Now make the first 3 pages read-only, splitting the VMA:
342 	 *
343 	 *      RO                RW
344 	 * |-----------|-----------------------|
345 	 * | unfaulted |       unfaulted       |
346 	 * |-----------|-----------------------|
347 	 */
348 	ASSERT_EQ(mprotect(ptr, 3 * page_size, PROT_READ), 0);
349 	/*
350 	 * Fault in the first of the last 6 pages so it gets an anon_vma and
351 	 * thus the whole VMA becomes 'faulted':
352 	 *
353 	 *      RO                RW
354 	 * |-----------|-----------------------|
355 	 * | unfaulted |        faulted        |
356 	 * |-----------|-----------------------|
357 	 */
358 	ptr[3 * page_size] = 'x';
359 	/*
360 	 * Now make the last 3 pages read-only, splitting the VMA:
361 	 *
362 	 *      RO          RW          RO
363 	 * |-----------|-----------|-----------|
364 	 * | unfaulted |  faulted  |  faulted  |
365 	 * |-----------|-----------|-----------|
366 	 */
367 	ASSERT_EQ(mprotect(&ptr[6 * page_size], 3 * page_size, PROT_READ), 0);
368 	/*
369 	 * Now mprotect() the RW region read-only, we should merge:
370 	 *
371 	 *             RO
372 	 * |-----------------------|
373 	 * |        faulted        |
374 	 * |-----------------------|
375 	 */
376 	ASSERT_EQ(mprotect(&ptr[3 * page_size], 3 * page_size, PROT_READ), 0);
377 
378 	/* Assert that the merge succeeded using PROCMAP_QUERY. */
379 	ASSERT_TRUE(find_vma_procmap(procmap, ptr));
380 	ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr);
381 	ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr + 9 * page_size);
382 }
383 
384 TEST_F(merge, forked_target_vma)
385 {
386 	unsigned int page_size = self->page_size;
387 	char *carveout = self->carveout;
388 	struct procmap_fd *procmap = &self->procmap;
389 	char *ptr, *ptr2;
390 	pid_t pid;
391 	int i;
392 
393 	/*
394 	 * |-----------|
395 	 * | unfaulted |
396 	 * |-----------|
397 	 */
398 	ptr = mmap(&carveout[page_size], 5 * page_size, PROT_READ | PROT_WRITE,
399 		   MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0);
400 	ASSERT_NE(ptr, MAP_FAILED);
401 
402 	/*
403 	 * Fault in process.
404 	 *
405 	 * |-----------|
406 	 * |  faulted  |
407 	 * |-----------|
408 	 */
409 	ptr[0] = 'x';
410 
411 	pid = do_fork(&self->procmap);
412 	ASSERT_NE(pid, -1);
413 	if (pid != 0)
414 		return;
415 
416 	/* unCOWing everything does not cause the AVC to go away. */
417 	for (i = 0; i < 5 * page_size; i += page_size)
418 		ptr[i] = 'x';
419 
420 	/*
421 	 * Map in adjacent VMA in child.
422 	 *
423 	 *     forked
424 	 * |-----------|-----------|
425 	 * |  faulted  | unfaulted |
426 	 * |-----------|-----------|
427 	 *      ptr         ptr2
428 	 */
429 	ptr2 = mmap(&ptr[5 * page_size], 5 * page_size, PROT_READ | PROT_WRITE,
430 		   MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0);
431 	ASSERT_NE(ptr2, MAP_FAILED);
432 
433 	/* Make sure not merged. */
434 	ASSERT_TRUE(find_vma_procmap(procmap, ptr));
435 	ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr);
436 	ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr + 5 * page_size);
437 }
438 
439 TEST_F(merge, forked_source_vma)
440 {
441 	unsigned int page_size = self->page_size;
442 	char *carveout = self->carveout;
443 	struct procmap_fd *procmap = &self->procmap;
444 	char *ptr, *ptr2;
445 	pid_t pid;
446 	int i;
447 
448 	/*
449 	 * |-----------|------------|
450 	 * | unfaulted | <unmapped> |
451 	 * |-----------|------------|
452 	 */
453 	ptr = mmap(&carveout[page_size], 5 * page_size, PROT_READ | PROT_WRITE,
454 		   MAP_ANON | MAP_PRIVATE | MAP_FIXED | MAP_NORESERVE, -1, 0);
455 	ASSERT_NE(ptr, MAP_FAILED);
456 
457 	/*
458 	 * Fault in process.
459 	 *
460 	 * |-----------|------------|
461 	 * |  faulted  | <unmapped> |
462 	 * |-----------|------------|
463 	 */
464 	ptr[0] = 'x';
465 
466 	pid = do_fork(&self->procmap);
467 	ASSERT_NE(pid, -1);
468 	if (pid != 0)
469 		return;
470 
471 	/* unCOWing everything does not cause the AVC to go away. */
472 	for (i = 0; i < 5 * page_size; i += page_size)
473 		ptr[i] = 'x';
474 
475 	/*
476 	 * Map in adjacent VMA in child, ptr2 after ptr, but incompatible.
477 	 *
478 	 *   forked RW      RWX
479 	 * |-----------|-----------|
480 	 * |  faulted  | unfaulted |
481 	 * |-----------|-----------|
482 	 *      ptr        ptr2
483 	 */
484 	ptr2 = mmap(&carveout[6 * page_size], 5 * page_size, PROT_READ | PROT_WRITE | PROT_EXEC,
485 		   MAP_ANON | MAP_PRIVATE | MAP_FIXED | MAP_NORESERVE, -1, 0);
486 	ASSERT_NE(ptr2, MAP_FAILED);
487 
488 	/* Make sure not merged. */
489 	ASSERT_TRUE(find_vma_procmap(procmap, ptr2));
490 	ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr2);
491 	ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr2 + 5 * page_size);
492 
493 	/*
494 	 * Now mprotect forked region to RWX so it becomes the source for the
495 	 * merge to unfaulted region:
496 	 *
497 	 *  forked RWX      RWX
498 	 * |-----------|-----------|
499 	 * |  faulted  | unfaulted |
500 	 * |-----------|-----------|
501 	 *      ptr         ptr2
502 	 *
503 	 * This should NOT result in a merge, as ptr was forked.
504 	 */
505 	ASSERT_EQ(mprotect(ptr, 5 * page_size, PROT_READ | PROT_WRITE | PROT_EXEC), 0);
506 	/* Again, make sure not merged. */
507 	ASSERT_TRUE(find_vma_procmap(procmap, ptr2));
508 	ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr2);
509 	ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr2 + 5 * page_size);
510 }
511 
512 TEST_F(merge, handle_uprobe_upon_merged_vma)
513 {
514 	const size_t attr_sz = sizeof(struct perf_event_attr);
515 	unsigned int page_size = self->page_size;
516 	const char *probe_file = "./foo";
517 	char *carveout = self->carveout;
518 	struct perf_event_attr attr;
519 	unsigned long type;
520 	void *ptr1, *ptr2;
521 	int fd;
522 
523 	fd = open(probe_file, O_RDWR|O_CREAT, 0600);
524 	ASSERT_GE(fd, 0);
525 
526 	ASSERT_EQ(ftruncate(fd, page_size), 0);
527 	if (read_sysfs("/sys/bus/event_source/devices/uprobe/type", &type) != 0) {
528 		SKIP(goto out, "Failed to read uprobe sysfs file, skipping");
529 	}
530 
531 	memset(&attr, 0, attr_sz);
532 	attr.size = attr_sz;
533 	attr.type = type;
534 	attr.config1 = (__u64)(long)probe_file;
535 	attr.config2 = 0x0;
536 
537 	ASSERT_GE(syscall(__NR_perf_event_open, &attr, 0, -1, -1, 0), 0);
538 
539 	ptr1 = mmap(&carveout[page_size], 10 * page_size, PROT_EXEC,
540 		    MAP_PRIVATE | MAP_FIXED, fd, 0);
541 	ASSERT_NE(ptr1, MAP_FAILED);
542 
543 	ptr2 = mremap(ptr1, page_size, 2 * page_size,
544 		      MREMAP_MAYMOVE | MREMAP_FIXED, ptr1 + 5 * page_size);
545 	ASSERT_NE(ptr2, MAP_FAILED);
546 
547 	ASSERT_NE(mremap(ptr2, page_size, page_size,
548 			 MREMAP_MAYMOVE | MREMAP_FIXED, ptr1), MAP_FAILED);
549 
550 out:
551 	close(fd);
552 	remove(probe_file);
553 }
554 
555 TEST_F(merge, ksm_merge)
556 {
557 	unsigned int page_size = self->page_size;
558 	char *carveout = self->carveout;
559 	struct procmap_fd *procmap = &self->procmap;
560 	char *ptr, *ptr2;
561 	int err;
562 
563 	/*
564 	 * Map two R/W immediately adjacent to one another, they should
565 	 * trivially merge:
566 	 *
567 	 * |-----------|-----------|
568 	 * |    R/W    |    R/W    |
569 	 * |-----------|-----------|
570 	 *      ptr         ptr2
571 	 */
572 
573 	ptr = mmap(&carveout[page_size], page_size, PROT_READ | PROT_WRITE,
574 		   MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0);
575 	ASSERT_NE(ptr, MAP_FAILED);
576 	ptr2 = mmap(&carveout[2 * page_size], page_size,
577 		    PROT_READ | PROT_WRITE,
578 		    MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0);
579 	ASSERT_NE(ptr2, MAP_FAILED);
580 	ASSERT_TRUE(find_vma_procmap(procmap, ptr));
581 	ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr);
582 	ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr + 2 * page_size);
583 
584 	/* Unmap the second half of this merged VMA. */
585 	ASSERT_EQ(munmap(ptr2, page_size), 0);
586 
587 	/* OK, now enable global KSM merge. We clear this on test teardown. */
588 	err = prctl(PR_SET_MEMORY_MERGE, 1, 0, 0, 0);
589 	if (err == -1) {
590 		int errnum = errno;
591 
592 		/* Only non-failure case... */
593 		ASSERT_EQ(errnum, EINVAL);
594 		/* ...but indicates we should skip. */
595 		SKIP(return, "KSM memory merging not supported, skipping.");
596 	}
597 
598 	/*
599 	 * Now map a VMA adjacent to the existing that was just made
600 	 * VM_MERGEABLE, this should merge as well.
601 	 */
602 	ptr2 = mmap(&carveout[2 * page_size], page_size,
603 		    PROT_READ | PROT_WRITE,
604 		    MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0);
605 	ASSERT_NE(ptr2, MAP_FAILED);
606 	ASSERT_TRUE(find_vma_procmap(procmap, ptr));
607 	ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr);
608 	ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr + 2 * page_size);
609 
610 	/* Now this VMA altogether. */
611 	ASSERT_EQ(munmap(ptr, 2 * page_size), 0);
612 
613 	/* Try the same operation as before, asserting this also merges fine. */
614 	ptr = mmap(&carveout[page_size], page_size, PROT_READ | PROT_WRITE,
615 		   MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0);
616 	ASSERT_NE(ptr, MAP_FAILED);
617 	ptr2 = mmap(&carveout[2 * page_size], page_size,
618 		    PROT_READ | PROT_WRITE,
619 		    MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0);
620 	ASSERT_NE(ptr2, MAP_FAILED);
621 	ASSERT_TRUE(find_vma_procmap(procmap, ptr));
622 	ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr);
623 	ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr + 2 * page_size);
624 }
625 
626 TEST_F(merge, mremap_unfaulted_to_faulted)
627 {
628 	unsigned int page_size = self->page_size;
629 	char *carveout = self->carveout;
630 	struct procmap_fd *procmap = &self->procmap;
631 	char *ptr, *ptr2;
632 
633 	/*
634 	 * Map two distinct areas:
635 	 *
636 	 * |-----------|  |-----------|
637 	 * | unfaulted |  | unfaulted |
638 	 * |-----------|  |-----------|
639 	 *      ptr            ptr2
640 	 */
641 	ptr = mmap(&carveout[page_size], 5 * page_size, PROT_READ | PROT_WRITE,
642 		   MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0);
643 	ASSERT_NE(ptr, MAP_FAILED);
644 	ptr2 = mmap(&carveout[7 * page_size], 5 * page_size, PROT_READ | PROT_WRITE,
645 		    MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0);
646 	ASSERT_NE(ptr2, MAP_FAILED);
647 
648 	/* Offset ptr2 further away. */
649 	ptr2 = sys_mremap(ptr2, 5 * page_size, 5 * page_size,
650 			  MREMAP_MAYMOVE | MREMAP_FIXED, ptr2 + page_size * 1000);
651 	ASSERT_NE(ptr2, MAP_FAILED);
652 
653 	/*
654 	 * Fault in ptr:
655 	 *                \
656 	 * |-----------|  /  |-----------|
657 	 * |  faulted  |  \  | unfaulted |
658 	 * |-----------|  /  |-----------|
659 	 *      ptr       \       ptr2
660 	 */
661 	ptr[0] = 'x';
662 
663 	/*
664 	 * Now move ptr2 adjacent to ptr:
665 	 *
666 	 * |-----------|-----------|
667 	 * |  faulted  | unfaulted |
668 	 * |-----------|-----------|
669 	 *      ptr         ptr2
670 	 *
671 	 * It should merge:
672 	 *
673 	 * |----------------------|
674 	 * |       faulted        |
675 	 * |----------------------|
676 	 *            ptr
677 	 */
678 	ptr2 = sys_mremap(ptr2, 5 * page_size, 5 * page_size,
679 			  MREMAP_MAYMOVE | MREMAP_FIXED, &ptr[5 * page_size]);
680 	ASSERT_NE(ptr2, MAP_FAILED);
681 
682 	ASSERT_TRUE(find_vma_procmap(procmap, ptr));
683 	ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr);
684 	ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr + 10 * page_size);
685 }
686 
687 TEST_F(merge, mremap_unfaulted_behind_faulted)
688 {
689 	unsigned int page_size = self->page_size;
690 	char *carveout = self->carveout;
691 	struct procmap_fd *procmap = &self->procmap;
692 	char *ptr, *ptr2;
693 
694 	/*
695 	 * Map two distinct areas:
696 	 *
697 	 * |-----------|  |-----------|
698 	 * | unfaulted |  | unfaulted |
699 	 * |-----------|  |-----------|
700 	 *      ptr            ptr2
701 	 */
702 	ptr = mmap(&carveout[6 * page_size], 5 * page_size, PROT_READ | PROT_WRITE,
703 		   MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0);
704 	ASSERT_NE(ptr, MAP_FAILED);
705 	ptr2 = mmap(&carveout[14 * page_size], 5 * page_size, PROT_READ | PROT_WRITE,
706 		    MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0);
707 	ASSERT_NE(ptr2, MAP_FAILED);
708 
709 	/* Offset ptr2 further away. */
710 	ptr2 = sys_mremap(ptr2, 5 * page_size, 5 * page_size,
711 			  MREMAP_MAYMOVE | MREMAP_FIXED, ptr2 + page_size * 1000);
712 	ASSERT_NE(ptr2, MAP_FAILED);
713 
714 	/*
715 	 * Fault in ptr:
716 	 *                \
717 	 * |-----------|  /  |-----------|
718 	 * |  faulted  |  \  | unfaulted |
719 	 * |-----------|  /  |-----------|
720 	 *      ptr       \       ptr2
721 	 */
722 	ptr[0] = 'x';
723 
724 	/*
725 	 * Now move ptr2 adjacent, but behind, ptr:
726 	 *
727 	 * |-----------|-----------|
728 	 * | unfaulted |  faulted  |
729 	 * |-----------|-----------|
730 	 *      ptr2        ptr
731 	 *
732 	 * It should merge:
733 	 *
734 	 * |----------------------|
735 	 * |       faulted        |
736 	 * |----------------------|
737 	 *            ptr2
738 	 */
739 	ptr2 = sys_mremap(ptr2, 5 * page_size, 5 * page_size,
740 			  MREMAP_MAYMOVE | MREMAP_FIXED, &carveout[page_size]);
741 	ASSERT_NE(ptr2, MAP_FAILED);
742 
743 	ASSERT_TRUE(find_vma_procmap(procmap, ptr2));
744 	ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr2);
745 	ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr2 + 10 * page_size);
746 }
747 
748 TEST_F(merge, mremap_unfaulted_between_faulted)
749 {
750 	unsigned int page_size = self->page_size;
751 	char *carveout = self->carveout;
752 	struct procmap_fd *procmap = &self->procmap;
753 	char *ptr, *ptr2, *ptr3;
754 
755 	/*
756 	 * Map three distinct areas:
757 	 *
758 	 * |-----------|  |-----------|  |-----------|
759 	 * | unfaulted |  | unfaulted |  | unfaulted |
760 	 * |-----------|  |-----------|  |-----------|
761 	 *      ptr            ptr2           ptr3
762 	 */
763 	ptr = mmap(&carveout[page_size], 5 * page_size, PROT_READ | PROT_WRITE,
764 		   MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0);
765 	ASSERT_NE(ptr, MAP_FAILED);
766 	ptr2 = mmap(&carveout[7 * page_size], 5 * page_size, PROT_READ | PROT_WRITE,
767 		    MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0);
768 	ASSERT_NE(ptr2, MAP_FAILED);
769 	ptr3 = mmap(&carveout[14 * page_size], 5 * page_size, PROT_READ | PROT_WRITE,
770 		    MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0);
771 	ASSERT_NE(ptr3, MAP_FAILED);
772 
773 	/* Offset ptr3 further away. */
774 	ptr3 = sys_mremap(ptr3, 5 * page_size, 5 * page_size,
775 			  MREMAP_MAYMOVE | MREMAP_FIXED, ptr3 + page_size * 2000);
776 	ASSERT_NE(ptr3, MAP_FAILED);
777 
778 	/* Offset ptr2 further away. */
779 	ptr2 = sys_mremap(ptr2, 5 * page_size, 5 * page_size,
780 			  MREMAP_MAYMOVE | MREMAP_FIXED, ptr2 + page_size * 1000);
781 	ASSERT_NE(ptr2, MAP_FAILED);
782 
783 	/*
784 	 * Fault in ptr, ptr3:
785 	 *                \                 \
786 	 * |-----------|  /  |-----------|  /  |-----------|
787 	 * |  faulted  |  \  | unfaulted |  \  |  faulted  |
788 	 * |-----------|  /  |-----------|  /  |-----------|
789 	 *      ptr       \       ptr2      \       ptr3
790 	 */
791 	ptr[0] = 'x';
792 	ptr3[0] = 'x';
793 
794 	/*
795 	 * Move ptr3 back into place, leaving a place for ptr2:
796 	 *                                        \
797 	 * |-----------|           |-----------|  /  |-----------|
798 	 * |  faulted  |           |  faulted  |  \  | unfaulted |
799 	 * |-----------|           |-----------|  /  |-----------|
800 	 *      ptr                     ptr3      \       ptr2
801 	 */
802 	ptr3 = sys_mremap(ptr3, 5 * page_size, 5 * page_size,
803 			  MREMAP_MAYMOVE | MREMAP_FIXED, &ptr[10 * page_size]);
804 	ASSERT_NE(ptr3, MAP_FAILED);
805 
806 	/*
807 	 * Finally, move ptr2 into place:
808 	 *
809 	 * |-----------|-----------|-----------|
810 	 * |  faulted  | unfaulted |  faulted  |
811 	 * |-----------|-----------|-----------|
812 	 *      ptr        ptr2         ptr3
813 	 *
814 	 * It should merge, but only ptr, ptr2:
815 	 *
816 	 * |-----------------------|-----------|
817 	 * |        faulted        | unfaulted |
818 	 * |-----------------------|-----------|
819 	 */
820 	ptr2 = sys_mremap(ptr2, 5 * page_size, 5 * page_size,
821 			  MREMAP_MAYMOVE | MREMAP_FIXED, &ptr[5 * page_size]);
822 	ASSERT_NE(ptr2, MAP_FAILED);
823 
824 	ASSERT_TRUE(find_vma_procmap(procmap, ptr));
825 	ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr);
826 	ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr + 10 * page_size);
827 
828 	ASSERT_TRUE(find_vma_procmap(procmap, ptr3));
829 	ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr3);
830 	ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr3 + 5 * page_size);
831 }
832 
833 TEST_F(merge, mremap_unfaulted_between_faulted_unfaulted)
834 {
835 	unsigned int page_size = self->page_size;
836 	char *carveout = self->carveout;
837 	struct procmap_fd *procmap = &self->procmap;
838 	char *ptr, *ptr2, *ptr3;
839 
840 	/*
841 	 * Map three distinct areas:
842 	 *
843 	 * |-----------|  |-----------|  |-----------|
844 	 * | unfaulted |  | unfaulted |  | unfaulted |
845 	 * |-----------|  |-----------|  |-----------|
846 	 *      ptr            ptr2           ptr3
847 	 */
848 	ptr = mmap(&carveout[page_size], 5 * page_size, PROT_READ | PROT_WRITE,
849 		   MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0);
850 	ASSERT_NE(ptr, MAP_FAILED);
851 	ptr2 = mmap(&carveout[7 * page_size], 5 * page_size, PROT_READ | PROT_WRITE,
852 		    MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0);
853 	ASSERT_NE(ptr2, MAP_FAILED);
854 	ptr3 = mmap(&carveout[14 * page_size], 5 * page_size, PROT_READ | PROT_WRITE,
855 		    MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0);
856 	ASSERT_NE(ptr3, MAP_FAILED);
857 
858 	/* Offset ptr3 further away. */
859 	ptr3 = sys_mremap(ptr3, 5 * page_size, 5 * page_size,
860 			  MREMAP_MAYMOVE | MREMAP_FIXED, ptr3 + page_size * 2000);
861 	ASSERT_NE(ptr3, MAP_FAILED);
862 
863 
864 	/* Offset ptr2 further away. */
865 	ptr2 = sys_mremap(ptr2, 5 * page_size, 5 * page_size,
866 			  MREMAP_MAYMOVE | MREMAP_FIXED, ptr2 + page_size * 1000);
867 	ASSERT_NE(ptr2, MAP_FAILED);
868 
869 	/*
870 	 * Fault in ptr:
871 	 *                \                 \
872 	 * |-----------|  /  |-----------|  /  |-----------|
873 	 * |  faulted  |  \  | unfaulted |  \  | unfaulted |
874 	 * |-----------|  /  |-----------|  /  |-----------|
875 	 *      ptr       \       ptr2      \       ptr3
876 	 */
877 	ptr[0] = 'x';
878 
879 	/*
880 	 * Move ptr3 back into place, leaving a place for ptr2:
881 	 *                                        \
882 	 * |-----------|           |-----------|  /  |-----------|
883 	 * |  faulted  |           | unfaulted |  \  | unfaulted |
884 	 * |-----------|           |-----------|  /  |-----------|
885 	 *      ptr                     ptr3      \       ptr2
886 	 */
887 	ptr3 = sys_mremap(ptr3, 5 * page_size, 5 * page_size,
888 			  MREMAP_MAYMOVE | MREMAP_FIXED, &ptr[10 * page_size]);
889 	ASSERT_NE(ptr3, MAP_FAILED);
890 
891 	/*
892 	 * Finally, move ptr2 into place:
893 	 *
894 	 * |-----------|-----------|-----------|
895 	 * |  faulted  | unfaulted | unfaulted |
896 	 * |-----------|-----------|-----------|
897 	 *      ptr        ptr2         ptr3
898 	 *
899 	 * It should merge:
900 	 *
901 	 * |-----------------------------------|
902 	 * |              faulted              |
903 	 * |-----------------------------------|
904 	 */
905 	ptr2 = sys_mremap(ptr2, 5 * page_size, 5 * page_size,
906 			  MREMAP_MAYMOVE | MREMAP_FIXED, &ptr[5 * page_size]);
907 	ASSERT_NE(ptr2, MAP_FAILED);
908 
909 	ASSERT_TRUE(find_vma_procmap(procmap, ptr));
910 	ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr);
911 	ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr + 15 * page_size);
912 }
913 
914 TEST_F(merge, mremap_unfaulted_between_correctly_placed_faulted)
915 {
916 	unsigned int page_size = self->page_size;
917 	char *carveout = self->carveout;
918 	struct procmap_fd *procmap = &self->procmap;
919 	char *ptr, *ptr2;
920 
921 	/*
922 	 * Map one larger area:
923 	 *
924 	 * |-----------------------------------|
925 	 * |            unfaulted              |
926 	 * |-----------------------------------|
927 	 */
928 	ptr = mmap(&carveout[page_size], 15 * page_size, PROT_READ | PROT_WRITE,
929 		   MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0);
930 	ASSERT_NE(ptr, MAP_FAILED);
931 
932 	/*
933 	 * Fault in ptr:
934 	 *
935 	 * |-----------------------------------|
936 	 * |              faulted              |
937 	 * |-----------------------------------|
938 	 */
939 	ptr[0] = 'x';
940 
941 	/*
942 	 * Unmap middle:
943 	 *
944 	 * |-----------|           |-----------|
945 	 * |  faulted  |           |  faulted  |
946 	 * |-----------|           |-----------|
947 	 *
948 	 * Now the faulted areas are compatible with each other (anon_vma the
949 	 * same, vma->vm_pgoff equal to virtual page offset).
950 	 */
951 	ASSERT_EQ(munmap(&ptr[5 * page_size], 5 * page_size), 0);
952 
953 	/*
954 	 * Map a new area, ptr2:
955 	 *                                        \
956 	 * |-----------|           |-----------|  /  |-----------|
957 	 * |  faulted  |           |  faulted  |  \  | unfaulted |
958 	 * |-----------|           |-----------|  /  |-----------|
959 	 *      ptr                               \       ptr2
960 	 */
961 	ptr2 = mmap(&carveout[20 * page_size], 5 * page_size, PROT_READ | PROT_WRITE,
962 		    MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0);
963 	ASSERT_NE(ptr2, MAP_FAILED);
964 
965 	/*
966 	 * Finally, move ptr2 into place:
967 	 *
968 	 * |-----------|-----------|-----------|
969 	 * |  faulted  | unfaulted |  faulted  |
970 	 * |-----------|-----------|-----------|
971 	 *      ptr        ptr2         ptr3
972 	 *
973 	 * It should merge:
974 	 *
975 	 * |-----------------------------------|
976 	 * |              faulted              |
977 	 * |-----------------------------------|
978 	 */
979 	ptr2 = sys_mremap(ptr2, 5 * page_size, 5 * page_size,
980 			  MREMAP_MAYMOVE | MREMAP_FIXED, &ptr[5 * page_size]);
981 	ASSERT_NE(ptr2, MAP_FAILED);
982 
983 	ASSERT_TRUE(find_vma_procmap(procmap, ptr));
984 	ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr);
985 	ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr + 15 * page_size);
986 }
987 
988 TEST_F(merge, mremap_correct_placed_faulted)
989 {
990 	unsigned int page_size = self->page_size;
991 	char *carveout = self->carveout;
992 	struct procmap_fd *procmap = &self->procmap;
993 	char *ptr, *ptr2, *ptr3;
994 
995 	/*
996 	 * Map one larger area:
997 	 *
998 	 * |-----------------------------------|
999 	 * |            unfaulted              |
1000 	 * |-----------------------------------|
1001 	 */
1002 	ptr = mmap(&carveout[page_size], 15 * page_size, PROT_READ | PROT_WRITE,
1003 		   MAP_ANON | MAP_PRIVATE | MAP_FIXED, -1, 0);
1004 	ASSERT_NE(ptr, MAP_FAILED);
1005 
1006 	/*
1007 	 * Fault in ptr:
1008 	 *
1009 	 * |-----------------------------------|
1010 	 * |              faulted              |
1011 	 * |-----------------------------------|
1012 	 */
1013 	ptr[0] = 'x';
1014 
1015 	/*
1016 	 * Offset the final and middle 5 pages further away:
1017 	 *                \                 \
1018 	 * |-----------|  /  |-----------|  /  |-----------|
1019 	 * |  faulted  |  \  |  faulted  |  \  |  faulted  |
1020 	 * |-----------|  /  |-----------|  /  |-----------|
1021 	 *      ptr       \       ptr2      \       ptr3
1022 	 */
1023 	ptr3 = &ptr[10 * page_size];
1024 	ptr3 = sys_mremap(ptr3, 5 * page_size, 5 * page_size,
1025 			  MREMAP_MAYMOVE | MREMAP_FIXED, ptr3 + page_size * 2000);
1026 	ASSERT_NE(ptr3, MAP_FAILED);
1027 	ptr2 = &ptr[5 * page_size];
1028 	ptr2 = sys_mremap(ptr2, 5 * page_size, 5 * page_size,
1029 			  MREMAP_MAYMOVE | MREMAP_FIXED, ptr2 + page_size * 1000);
1030 	ASSERT_NE(ptr2, MAP_FAILED);
1031 
1032 	/*
1033 	 * Move ptr2 into its correct place:
1034 	 *                            \
1035 	 * |-----------|-----------|  /  |-----------|
1036 	 * |  faulted  |  faulted  |  \  |  faulted  |
1037 	 * |-----------|-----------|  /  |-----------|
1038 	 *      ptr         ptr2      \       ptr3
1039 	 *
1040 	 * It should merge:
1041 	 *                            \
1042 	 * |-----------------------|  /  |-----------|
1043 	 * |        faulted        |  \  |  faulted  |
1044 	 * |-----------------------|  /  |-----------|
1045 	 *            ptr             \       ptr3
1046 	 */
1047 
1048 	ptr2 = sys_mremap(ptr2, 5 * page_size, 5 * page_size,
1049 			  MREMAP_MAYMOVE | MREMAP_FIXED, &ptr[5 * page_size]);
1050 	ASSERT_NE(ptr2, MAP_FAILED);
1051 
1052 	ASSERT_TRUE(find_vma_procmap(procmap, ptr));
1053 	ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr);
1054 	ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr + 10 * page_size);
1055 
1056 	/*
1057 	 * Now move ptr out of place:
1058 	 *                            \                 \
1059 	 *             |-----------|  /  |-----------|  /  |-----------|
1060 	 *             |  faulted  |  \  |  faulted  |  \  |  faulted  |
1061 	 *             |-----------|  /  |-----------|  /  |-----------|
1062 	 *                  ptr2      \       ptr       \       ptr3
1063 	 */
1064 	ptr = sys_mremap(ptr, 5 * page_size, 5 * page_size,
1065 			 MREMAP_MAYMOVE | MREMAP_FIXED, ptr + page_size * 1000);
1066 	ASSERT_NE(ptr, MAP_FAILED);
1067 
1068 	/*
1069 	 * Now move ptr back into place:
1070 	 *                            \
1071 	 * |-----------|-----------|  /  |-----------|
1072 	 * |  faulted  |  faulted  |  \  |  faulted  |
1073 	 * |-----------|-----------|  /  |-----------|
1074 	 *      ptr         ptr2      \       ptr3
1075 	 *
1076 	 * It should merge:
1077 	 *                            \
1078 	 * |-----------------------|  /  |-----------|
1079 	 * |        faulted        |  \  |  faulted  |
1080 	 * |-----------------------|  /  |-----------|
1081 	 *            ptr             \       ptr3
1082 	 */
1083 	ptr = sys_mremap(ptr, 5 * page_size, 5 * page_size,
1084 			 MREMAP_MAYMOVE | MREMAP_FIXED, &carveout[page_size]);
1085 	ASSERT_NE(ptr, MAP_FAILED);
1086 
1087 	ASSERT_TRUE(find_vma_procmap(procmap, ptr));
1088 	ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr);
1089 	ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr + 10 * page_size);
1090 
1091 	/*
1092 	 * Now move ptr out of place again:
1093 	 *                            \                 \
1094 	 *             |-----------|  /  |-----------|  /  |-----------|
1095 	 *             |  faulted  |  \  |  faulted  |  \  |  faulted  |
1096 	 *             |-----------|  /  |-----------|  /  |-----------|
1097 	 *                  ptr2      \       ptr       \       ptr3
1098 	 */
1099 	ptr = sys_mremap(ptr, 5 * page_size, 5 * page_size,
1100 			 MREMAP_MAYMOVE | MREMAP_FIXED, ptr + page_size * 1000);
1101 	ASSERT_NE(ptr, MAP_FAILED);
1102 
1103 	/*
1104 	 * Now move ptr3 back into place:
1105 	 *                                        \
1106 	 *             |-----------|-----------|  /  |-----------|
1107 	 *             |  faulted  |  faulted  |  \  |  faulted  |
1108 	 *             |-----------|-----------|  /  |-----------|
1109 	 *                  ptr2        ptr3      \       ptr
1110 	 *
1111 	 * It should merge:
1112 	 *                                        \
1113 	 *             |-----------------------|  /  |-----------|
1114 	 *             |        faulted        |  \  |  faulted  |
1115 	 *             |-----------------------|  /  |-----------|
1116 	 *                        ptr2            \       ptr
1117 	 */
1118 	ptr3 = sys_mremap(ptr3, 5 * page_size, 5 * page_size,
1119 			  MREMAP_MAYMOVE | MREMAP_FIXED, &ptr2[5 * page_size]);
1120 	ASSERT_NE(ptr3, MAP_FAILED);
1121 
1122 	ASSERT_TRUE(find_vma_procmap(procmap, ptr2));
1123 	ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr2);
1124 	ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr2 + 10 * page_size);
1125 
1126 	/*
1127 	 * Now move ptr back into place:
1128 	 *
1129 	 * |-----------|-----------------------|
1130 	 * |  faulted  |        faulted        |
1131 	 * |-----------|-----------------------|
1132 	 *      ptr               ptr2
1133 	 *
1134 	 * It should merge:
1135 	 *
1136 	 * |-----------------------------------|
1137 	 * |              faulted              |
1138 	 * |-----------------------------------|
1139 	 *                  ptr
1140 	 */
1141 	ptr = sys_mremap(ptr, 5 * page_size, 5 * page_size,
1142 			 MREMAP_MAYMOVE | MREMAP_FIXED, &carveout[page_size]);
1143 	ASSERT_NE(ptr, MAP_FAILED);
1144 
1145 	ASSERT_TRUE(find_vma_procmap(procmap, ptr));
1146 	ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr);
1147 	ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr + 15 * page_size);
1148 
1149 	/*
1150 	 * Now move ptr2 out of the way:
1151 	 *                                        \
1152 	 * |-----------|           |-----------|  /  |-----------|
1153 	 * |  faulted  |           |  faulted  |  \  |  faulted  |
1154 	 * |-----------|           |-----------|  /  |-----------|
1155 	 *      ptr                     ptr3      \       ptr2
1156 	 */
1157 	ptr2 = sys_mremap(ptr2, 5 * page_size, 5 * page_size,
1158 			  MREMAP_MAYMOVE | MREMAP_FIXED, ptr2 + page_size * 1000);
1159 	ASSERT_NE(ptr2, MAP_FAILED);
1160 
1161 	/*
1162 	 * Now move it back:
1163 	 *
1164 	 * |-----------|-----------|-----------|
1165 	 * |  faulted  |  faulted  |  faulted  |
1166 	 * |-----------|-----------|-----------|
1167 	 *      ptr         ptr2        ptr3
1168 	 *
1169 	 * It should merge:
1170 	 *
1171 	 * |-----------------------------------|
1172 	 * |              faulted              |
1173 	 * |-----------------------------------|
1174 	 *                  ptr
1175 	 */
1176 	ptr2 = sys_mremap(ptr2, 5 * page_size, 5 * page_size,
1177 			  MREMAP_MAYMOVE | MREMAP_FIXED, &ptr[5 * page_size]);
1178 	ASSERT_NE(ptr2, MAP_FAILED);
1179 
1180 	ASSERT_TRUE(find_vma_procmap(procmap, ptr));
1181 	ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr);
1182 	ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr + 15 * page_size);
1183 
1184 	/*
1185 	 * Move ptr3 out of place:
1186 	 *                                        \
1187 	 * |-----------------------|              /  |-----------|
1188 	 * |        faulted        |              \  |  faulted  |
1189 	 * |-----------------------|              /  |-----------|
1190 	 *            ptr                         \       ptr3
1191 	 */
1192 	ptr3 = sys_mremap(ptr3, 5 * page_size, 5 * page_size,
1193 			  MREMAP_MAYMOVE | MREMAP_FIXED, ptr3 + page_size * 1000);
1194 	ASSERT_NE(ptr3, MAP_FAILED);
1195 
1196 	/*
1197 	 * Now move it back:
1198 	 *
1199 	 * |-----------|-----------|-----------|
1200 	 * |  faulted  |  faulted  |  faulted  |
1201 	 * |-----------|-----------|-----------|
1202 	 *      ptr         ptr2        ptr3
1203 	 *
1204 	 * It should merge:
1205 	 *
1206 	 * |-----------------------------------|
1207 	 * |              faulted              |
1208 	 * |-----------------------------------|
1209 	 *                  ptr
1210 	 */
1211 	ptr3 = sys_mremap(ptr3, 5 * page_size, 5 * page_size,
1212 			  MREMAP_MAYMOVE | MREMAP_FIXED, &ptr[10 * page_size]);
1213 	ASSERT_NE(ptr3, MAP_FAILED);
1214 
1215 	ASSERT_TRUE(find_vma_procmap(procmap, ptr));
1216 	ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr);
1217 	ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr + 15 * page_size);
1218 }
1219 
1220 TEST_F(merge_with_fork, mremap_faulted_to_unfaulted_prev)
1221 {
1222 	struct procmap_fd *procmap = &self->procmap;
1223 	unsigned int page_size = self->page_size;
1224 	unsigned long offset;
1225 	char *ptr_a, *ptr_b;
1226 
1227 	/*
1228 	 * mremap() such that A and B merge:
1229 	 *
1230 	 *                             |------------|
1231 	 *                             |    \       |
1232 	 *           |-----------|     |    /  |---------|
1233 	 *           | unfaulted |     v    \  | faulted |
1234 	 *           |-----------|          /  |---------|
1235 	 *                 B                \       A
1236 	 */
1237 
1238 	/* Map VMA A into place. */
1239 	ptr_a = mmap(&self->carveout[page_size + 3 * page_size],
1240 		     3 * page_size,
1241 		     PROT_READ | PROT_WRITE,
1242 		     MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0);
1243 	ASSERT_NE(ptr_a, MAP_FAILED);
1244 	/* Fault it in. */
1245 	ptr_a[0] = 'x';
1246 
1247 	if (variant->forked) {
1248 		pid_t pid = do_fork(&self->procmap);
1249 
1250 		ASSERT_NE(pid, -1);
1251 		if (pid != 0)
1252 			return;
1253 	}
1254 
1255 	/*
1256 	 * Now move it out of the way so we can place VMA B in position,
1257 	 * unfaulted.
1258 	 */
1259 	ptr_a = mremap(ptr_a, 3 * page_size, 3 * page_size,
1260 		       MREMAP_FIXED | MREMAP_MAYMOVE, &self->carveout[20 * page_size]);
1261 	ASSERT_NE(ptr_a, MAP_FAILED);
1262 
1263 	/* Map VMA B into place. */
1264 	ptr_b = mmap(&self->carveout[page_size], 3 * page_size,
1265 		     PROT_READ | PROT_WRITE,
1266 		     MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0);
1267 	ASSERT_NE(ptr_b, MAP_FAILED);
1268 
1269 	/*
1270 	 * Now move VMA A into position with MREMAP_DONTUNMAP to catch incorrect
1271 	 * anon_vma propagation.
1272 	 */
1273 	ptr_a = mremap(ptr_a, 3 * page_size, 3 * page_size,
1274 		       MREMAP_FIXED | MREMAP_MAYMOVE | MREMAP_DONTUNMAP,
1275 		       &self->carveout[page_size + 3 * page_size]);
1276 	ASSERT_NE(ptr_a, MAP_FAILED);
1277 
1278 	/* The VMAs should have merged, if not forked. */
1279 	ASSERT_TRUE(find_vma_procmap(procmap, ptr_b));
1280 	ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr_b);
1281 
1282 	offset = variant->forked ? 3 * page_size : 6 * page_size;
1283 	ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr_b + offset);
1284 }
1285 
1286 TEST_F(merge_with_fork, mremap_faulted_to_unfaulted_next)
1287 {
1288 	struct procmap_fd *procmap = &self->procmap;
1289 	unsigned int page_size = self->page_size;
1290 	unsigned long offset;
1291 	char *ptr_a, *ptr_b;
1292 
1293 	/*
1294 	 * mremap() such that A and B merge:
1295 	 *
1296 	 *      |---------------------------|
1297 	 *      |                   \       |
1298 	 *      |    |-----------|  /  |---------|
1299 	 *      v    | unfaulted |  \  | faulted |
1300 	 *           |-----------|  /  |---------|
1301 	 *                 B        \       A
1302 	 *
1303 	 * Then unmap VMA A to trigger the bug.
1304 	 */
1305 
1306 	/* Map VMA A into place. */
1307 	ptr_a = mmap(&self->carveout[page_size], 3 * page_size,
1308 		     PROT_READ | PROT_WRITE,
1309 		     MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0);
1310 	ASSERT_NE(ptr_a, MAP_FAILED);
1311 	/* Fault it in. */
1312 	ptr_a[0] = 'x';
1313 
1314 	if (variant->forked) {
1315 		pid_t pid = do_fork(&self->procmap);
1316 
1317 		ASSERT_NE(pid, -1);
1318 		if (pid != 0)
1319 			return;
1320 	}
1321 
1322 	/*
1323 	 * Now move it out of the way so we can place VMA B in position,
1324 	 * unfaulted.
1325 	 */
1326 	ptr_a = mremap(ptr_a, 3 * page_size, 3 * page_size,
1327 		       MREMAP_FIXED | MREMAP_MAYMOVE, &self->carveout[20 * page_size]);
1328 	ASSERT_NE(ptr_a, MAP_FAILED);
1329 
1330 	/* Map VMA B into place. */
1331 	ptr_b = mmap(&self->carveout[page_size + 3 * page_size], 3 * page_size,
1332 		     PROT_READ | PROT_WRITE,
1333 		     MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0);
1334 	ASSERT_NE(ptr_b, MAP_FAILED);
1335 
1336 	/*
1337 	 * Now move VMA A into position with MREMAP_DONTUNMAP to catch incorrect
1338 	 * anon_vma propagation.
1339 	 */
1340 	ptr_a = mremap(ptr_a, 3 * page_size, 3 * page_size,
1341 		       MREMAP_FIXED | MREMAP_MAYMOVE | MREMAP_DONTUNMAP,
1342 		       &self->carveout[page_size]);
1343 	ASSERT_NE(ptr_a, MAP_FAILED);
1344 
1345 	/* The VMAs should have merged, if not forked. */
1346 	ASSERT_TRUE(find_vma_procmap(procmap, ptr_a));
1347 	ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr_a);
1348 	offset = variant->forked ? 3 * page_size : 6 * page_size;
1349 	ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr_a + offset);
1350 }
1351 
1352 TEST_F(merge_with_fork, mremap_faulted_to_unfaulted_prev_unfaulted_next)
1353 {
1354 	struct procmap_fd *procmap = &self->procmap;
1355 	unsigned int page_size = self->page_size;
1356 	unsigned long offset;
1357 	char *ptr_a, *ptr_b, *ptr_c;
1358 
1359 	/*
1360 	 * mremap() with MREMAP_DONTUNMAP such that A, B and C merge:
1361 	 *
1362 	 *                  |---------------------------|
1363 	 *                  |                   \       |
1364 	 * |-----------|    |    |-----------|  /  |---------|
1365 	 * | unfaulted |    v    | unfaulted |  \  | faulted |
1366 	 * |-----------|         |-----------|  /  |---------|
1367 	 *       A                     C        \        B
1368 	 */
1369 
1370 	/* Map VMA B into place. */
1371 	ptr_b = mmap(&self->carveout[page_size + 3 * page_size], 3 * page_size,
1372 		     PROT_READ | PROT_WRITE,
1373 		     MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0);
1374 	ASSERT_NE(ptr_b, MAP_FAILED);
1375 	/* Fault it in. */
1376 	ptr_b[0] = 'x';
1377 
1378 	if (variant->forked) {
1379 		pid_t pid = do_fork(&self->procmap);
1380 
1381 		ASSERT_NE(pid, -1);
1382 		if (pid != 0)
1383 			return;
1384 	}
1385 
1386 	/*
1387 	 * Now move it out of the way so we can place VMAs A, C in position,
1388 	 * unfaulted.
1389 	 */
1390 	ptr_b = mremap(ptr_b, 3 * page_size, 3 * page_size,
1391 		       MREMAP_FIXED | MREMAP_MAYMOVE, &self->carveout[20 * page_size]);
1392 	ASSERT_NE(ptr_b, MAP_FAILED);
1393 
1394 	/* Map VMA A into place. */
1395 
1396 	ptr_a = mmap(&self->carveout[page_size], 3 * page_size,
1397 		     PROT_READ | PROT_WRITE,
1398 		     MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0);
1399 	ASSERT_NE(ptr_a, MAP_FAILED);
1400 
1401 	/* Map VMA C into place. */
1402 	ptr_c = mmap(&self->carveout[page_size + 3 * page_size + 3 * page_size],
1403 		     3 * page_size, PROT_READ | PROT_WRITE,
1404 		     MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0);
1405 	ASSERT_NE(ptr_c, MAP_FAILED);
1406 
1407 	/*
1408 	 * Now move VMA B into position with MREMAP_DONTUNMAP to catch incorrect
1409 	 * anon_vma propagation.
1410 	 */
1411 	ptr_b = mremap(ptr_b, 3 * page_size, 3 * page_size,
1412 		       MREMAP_FIXED | MREMAP_MAYMOVE | MREMAP_DONTUNMAP,
1413 		       &self->carveout[page_size + 3 * page_size]);
1414 	ASSERT_NE(ptr_b, MAP_FAILED);
1415 
1416 	/* The VMAs should have merged, if not forked. */
1417 	ASSERT_TRUE(find_vma_procmap(procmap, ptr_a));
1418 	ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr_a);
1419 	offset = variant->forked ? 3 * page_size : 9 * page_size;
1420 	ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr_a + offset);
1421 
1422 	/* If forked, B and C should also not have merged. */
1423 	if (variant->forked) {
1424 		ASSERT_TRUE(find_vma_procmap(procmap, ptr_b));
1425 		ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr_b);
1426 		ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr_b + 3 * page_size);
1427 	}
1428 }
1429 
1430 TEST_F(merge_with_fork, mremap_faulted_to_unfaulted_prev_faulted_next)
1431 {
1432 	struct procmap_fd *procmap = &self->procmap;
1433 	unsigned int page_size = self->page_size;
1434 	char *ptr_a, *ptr_b, *ptr_bc;
1435 
1436 	/*
1437 	 * mremap() with MREMAP_DONTUNMAP such that A, B and C merge:
1438 	 *
1439 	 *                  |---------------------------|
1440 	 *                  |                   \       |
1441 	 * |-----------|    |    |-----------|  /  |---------|
1442 	 * | unfaulted |    v    |  faulted  |  \  | faulted |
1443 	 * |-----------|         |-----------|  /  |---------|
1444 	 *       A                     C        \       B
1445 	 */
1446 
1447 	/*
1448 	 * Map VMA B and C into place. We have to map them together so their
1449 	 * anon_vma is the same and the vma->vm_pgoff's are correctly aligned.
1450 	 */
1451 	ptr_bc = mmap(&self->carveout[page_size + 3 * page_size],
1452 		      3 * page_size + 3 * page_size,
1453 		     PROT_READ | PROT_WRITE,
1454 		     MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0);
1455 	ASSERT_NE(ptr_bc, MAP_FAILED);
1456 
1457 	/* Fault it in. */
1458 	ptr_bc[0] = 'x';
1459 
1460 	if (variant->forked) {
1461 		pid_t pid = do_fork(&self->procmap);
1462 
1463 		ASSERT_NE(pid, -1);
1464 		if (pid != 0)
1465 			return;
1466 	}
1467 
1468 	/*
1469 	 * Now move VMA B out the way (splitting VMA BC) so we can place VMA A
1470 	 * in position, unfaulted, and leave the remainder of the VMA we just
1471 	 * moved in place, faulted, as VMA C.
1472 	 */
1473 	ptr_b = mremap(ptr_bc, 3 * page_size, 3 * page_size,
1474 		       MREMAP_FIXED | MREMAP_MAYMOVE, &self->carveout[20 * page_size]);
1475 	ASSERT_NE(ptr_b, MAP_FAILED);
1476 
1477 	/* Map VMA A into place. */
1478 	ptr_a = mmap(&self->carveout[page_size], 3 * page_size,
1479 		     PROT_READ | PROT_WRITE,
1480 		     MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0);
1481 	ASSERT_NE(ptr_a, MAP_FAILED);
1482 
1483 	/*
1484 	 * Now move VMA B into position with MREMAP_DONTUNMAP to catch incorrect
1485 	 * anon_vma propagation.
1486 	 */
1487 	ptr_b = mremap(ptr_b, 3 * page_size, 3 * page_size,
1488 		       MREMAP_FIXED | MREMAP_MAYMOVE | MREMAP_DONTUNMAP,
1489 		       &self->carveout[page_size + 3 * page_size]);
1490 	ASSERT_NE(ptr_b, MAP_FAILED);
1491 
1492 	/* The VMAs should have merged. A,B,C if unforked, B, C if forked. */
1493 	if (variant->forked) {
1494 		ASSERT_TRUE(find_vma_procmap(procmap, ptr_b));
1495 		ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr_b);
1496 		ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr_b + 6 * page_size);
1497 	} else {
1498 		ASSERT_TRUE(find_vma_procmap(procmap, ptr_a));
1499 		ASSERT_EQ(procmap->query.vma_start, (unsigned long)ptr_a);
1500 		ASSERT_EQ(procmap->query.vma_end, (unsigned long)ptr_a + 9 * page_size);
1501 	}
1502 }
1503 
1504 TEST_HARNESS_MAIN
1505