xref: /xnu-12377.81.4/tests/vm/configurator_mmap.c (revision 043036a2b3718f7f0be807e2870f8f47d3fa0796)
1 /*
2  * Copyright (c) 2024 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 
29 /*
30  * vm/configurator_vm_allocate.c
31  *
32  * Test vm_allocate(FIXED and FIXED|OVERWRITE) with many different VM states.
33  */
34 
35 #include "configurator/vm_configurator_tests.h"
36 #include "configurator/vm_configurator_helpers.h"
37 #include "exc_guard_helper.h"
38 #include <sys/mman.h>
39 
40 T_GLOBAL_META(
41 	T_META_NAMESPACE("xnu.vm.configurator"),
42 	T_META_RADAR_COMPONENT_NAME("xnu"),
43 	T_META_RADAR_COMPONENT_VERSION("VM"),
44 	T_META_RUN_CONCURRENTLY(true),
45 	T_META_ASROOT(true),  /* required for vm submap sysctls */
46 	T_META_ALL_VALID_ARCHS(true)
47 	);
48 
49 /*
50  * rdar://143341561 mmap(FIXED) overwrite sometimes provokes EXC_GUARD
51  * Remove this when that bug is fixed.
52  *
53  * normal workaround: run mmap(FIXED) with the EXC_GUARD catcher in place
54  *     when the test is expected to hit rdar://143341561
55  * Rosetta workaround: EXC_GUARD catcher doesn't work on Rosetta, so don't run
56  *     mmap(FIXED) when the test is expected to hit rdar://143341561
57  */
58 #define workaround_rdar_143341561 1
59 
60 static void
checker_perform_successful_mmap_anon(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size,uint16_t user_tag)61 checker_perform_successful_mmap_anon(
62 	checker_list_t *checker_list,
63 	mach_vm_address_t start,
64 	mach_vm_size_t size,
65 	uint16_t user_tag)
66 {
67 	/* Make a new checker for the allocation. */
68 	vm_entry_checker_t *new_checker = make_checker_for_vm_allocate(
69 		checker_list, start, size, VM_MAKE_TAG(user_tag));
70 	entry_checker_range_t new_range = { new_checker, new_checker };
71 
72 	/* Find existing checkers in the address range. */
73 	entry_checker_range_t old_range =
74 	    checker_list_find_and_clip_including_holes(checker_list, start, size);
75 
76 	/* Free the old checkers and insert the new checker. */
77 	checker_list_replace_range(checker_list, old_range, new_range);
78 }
79 
80 static test_result_t
successful_mmap_anon_fixed(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)81 successful_mmap_anon_fixed(
82 	checker_list_t *checker_list,
83 	mach_vm_address_t start,
84 	mach_vm_size_t size)
85 {
86 	void *ret = mmap((void *)start, size, PROT_READ | PROT_WRITE,
87 	    MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0);
88 	mach_vm_address_t allocated = (mach_vm_address_t)ret;
89 	if (ret == MAP_FAILED) {
90 		T_EXPECT_POSIX_SUCCESS(ret, "mmap(ANON | FIXED)");
91 		return TestFailed;
92 	}
93 	if (allocated != start) {
94 		T_FAIL("mmap(ANON | FIXED) returned address 0x%llx (expected 0x%llx)", allocated, start);
95 		return TestFailed;
96 	}
97 	checker_perform_successful_mmap_anon(checker_list, start, size, 0);
98 
99 	return verify_vm_state(checker_list, "after mmap(ANON | FIXED)");
100 }
101 
102 
103 static test_result_t
successful_mmap_anon_fixed_with_tag(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size,uint16_t tag)104 successful_mmap_anon_fixed_with_tag(
105 	checker_list_t *checker_list,
106 	mach_vm_address_t start,
107 	mach_vm_size_t size,
108 	uint16_t tag)
109 {
110 	void *ret = mmap((void *)start, size, PROT_READ | PROT_WRITE,
111 	    MAP_PRIVATE | MAP_ANON | MAP_FIXED, VM_MAKE_TAG(tag), 0);
112 	mach_vm_address_t allocated = (mach_vm_address_t)ret;
113 	if (ret == MAP_FAILED) {
114 		T_EXPECT_POSIX_SUCCESS(ret, "mmap(ANON | FIXED, tag)");
115 		return TestFailed;
116 	}
117 	if (allocated != start) {
118 		T_FAIL("mmap(ANON | FIXED, tag) returned address 0x%llx (expected 0x%llx)", allocated, start);
119 		return TestFailed;
120 	}
121 	checker_perform_successful_mmap_anon(checker_list, start, size, tag);
122 
123 	return verify_vm_state(checker_list, "after mmap(ANON | FIXED, tag)");
124 }
125 
126 static test_result_t
successful_mmap_anon_fixed_with_neighbor_tags(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)127 successful_mmap_anon_fixed_with_neighbor_tags(
128 	checker_list_t *checker_list,
129 	mach_vm_address_t start,
130 	mach_vm_size_t size)
131 {
132 	uint16_t tag;
133 
134 	/*
135 	 * Allocate with a tag matching the entry to the left,
136 	 * to probe simplify behavior.
137 	 */
138 	tag = get_app_specific_user_tag_for_address(start - 1);
139 	if (TestFailed == successful_mmap_anon_fixed_with_tag(
140 		    checker_list, start, size, tag)) {
141 		return TestFailed;
142 	}
143 
144 	/*
145 	 * Allocate again, with a tag matching the entry to the right,
146 	 * to probe simplify behavior.
147 	 */
148 	tag = get_app_specific_user_tag_for_address(start + size);
149 	if (TestFailed == successful_mmap_anon_fixed_with_tag(
150 		    checker_list, start, size, tag)) {
151 		return TestFailed;
152 	}
153 
154 	return TestSucceeded;
155 }
156 
157 static bool
call_mmap_anon_fixed_and_expect_ENOMEM(mach_vm_address_t start,mach_vm_size_t size,uint16_t tag)158 call_mmap_anon_fixed_and_expect_ENOMEM(
159 	mach_vm_address_t start,
160 	mach_vm_size_t size,
161 	uint16_t tag)
162 {
163 #if workaround_rdar_143341561
164 	__block void *ret;
165 	exc_guard_helper_info_t exc_info;
166 	bool caught_exception =
167 	    block_raised_exc_guard_of_type(GUARD_TYPE_VIRT_MEMORY, &exc_info, ^{
168 		ret = mmap((void *)start, size, PROT_READ | PROT_WRITE,
169 		MAP_PRIVATE | MAP_ANON | MAP_FIXED, VM_MAKE_TAG(tag), 0);
170 	});
171 	if (caught_exception) {
172 		T_LOG("warning: rdar://143341561 mmap(fixed) should work "
173 		    "regardless of whether a mapping exists at the addr");
174 	}
175 #else  /* not workaround_rdar_143341561 */
176 	void *ret = mmap((void *)start, size, PROT_READ | PROT_WRITE,
177 	    MAP_PRIVATE | MAP_ANON | MAP_FIXED, VM_MAKE_TAG(tag), 0);
178 #endif /* not workaround_rdar_143341561 */
179 
180 	if (ret != MAP_FAILED) {
181 		T_EXPECT_POSIX_ERROR(ret, ENOMEM, "mmap(ANON | FIXED, tag)");
182 		return false;
183 	}
184 	return true;
185 }
186 
187 
188 static test_result_t
test_permanent_entry_fixed(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)189 test_permanent_entry_fixed(
190 	checker_list_t *checker_list,
191 	mach_vm_address_t start,
192 	mach_vm_size_t size)
193 {
194 #if workaround_rdar_143341561
195 	if (isRosetta()) {
196 		T_LOG("warning: can't work around rdar://143341561 on Rosetta; just passing instead");
197 		return TestSucceeded;
198 	}
199 #endif
200 
201 	if (!call_mmap_anon_fixed_and_expect_ENOMEM(start, size, 0)) {
202 		return TestFailed;
203 	}
204 
205 	/* one permanent entry, it becomes inaccessible */
206 	checker_perform_vm_deallocate_permanent(checker_list, start, size);
207 
208 	return verify_vm_state(checker_list, "after mmap(ANON | FIXED)");
209 }
210 
211 static test_result_t
test_permanent_before_permanent_fixed(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)212 test_permanent_before_permanent_fixed(
213 	checker_list_t *checker_list,
214 	mach_vm_address_t start,
215 	mach_vm_size_t size)
216 {
217 #if workaround_rdar_143341561
218 	if (isRosetta()) {
219 		T_LOG("warning: can't work around rdar://143341561 on Rosetta; just passing instead");
220 		return TestSucceeded;
221 	}
222 #endif
223 
224 	if (!call_mmap_anon_fixed_and_expect_ENOMEM(start, size, 0)) {
225 		return TestFailed;
226 	}
227 
228 	/* two permanent entries, both become inaccessible */
229 	checker_perform_vm_deallocate_permanent(checker_list, start, size / 2);
230 	checker_perform_vm_deallocate_permanent(checker_list, start + size / 2, size / 2);
231 
232 	return verify_vm_state(checker_list, "after mmap(ANON | FIXED)");
233 }
234 
235 static test_result_t
test_permanent_before_allocation_fixed(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)236 test_permanent_before_allocation_fixed(
237 	checker_list_t *checker_list,
238 	mach_vm_address_t start,
239 	mach_vm_size_t size)
240 {
241 #if workaround_rdar_143341561
242 	if (isRosetta()) {
243 		T_LOG("warning: can't work around rdar://143341561 on Rosetta; just passing instead");
244 		return TestSucceeded;
245 	}
246 #endif
247 
248 	if (!call_mmap_anon_fixed_and_expect_ENOMEM(start, size, 0)) {
249 		return TestFailed;
250 	}
251 
252 	/*
253 	 * one permanent entry, becomes inaccessible
254 	 * one nonpermanent allocation, unchanged
255 	 */
256 	checker_perform_vm_deallocate_permanent(checker_list, start, size / 2);
257 	/* [start + size/2, start + size) unchanged */
258 
259 	return verify_vm_state(checker_list, "after mmap(ANON | FIXED)");
260 }
261 
262 static test_result_t
test_permanent_before_allocation_fixed_rdar144128567(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)263 test_permanent_before_allocation_fixed_rdar144128567(
264 	checker_list_t *checker_list,
265 	mach_vm_address_t start,
266 	mach_vm_size_t size)
267 {
268 #if workaround_rdar_143341561
269 	if (isRosetta()) {
270 		T_LOG("warning: can't work around rdar://143341561 on Rosetta; just passing instead");
271 		return TestSucceeded;
272 	}
273 #endif
274 
275 	if (!call_mmap_anon_fixed_and_expect_ENOMEM(start, size, 0)) {
276 		return TestFailed;
277 	}
278 
279 	/*
280 	 * one permanent entry, becomes inaccessible
281 	 * one nonpermanent allocation, becomes deallocated (rdar://144128567)
282 	 */
283 	checker_perform_vm_deallocate_permanent(checker_list, start, size / 2);
284 	checker_perform_successful_vm_deallocate(checker_list, start + size / 2, size / 2);
285 
286 	return verify_vm_state(checker_list, "after mmap(ANON | FIXED)");
287 }
288 
289 static test_result_t
test_permanent_before_hole_fixed(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)290 test_permanent_before_hole_fixed(
291 	checker_list_t *checker_list,
292 	mach_vm_address_t start,
293 	mach_vm_size_t size)
294 {
295 #if workaround_rdar_143341561
296 	if (isRosetta()) {
297 		T_LOG("warning: can't work around rdar://143341561 on Rosetta; just passing instead");
298 		return TestSucceeded;
299 	}
300 #endif
301 
302 	if (!call_mmap_anon_fixed_and_expect_ENOMEM(start, size, 0)) {
303 		return TestFailed;
304 	}
305 
306 	/*
307 	 * one permanent entry, becomes inaccessible
308 	 * one hole, unchanged
309 	 */
310 	checker_perform_vm_deallocate_permanent(checker_list, start, size / 2);
311 	/* no change for addresses [start + size / 2, start + size) */
312 
313 	return verify_vm_state(checker_list, "after mmap(ANON | FIXED)");
314 }
315 
316 static test_result_t
test_permanent_after_allocation_fixed(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)317 test_permanent_after_allocation_fixed(
318 	checker_list_t *checker_list,
319 	mach_vm_address_t start,
320 	mach_vm_size_t size)
321 {
322 #if workaround_rdar_143341561
323 	if (isRosetta()) {
324 		T_LOG("warning: can't work around rdar://143341561 on Rosetta; just passing instead");
325 		return TestSucceeded;
326 	}
327 #endif
328 
329 	if (!call_mmap_anon_fixed_and_expect_ENOMEM(start, size, 0)) {
330 		return TestFailed;
331 	}
332 
333 	/*
334 	 * one nonpermanent allocation, becomes deallocated
335 	 * one permanent entry, becomes inaccessible
336 	 */
337 	checker_perform_successful_vm_deallocate(checker_list, start, size / 2);
338 	checker_perform_vm_deallocate_permanent(checker_list, start + size / 2, size / 2);
339 
340 	return verify_vm_state(checker_list, "after mmap(ANON | FIXED)");
341 }
342 
343 static test_result_t
test_permanent_after_hole_fixed(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)344 test_permanent_after_hole_fixed(
345 	checker_list_t *checker_list,
346 	mach_vm_address_t start,
347 	mach_vm_size_t size)
348 {
349 #if workaround_rdar_143341561
350 	if (isRosetta()) {
351 		T_LOG("warning: can't work around rdar://143341561 on Rosetta; just passing instead");
352 		return TestSucceeded;
353 	}
354 #endif
355 
356 	if (!call_mmap_anon_fixed_and_expect_ENOMEM(start, size, 0)) {
357 		return TestFailed;
358 	}
359 
360 	/*
361 	 * one hole, unchanged
362 	 * one permanent entry, becomes inaccessible
363 	 */
364 	/* no change for addresses [start, start + size / 2) */
365 	checker_perform_vm_deallocate_permanent(checker_list, start + size / 2, size / 2);
366 
367 	return verify_vm_state(checker_list, "after mmap(ANON | FIXED)");
368 }
369 
370 
371 static test_result_t
test_permanent_entry_fixed_with_neighbor_tags(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)372 test_permanent_entry_fixed_with_neighbor_tags(
373 	checker_list_t *checker_list,
374 	mach_vm_address_t start,
375 	mach_vm_size_t size)
376 {
377 #if workaround_rdar_143341561
378 	if (isRosetta()) {
379 		T_LOG("warning: can't work around rdar://143341561 on Rosetta; just passing instead");
380 		return TestSucceeded;
381 	}
382 #endif
383 
384 	uint16_t tag;
385 
386 	/*
387 	 * Allocate with a tag matching the entry to the left,
388 	 */
389 	tag = get_app_specific_user_tag_for_address(start - 1);
390 	if (!call_mmap_anon_fixed_and_expect_ENOMEM(start, size, tag)) {
391 		return TestFailed;
392 	}
393 
394 	/* one permanent entry, it becomes inaccessible */
395 	checker_perform_vm_deallocate_permanent(checker_list, start, size);
396 
397 	return verify_vm_state(checker_list, "after mmap(ANON | FIXED)");
398 }
399 
400 static test_result_t
test_permanent_before_permanent_fixed_with_neighbor_tags(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)401 test_permanent_before_permanent_fixed_with_neighbor_tags(
402 	checker_list_t *checker_list,
403 	mach_vm_address_t start,
404 	mach_vm_size_t size)
405 {
406 #if workaround_rdar_143341561
407 	if (isRosetta()) {
408 		T_LOG("warning: can't work around rdar://143341561 on Rosetta; just passing instead");
409 		return TestSucceeded;
410 	}
411 #endif
412 
413 	uint16_t tag;
414 
415 	/*
416 	 * Allocate with a tag matching the entry to the left,
417 	 */
418 	tag = get_app_specific_user_tag_for_address(start - 1);
419 	if (!call_mmap_anon_fixed_and_expect_ENOMEM(start, size, tag)) {
420 		return TestFailed;
421 	}
422 
423 	/* two permanent entries, both become inaccessible */
424 	checker_perform_vm_deallocate_permanent(checker_list, start, size / 2);
425 	checker_perform_vm_deallocate_permanent(checker_list, start + size / 2, size / 2);
426 
427 	return verify_vm_state(checker_list, "after mmap(ANON | FIXED)");
428 }
429 
430 static test_result_t
test_permanent_before_allocation_fixed_with_neighbor_tags(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)431 test_permanent_before_allocation_fixed_with_neighbor_tags(
432 	checker_list_t *checker_list,
433 	mach_vm_address_t start,
434 	mach_vm_size_t size)
435 {
436 #if workaround_rdar_143341561
437 	if (isRosetta()) {
438 		T_LOG("warning: can't work around rdar://143341561 on Rosetta; just passing instead");
439 		return TestSucceeded;
440 	}
441 #endif
442 
443 	uint16_t tag;
444 
445 	/*
446 	 * Allocate with a tag matching the entry to the left,
447 	 */
448 	tag = get_app_specific_user_tag_for_address(start - 1);
449 	if (!call_mmap_anon_fixed_and_expect_ENOMEM(start, size, tag)) {
450 		return TestFailed;
451 	}
452 
453 	/*
454 	 * one permanent entry, becomes inaccessible
455 	 * one nonpermanent allocation, unchanged
456 	 */
457 	checker_perform_vm_deallocate_permanent(checker_list, start, size / 2);
458 	/* [start + size/2, start + size) unchanged */
459 
460 	return verify_vm_state(checker_list, "after mmap(ANON | FIXED)");
461 }
462 
463 static test_result_t
test_permanent_before_allocation_fixed_with_neighbor_tags_rdar144128567(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)464 test_permanent_before_allocation_fixed_with_neighbor_tags_rdar144128567(
465 	checker_list_t *checker_list,
466 	mach_vm_address_t start,
467 	mach_vm_size_t size)
468 {
469 #if workaround_rdar_143341561
470 	if (isRosetta()) {
471 		T_LOG("warning: can't work around rdar://143341561 on Rosetta; just passing instead");
472 		return TestSucceeded;
473 	}
474 #endif
475 
476 	uint16_t tag;
477 
478 	/*
479 	 * Allocate with a tag matching the entry to the left,
480 	 */
481 	tag = get_app_specific_user_tag_for_address(start - 1);
482 	if (!call_mmap_anon_fixed_and_expect_ENOMEM(start, size, tag)) {
483 		return TestFailed;
484 	}
485 
486 	/*
487 	 * one permanent entry, becomes inaccessible
488 	 * one nonpermanent allocation, becomes deallocated (rdar://144128567)
489 	 */
490 	checker_perform_vm_deallocate_permanent(checker_list, start, size / 2);
491 	checker_perform_successful_vm_deallocate(checker_list, start + size / 2, size / 2);
492 
493 	return verify_vm_state(checker_list, "after mmap(ANON | FIXED)");
494 }
495 
496 static test_result_t
test_permanent_before_hole_fixed_with_neighbor_tags(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)497 test_permanent_before_hole_fixed_with_neighbor_tags(
498 	checker_list_t *checker_list,
499 	mach_vm_address_t start,
500 	mach_vm_size_t size)
501 {
502 #if workaround_rdar_143341561
503 	if (isRosetta()) {
504 		T_LOG("warning: can't work around rdar://143341561 on Rosetta; just passing instead");
505 		return TestSucceeded;
506 	}
507 #endif
508 
509 	uint16_t tag;
510 
511 	/*
512 	 * Allocate with a tag matching the entry to the left,
513 	 */
514 	tag = get_app_specific_user_tag_for_address(start - 1);
515 	if (!call_mmap_anon_fixed_and_expect_ENOMEM(start, size, tag)) {
516 		return TestFailed;
517 	}
518 
519 	/*
520 	 * one permanent entry, becomes inaccessible
521 	 * one hole, unchanged
522 	 */
523 	checker_perform_vm_deallocate_permanent(checker_list, start, size / 2);
524 	/* no change for addresses [start + size / 2, start + size) */
525 
526 	return verify_vm_state(checker_list, "after mmap(ANON | FIXED)");
527 }
528 
529 static test_result_t
test_permanent_after_allocation_fixed_with_neighbor_tags(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)530 test_permanent_after_allocation_fixed_with_neighbor_tags(
531 	checker_list_t *checker_list,
532 	mach_vm_address_t start,
533 	mach_vm_size_t size)
534 {
535 #if workaround_rdar_143341561
536 	if (isRosetta()) {
537 		T_LOG("warning: can't work around rdar://143341561 on Rosetta; just passing instead");
538 		return TestSucceeded;
539 	}
540 #endif
541 
542 	uint16_t tag;
543 
544 	/*
545 	 * Allocate with a tag matching the entry to the left,
546 	 */
547 	tag = get_app_specific_user_tag_for_address(start - 1);
548 	if (!call_mmap_anon_fixed_and_expect_ENOMEM(start, size, tag)) {
549 		return TestFailed;
550 	}
551 
552 	/*
553 	 * one nonpermanent allocation, becomes deallocated
554 	 * one permanent entry, becomes inaccessible
555 	 */
556 	checker_perform_successful_vm_deallocate(checker_list, start, size / 2);
557 	checker_perform_vm_deallocate_permanent(checker_list, start + size / 2, size / 2);
558 
559 	return verify_vm_state(checker_list, "after mmap(ANON | FIXED)");
560 }
561 
562 static test_result_t
test_permanent_after_hole_fixed_with_neighbor_tags(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)563 test_permanent_after_hole_fixed_with_neighbor_tags(
564 	checker_list_t *checker_list,
565 	mach_vm_address_t start,
566 	mach_vm_size_t size)
567 {
568 #if workaround_rdar_143341561
569 	if (isRosetta()) {
570 		T_LOG("warning: can't work around rdar://143341561 on Rosetta; just passing instead");
571 		return TestSucceeded;
572 	}
573 #endif
574 
575 	uint16_t tag;
576 
577 	/*
578 	 * Allocate with a tag matching the entry to the left,
579 	 */
580 	tag = get_app_specific_user_tag_for_address(start - 1);
581 	if (!call_mmap_anon_fixed_and_expect_ENOMEM(start, size, tag)) {
582 		return TestFailed;
583 	}
584 
585 	/*
586 	 * one hole, unchanged
587 	 * one permanent entry, becomes inaccessible
588 	 */
589 	/* no change for addresses [start, start + size / 2) */
590 	checker_perform_vm_deallocate_permanent(checker_list, start + size / 2, size / 2);
591 
592 	return verify_vm_state(checker_list, "after mmap(ANON | FIXED)");
593 }
594 
595 
596 T_DECL(mmap_anon_fixed,
597     "run mmap(ANON | FIXED) with various vm configurations")
598 {
599 #if workaround_rdar_143341561
600 	enable_non_fatal_vm_exc_guard();
601 #endif
602 
603 	vm_tests_t tests = {
604 		.single_entry_1 = successful_mmap_anon_fixed,
605 		.single_entry_2 = successful_mmap_anon_fixed,
606 		.single_entry_3 = successful_mmap_anon_fixed,
607 		.single_entry_4 = successful_mmap_anon_fixed,
608 
609 		.multiple_entries_1 = successful_mmap_anon_fixed,
610 		.multiple_entries_2 = successful_mmap_anon_fixed,
611 		.multiple_entries_3 = successful_mmap_anon_fixed,
612 		.multiple_entries_4 = successful_mmap_anon_fixed,
613 		.multiple_entries_5 = successful_mmap_anon_fixed,
614 		.multiple_entries_6 = successful_mmap_anon_fixed,
615 
616 		.some_holes_1 = successful_mmap_anon_fixed,
617 		.some_holes_2 = successful_mmap_anon_fixed,
618 		.some_holes_3 = successful_mmap_anon_fixed,
619 		.some_holes_4 = successful_mmap_anon_fixed,
620 		.some_holes_5 = successful_mmap_anon_fixed,
621 		.some_holes_6 = successful_mmap_anon_fixed,
622 		.some_holes_7 = successful_mmap_anon_fixed,
623 		.some_holes_8 = successful_mmap_anon_fixed,
624 		.some_holes_9 = successful_mmap_anon_fixed,
625 		.some_holes_10 = successful_mmap_anon_fixed,
626 		.some_holes_11 = successful_mmap_anon_fixed,
627 		.some_holes_12 = successful_mmap_anon_fixed,
628 
629 		.all_holes_1 = successful_mmap_anon_fixed,
630 		.all_holes_2 = successful_mmap_anon_fixed,
631 		.all_holes_3 = successful_mmap_anon_fixed,
632 		.all_holes_4 = successful_mmap_anon_fixed,
633 
634 		.null_entry = successful_mmap_anon_fixed,
635 		.nonresident_entry = successful_mmap_anon_fixed,
636 		.resident_entry = successful_mmap_anon_fixed,
637 
638 		.shared_entry = successful_mmap_anon_fixed,
639 		.shared_entry_discontiguous = successful_mmap_anon_fixed,
640 		.shared_entry_partial = successful_mmap_anon_fixed,
641 		.shared_entry_pairs = successful_mmap_anon_fixed,
642 		.shared_entry_x1000 = successful_mmap_anon_fixed,
643 
644 		.cow_entry = successful_mmap_anon_fixed,
645 		.cow_unreferenced = successful_mmap_anon_fixed,
646 		.cow_nocow = successful_mmap_anon_fixed,
647 		.nocow_cow = successful_mmap_anon_fixed,
648 		.cow_unreadable = successful_mmap_anon_fixed,
649 		.cow_unwriteable = successful_mmap_anon_fixed,
650 
651 		.permanent_entry = test_permanent_entry_fixed,
652 		.permanent_before_permanent = test_permanent_before_permanent_fixed,
653 		.permanent_before_allocation = test_permanent_before_allocation_fixed,
654 		.permanent_before_allocation_2 = test_permanent_before_allocation_fixed_rdar144128567,
655 		.permanent_before_hole = test_permanent_before_hole_fixed,
656 		.permanent_after_allocation = test_permanent_after_allocation_fixed,
657 		.permanent_after_hole = test_permanent_after_hole_fixed,
658 
659 		.single_submap_single_entry = successful_mmap_anon_fixed,
660 		.single_submap_single_entry_first_pages = successful_mmap_anon_fixed,
661 		.single_submap_single_entry_last_pages = successful_mmap_anon_fixed,
662 		.single_submap_single_entry_middle_pages = successful_mmap_anon_fixed,
663 		.single_submap_oversize_entry_at_start = successful_mmap_anon_fixed,
664 		.single_submap_oversize_entry_at_end = successful_mmap_anon_fixed,
665 		.single_submap_oversize_entry_at_both = successful_mmap_anon_fixed,
666 
667 		.submap_before_allocation = successful_mmap_anon_fixed,
668 		.submap_after_allocation = successful_mmap_anon_fixed,
669 		.submap_before_hole = successful_mmap_anon_fixed,
670 		.submap_after_hole = successful_mmap_anon_fixed,
671 		.submap_allocation_submap_one_entry = successful_mmap_anon_fixed,
672 		.submap_allocation_submap_two_entries = successful_mmap_anon_fixed,
673 		.submap_allocation_submap_three_entries = successful_mmap_anon_fixed,
674 
675 		.submap_before_allocation_ro = successful_mmap_anon_fixed,
676 		.submap_after_allocation_ro = successful_mmap_anon_fixed,
677 		.submap_before_hole_ro = successful_mmap_anon_fixed,
678 		.submap_after_hole_ro = successful_mmap_anon_fixed,
679 		.submap_allocation_submap_one_entry_ro = successful_mmap_anon_fixed,
680 		.submap_allocation_submap_two_entries_ro = successful_mmap_anon_fixed,
681 		.submap_allocation_submap_three_entries_ro = successful_mmap_anon_fixed,
682 
683 		.protection_single_000_000 = successful_mmap_anon_fixed,
684 		.protection_single_000_r00 = successful_mmap_anon_fixed,
685 		.protection_single_000_0w0 = successful_mmap_anon_fixed,
686 		.protection_single_000_rw0 = successful_mmap_anon_fixed,
687 		.protection_single_r00_r00 = successful_mmap_anon_fixed,
688 		.protection_single_r00_rw0 = successful_mmap_anon_fixed,
689 		.protection_single_0w0_0w0 = successful_mmap_anon_fixed,
690 		.protection_single_0w0_rw0 = successful_mmap_anon_fixed,
691 		.protection_single_rw0_rw0 = successful_mmap_anon_fixed,
692 
693 		.protection_pairs_000_000 = successful_mmap_anon_fixed,
694 		.protection_pairs_000_r00 = successful_mmap_anon_fixed,
695 		.protection_pairs_000_0w0 = successful_mmap_anon_fixed,
696 		.protection_pairs_000_rw0 = successful_mmap_anon_fixed,
697 		.protection_pairs_r00_000 = successful_mmap_anon_fixed,
698 		.protection_pairs_r00_r00 = successful_mmap_anon_fixed,
699 		.protection_pairs_r00_0w0 = successful_mmap_anon_fixed,
700 		.protection_pairs_r00_rw0 = successful_mmap_anon_fixed,
701 		.protection_pairs_0w0_000 = successful_mmap_anon_fixed,
702 		.protection_pairs_0w0_r00 = successful_mmap_anon_fixed,
703 		.protection_pairs_0w0_0w0 = successful_mmap_anon_fixed,
704 		.protection_pairs_0w0_rw0 = successful_mmap_anon_fixed,
705 		.protection_pairs_rw0_000 = successful_mmap_anon_fixed,
706 		.protection_pairs_rw0_r00 = successful_mmap_anon_fixed,
707 		.protection_pairs_rw0_0w0 = successful_mmap_anon_fixed,
708 		.protection_pairs_rw0_rw0 = successful_mmap_anon_fixed,
709 	};
710 
711 	run_vm_tests("mmap_anon_fixed", __FILE__, &tests, argc, argv);
712 }
713 
714 
715 T_DECL(mmap_anon_fixed_with_neighbor_tags,
716     "run mmap(ANON | FIXED, tag) with various vm configurations "
717     "and tags copied from neighboring entries")
718 {
719 #if workaround_rdar_143341561
720 	enable_non_fatal_vm_exc_guard();
721 #endif
722 
723 	vm_tests_t tests = {
724 		.single_entry_1 = successful_mmap_anon_fixed_with_neighbor_tags,
725 		.single_entry_2 = successful_mmap_anon_fixed_with_neighbor_tags,
726 		.single_entry_3 = successful_mmap_anon_fixed_with_neighbor_tags,
727 		.single_entry_4 = successful_mmap_anon_fixed_with_neighbor_tags,
728 
729 		.multiple_entries_1 = successful_mmap_anon_fixed_with_neighbor_tags,
730 		.multiple_entries_2 = successful_mmap_anon_fixed_with_neighbor_tags,
731 		.multiple_entries_3 = successful_mmap_anon_fixed_with_neighbor_tags,
732 		.multiple_entries_4 = successful_mmap_anon_fixed_with_neighbor_tags,
733 		.multiple_entries_5 = successful_mmap_anon_fixed_with_neighbor_tags,
734 		.multiple_entries_6 = successful_mmap_anon_fixed_with_neighbor_tags,
735 
736 		.some_holes_1 = successful_mmap_anon_fixed_with_neighbor_tags,
737 		.some_holes_2 = successful_mmap_anon_fixed_with_neighbor_tags,
738 		.some_holes_3 = successful_mmap_anon_fixed_with_neighbor_tags,
739 		.some_holes_4 = successful_mmap_anon_fixed_with_neighbor_tags,
740 		.some_holes_5 = successful_mmap_anon_fixed_with_neighbor_tags,
741 		.some_holes_6 = successful_mmap_anon_fixed_with_neighbor_tags,
742 		.some_holes_7 = successful_mmap_anon_fixed_with_neighbor_tags,
743 		.some_holes_8 = successful_mmap_anon_fixed_with_neighbor_tags,
744 		.some_holes_9 = successful_mmap_anon_fixed_with_neighbor_tags,
745 		.some_holes_10 = successful_mmap_anon_fixed_with_neighbor_tags,
746 		.some_holes_11 = successful_mmap_anon_fixed_with_neighbor_tags,
747 		.some_holes_12 = successful_mmap_anon_fixed_with_neighbor_tags,
748 
749 		.all_holes_1 = successful_mmap_anon_fixed_with_neighbor_tags,
750 		.all_holes_2 = successful_mmap_anon_fixed_with_neighbor_tags,
751 		.all_holes_3 = successful_mmap_anon_fixed_with_neighbor_tags,
752 		.all_holes_4 = successful_mmap_anon_fixed_with_neighbor_tags,
753 
754 		.null_entry = successful_mmap_anon_fixed_with_neighbor_tags,
755 		.nonresident_entry = successful_mmap_anon_fixed_with_neighbor_tags,
756 		.resident_entry = successful_mmap_anon_fixed_with_neighbor_tags,
757 
758 		.shared_entry = successful_mmap_anon_fixed_with_neighbor_tags,
759 		.shared_entry_discontiguous = successful_mmap_anon_fixed_with_neighbor_tags,
760 		.shared_entry_partial = successful_mmap_anon_fixed_with_neighbor_tags,
761 		.shared_entry_pairs = successful_mmap_anon_fixed_with_neighbor_tags,
762 		.shared_entry_x1000 = successful_mmap_anon_fixed_with_neighbor_tags,
763 
764 		.cow_entry = successful_mmap_anon_fixed_with_neighbor_tags,
765 		.cow_unreferenced = successful_mmap_anon_fixed_with_neighbor_tags,
766 		.cow_nocow = successful_mmap_anon_fixed_with_neighbor_tags,
767 		.nocow_cow = successful_mmap_anon_fixed_with_neighbor_tags,
768 		.cow_unreadable = successful_mmap_anon_fixed_with_neighbor_tags,
769 		.cow_unwriteable = successful_mmap_anon_fixed_with_neighbor_tags,
770 
771 		.permanent_entry = test_permanent_entry_fixed_with_neighbor_tags,
772 		.permanent_before_permanent = test_permanent_before_permanent_fixed_with_neighbor_tags,
773 		.permanent_before_allocation = test_permanent_before_allocation_fixed_with_neighbor_tags,
774 		.permanent_before_allocation_2 = test_permanent_before_allocation_fixed_with_neighbor_tags_rdar144128567,
775 		.permanent_before_hole = test_permanent_before_hole_fixed_with_neighbor_tags,
776 		.permanent_after_allocation = test_permanent_after_allocation_fixed_with_neighbor_tags,
777 		.permanent_after_hole = test_permanent_after_hole_fixed_with_neighbor_tags,
778 
779 		.single_submap_single_entry = successful_mmap_anon_fixed_with_neighbor_tags,
780 		.single_submap_single_entry_first_pages = successful_mmap_anon_fixed_with_neighbor_tags,
781 		.single_submap_single_entry_last_pages = successful_mmap_anon_fixed_with_neighbor_tags,
782 		.single_submap_single_entry_middle_pages = successful_mmap_anon_fixed_with_neighbor_tags,
783 		.single_submap_oversize_entry_at_start = successful_mmap_anon_fixed_with_neighbor_tags,
784 		.single_submap_oversize_entry_at_end = successful_mmap_anon_fixed_with_neighbor_tags,
785 		.single_submap_oversize_entry_at_both = successful_mmap_anon_fixed_with_neighbor_tags,
786 
787 		.submap_before_allocation = successful_mmap_anon_fixed_with_neighbor_tags,
788 		.submap_after_allocation = successful_mmap_anon_fixed_with_neighbor_tags,
789 		.submap_before_hole = successful_mmap_anon_fixed_with_neighbor_tags,
790 		.submap_after_hole = successful_mmap_anon_fixed_with_neighbor_tags,
791 		.submap_allocation_submap_one_entry = successful_mmap_anon_fixed_with_neighbor_tags,
792 		.submap_allocation_submap_two_entries = successful_mmap_anon_fixed_with_neighbor_tags,
793 		.submap_allocation_submap_three_entries = successful_mmap_anon_fixed_with_neighbor_tags,
794 
795 		.submap_before_allocation_ro = successful_mmap_anon_fixed_with_neighbor_tags,
796 		.submap_after_allocation_ro = successful_mmap_anon_fixed_with_neighbor_tags,
797 		.submap_before_hole_ro = successful_mmap_anon_fixed_with_neighbor_tags,
798 		.submap_after_hole_ro = successful_mmap_anon_fixed_with_neighbor_tags,
799 		.submap_allocation_submap_one_entry_ro = successful_mmap_anon_fixed_with_neighbor_tags,
800 		.submap_allocation_submap_two_entries_ro = successful_mmap_anon_fixed_with_neighbor_tags,
801 		.submap_allocation_submap_three_entries_ro = successful_mmap_anon_fixed_with_neighbor_tags,
802 
803 		.protection_single_000_000 = successful_mmap_anon_fixed_with_neighbor_tags,
804 		.protection_single_000_r00 = successful_mmap_anon_fixed_with_neighbor_tags,
805 		.protection_single_000_0w0 = successful_mmap_anon_fixed_with_neighbor_tags,
806 		.protection_single_000_rw0 = successful_mmap_anon_fixed_with_neighbor_tags,
807 		.protection_single_r00_r00 = successful_mmap_anon_fixed_with_neighbor_tags,
808 		.protection_single_r00_rw0 = successful_mmap_anon_fixed_with_neighbor_tags,
809 		.protection_single_0w0_0w0 = successful_mmap_anon_fixed_with_neighbor_tags,
810 		.protection_single_0w0_rw0 = successful_mmap_anon_fixed_with_neighbor_tags,
811 		.protection_single_rw0_rw0 = successful_mmap_anon_fixed_with_neighbor_tags,
812 
813 		.protection_pairs_000_000 = successful_mmap_anon_fixed_with_neighbor_tags,
814 		.protection_pairs_000_r00 = successful_mmap_anon_fixed_with_neighbor_tags,
815 		.protection_pairs_000_0w0 = successful_mmap_anon_fixed_with_neighbor_tags,
816 		.protection_pairs_000_rw0 = successful_mmap_anon_fixed_with_neighbor_tags,
817 		.protection_pairs_r00_000 = successful_mmap_anon_fixed_with_neighbor_tags,
818 		.protection_pairs_r00_r00 = successful_mmap_anon_fixed_with_neighbor_tags,
819 		.protection_pairs_r00_0w0 = successful_mmap_anon_fixed_with_neighbor_tags,
820 		.protection_pairs_r00_rw0 = successful_mmap_anon_fixed_with_neighbor_tags,
821 		.protection_pairs_0w0_000 = successful_mmap_anon_fixed_with_neighbor_tags,
822 		.protection_pairs_0w0_r00 = successful_mmap_anon_fixed_with_neighbor_tags,
823 		.protection_pairs_0w0_0w0 = successful_mmap_anon_fixed_with_neighbor_tags,
824 		.protection_pairs_0w0_rw0 = successful_mmap_anon_fixed_with_neighbor_tags,
825 		.protection_pairs_rw0_000 = successful_mmap_anon_fixed_with_neighbor_tags,
826 		.protection_pairs_rw0_r00 = successful_mmap_anon_fixed_with_neighbor_tags,
827 		.protection_pairs_rw0_0w0 = successful_mmap_anon_fixed_with_neighbor_tags,
828 		.protection_pairs_rw0_rw0 = successful_mmap_anon_fixed_with_neighbor_tags,
829 	};
830 
831 	run_vm_tests("mmap_anon_fixed_with_neighbor_tags", __FILE__, &tests, argc, argv);
832 }
833