xref: /xnu-12377.41.6/tests/vm/configurator_test.c (revision bbb1b6f9e71b8cdde6e5cd6f4841f207dee3d828)
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_test.c
31  *
32  * Test vm_configurator itself.
33  *
34  * Verify that the VM states generated by vm_configurator are correct.
35  * This is intended to catch bugs in vm_configurator's
36  * template and checker system, as well as bugs in individual
37  * configurations used by other tests.
38  */
39 
40 #include "configurator/vm_configurator_tests.h"
41 
42 T_GLOBAL_META(
43 	T_META_NAMESPACE("xnu.vm.configurator"),
44 	T_META_RADAR_COMPONENT_NAME("xnu"),
45 	T_META_RADAR_COMPONENT_VERSION("VM"),
46 	T_META_RUN_CONCURRENTLY(true),
47 	T_META_ASROOT(true),  /* required for vm submap sysctls */
48 	T_META_ALL_VALID_ARCHS(true)
49 	);
50 
51 
52 /*
53  * Return true if [start, start + size) is a VM entry at the given submap depth.
54  */
55 __attribute__((overloadable))
56 static bool
is_entry(mach_vm_address_t start,mach_vm_size_t size,uint32_t submap_depth)57 is_entry(mach_vm_address_t start, mach_vm_size_t size, uint32_t submap_depth)
58 {
59 	mach_vm_address_t entry_start = start;
60 	mach_vm_size_t entry_size;
61 	vm_region_submap_info_data_64_t info;
62 
63 	if (!get_info_for_address(&entry_start, &entry_size, &info, submap_depth)) {
64 		return false;  /* not mapped */
65 	}
66 	if (entry_start != start || entry_size != size) {
67 		return false;  /* mapped, but wrong extent */
68 	}
69 
70 	return true;
71 }
72 
73 /*
74  * Return true if [start, start + size) is a VM entry at submap depth 0.
75  */
76 __attribute__((overloadable, used))
77 static bool
is_entry(mach_vm_address_t start,mach_vm_size_t size)78 is_entry(mach_vm_address_t start, mach_vm_size_t size)
79 {
80 	return is_entry(start, size, 0);
81 }
82 
83 /*
84  * Return true if [start, start + size) is an unallocated hole
85  * at the given submap depth.
86  */
87 __attribute__((overloadable))
88 static bool
is_hole(mach_vm_address_t start,mach_vm_size_t size,uint32_t submap_depth)89 is_hole(mach_vm_address_t start, mach_vm_size_t size, uint32_t submap_depth)
90 {
91 	mach_vm_address_t entry_start = start;
92 	mach_vm_size_t entry_size;
93 	vm_region_submap_info_data_64_t info;
94 
95 	if (get_info_for_address(&entry_start, &entry_size, &info, submap_depth)) {
96 		/* start address was mapped */
97 		return false;
98 	} else if (entry_start < start + size) {
99 		/* some address before the end of the expected hole was mapped */
100 		return false;
101 	}
102 
103 	/* [start, start + size) was entirely unmapped */
104 	return true;
105 }
106 
107 /*
108  * Return true if [start, start + size) is an unallocated hole at submap depth 0.
109  * Unallocate space inside a submap does not count.
110  */
111 __attribute__((overloadable, used))
112 static bool
is_hole(mach_vm_address_t start,mach_vm_size_t size)113 is_hole(mach_vm_address_t start, mach_vm_size_t size)
114 {
115 	return is_hole(start, size, 0 /* submap_depth */);
116 }
117 
118 /*
119  * Verify the memory and the checker for an expected hole.
120  */
121 static void
assert_hole_checker_and_entry(vm_entry_checker_t * checker,mach_vm_address_t start,mach_vm_size_t size)122 assert_hole_checker_and_entry(
123 	vm_entry_checker_t *checker,
124 	mach_vm_address_t start,
125 	mach_vm_size_t size)
126 {
127 	assert(start % PAGE_SIZE == 0);
128 	assert(size % PAGE_SIZE == 0);
129 	assert(checker->kind == Hole);
130 	assert(checker->address == start);
131 	assert(checker->size == size);
132 
133 	assert(is_hole(start, size, checker->submap_depth));
134 }
135 
136 /*
137  * Verify the checker for an expected allocated entry.
138  * Does not verify the actual VM state.
139  */
140 static void
assert_allocation_checker(vm_entry_checker_t * checker,mach_vm_address_t start,mach_vm_size_t size)141 assert_allocation_checker(
142 	vm_entry_checker_t *checker,
143 	mach_vm_address_t start,
144 	mach_vm_size_t size)
145 {
146 	assert(start % PAGE_SIZE == 0);
147 	assert(size % PAGE_SIZE == 0);
148 	assert(checker->kind == Allocation);
149 	assert(checker->address == start);
150 	assert(checker->size == size);
151 }
152 
153 /*
154  * Verify the actual VM state for an expected allocated entry.
155  * Does not verify the matching checker.
156  * Returns the vm_region output for the memory.
157  */
158 static void
assert_allocation_entry(mach_vm_address_t start,mach_vm_size_t size,uint32_t submap_depth,vm_region_submap_info_data_64_t * const out_info)159 assert_allocation_entry(
160 	mach_vm_address_t start,
161 	mach_vm_size_t size,
162 	uint32_t submap_depth,
163 	vm_region_submap_info_data_64_t * const out_info)
164 {
165 	mach_vm_address_t entry_start = start;
166 	mach_vm_size_t entry_size;
167 	assert(get_info_for_address(&entry_start, &entry_size, out_info, submap_depth));
168 	assert(entry_start == start);
169 	assert(entry_size == size);
170 }
171 
172 /*
173  * Verify the memory and the checker for an expected allocated entry.
174  * Returns the vm_region output for the memory.
175  */
176 static void
assert_allocation_checker_and_entry(vm_entry_checker_t * checker,mach_vm_address_t start,mach_vm_size_t size,vm_region_submap_info_data_64_t * const out_info)177 assert_allocation_checker_and_entry(
178 	vm_entry_checker_t *checker,
179 	mach_vm_address_t start,
180 	mach_vm_size_t size,
181 	vm_region_submap_info_data_64_t * const out_info)
182 {
183 	assert_allocation_checker(checker, start, size);
184 	assert_allocation_entry(start, size, checker->submap_depth, out_info);
185 }
186 
187 
188 /*
189  * Verify that checker_list consists of a pattern of entries and holes
190  * Each allocation or hole is assumed to be DEFAULT_ENTRY_SIZE in length.
191  * "##.#..#": allocation, allocation, hole, allocation, hole, hole, allocation
192  */
193 static void
assert_allocation_and_hole_pattern(checker_list_t * checker_list,const char * pattern)194 assert_allocation_and_hole_pattern(
195 	checker_list_t *checker_list,
196 	const char *pattern)
197 {
198 	mach_vm_address_t base = checker_range_start_address(checker_list->entries);
199 	assert(checker_range_count(checker_list->entries) == strlen(pattern));
200 
201 	for (size_t i = 0; i < strlen(pattern); i++) {
202 		vm_region_submap_info_data_64_t info;
203 		mach_vm_address_t entry_address = base + i * DEFAULT_ENTRY_SIZE;
204 		vm_entry_checker_t *checker = checker_list_nth(checker_list, i);
205 		switch (pattern[i]) {
206 		case '#':
207 			assert_allocation_checker_and_entry(checker,
208 			    entry_address, DEFAULT_ENTRY_SIZE, &info);
209 			break;
210 		case '.':
211 			assert_hole_checker_and_entry(checker,
212 			    entry_address, DEFAULT_ENTRY_SIZE);
213 			break;
214 		default:
215 			T_ASSERT_FAIL("pattern character '%c' is neither '#' nor '.'", pattern[i]);
216 			break;
217 		}
218 	}
219 }
220 
221 static void
assert_checker_and_entry_protection_equals(vm_entry_checker_t * checker,vm_region_submap_info_data_64_t * info,int protection,int max_protection)222 assert_checker_and_entry_protection_equals(
223 	vm_entry_checker_t *checker,
224 	vm_region_submap_info_data_64_t *info,
225 	int protection,
226 	int max_protection)
227 {
228 	assert(checker->protection == protection);
229 	assert(checker->max_protection == max_protection);
230 	assert(info->protection == protection);
231 	assert(info->max_protection == max_protection);
232 }
233 
234 /*
235  * Verify the memory and the checker for an expected permanent entry.
236  * This is destructive because it attempts to deallocate the permanent entry
237  * which makes its memory inaccessible, and updates the checker to match.
238  */
239 static void
destructively_assert_permanent_checker_and_entry(vm_entry_checker_t * checker,mach_vm_address_t start,mach_vm_size_t size)240 destructively_assert_permanent_checker_and_entry(
241 	vm_entry_checker_t *checker,
242 	mach_vm_address_t start,
243 	mach_vm_size_t size)
244 {
245 	assert(start % PAGE_SIZE == 0);
246 	assert(size % PAGE_SIZE == 0);
247 	assert(checker->permanent == true);
248 	assert(checker->address == start);
249 	assert(checker->size == size);
250 
251 	/*
252 	 * Permanent memory is indistinguishable in vm_region output.
253 	 * We can only try to deallocate it and then see if it is still there.
254 	 */
255 
256 	/* check that it exists */
257 	assert(is_entry(start, size, checker->submap_depth));
258 
259 	/* try to deallocate it */
260 	kern_return_t kr = mach_vm_deallocate(mach_task_self(), start, size);
261 	assert(kr == 0);
262 
263 	/* check that it still exists */
264 	assert(is_entry(start, size, checker->submap_depth));
265 
266 	/* update the checker because the memory is now inaccessible */
267 	checker->protection = VM_PROT_NONE;
268 	checker->max_protection = VM_PROT_NONE;
269 }
270 
271 /*
272  * Verify the memory and checker for an expected non-permanent allocation.
273  * This is destructive because it deallocates the memory
274  * and updates the checker to match.
275  */
276 static void
destructively_assert_nonpermanent_checker_and_entry(checker_list_t * list,vm_entry_checker_t * checker,mach_vm_address_t start,mach_vm_size_t size)277 destructively_assert_nonpermanent_checker_and_entry(
278 	checker_list_t *list,
279 	vm_entry_checker_t *checker,
280 	mach_vm_address_t start,
281 	mach_vm_size_t size)
282 {
283 	assert(start % PAGE_SIZE == 0);
284 	assert(size % PAGE_SIZE == 0);
285 	assert(checker->permanent == false);
286 	assert(checker->address == start);
287 	assert(checker->size == size);
288 
289 	/*
290 	 * Permanent memory is indistinguishable in vm_region output.
291 	 * We can only try to deallocate it and then see if it is still there.
292 	 */
293 
294 	/* check that it exists */
295 	assert(is_entry(start, size, checker->submap_depth));
296 
297 	/* try to deallocate it */
298 	kern_return_t kr = mach_vm_deallocate(mach_task_self(), start, size);
299 	assert(kr == 0);
300 
301 	/* check that it no longer exists */
302 	assert(!is_entry(start, size, checker->submap_depth));
303 	assert(is_hole(start, size, 0 /* submap_depth */));
304 
305 	/*
306 	 * Update the checker to match the now-deallocated memory.
307 	 * The checker should be replaced by a hole checker.
308 	 *
309 	 * Save the checker's index first so we can
310 	 * look up and verify the hole checker after.
311 	 */
312 	unsigned index = 0;
313 	while (checker_list_nth(list, index) != checker) {
314 		index++;
315 	}
316 
317 	checker_list_free_checker(list, checker);
318 	vm_entry_checker_t *new_hole = checker_list_nth(list, index);
319 	assert_hole_checker_and_entry(new_hole, start, size);
320 }
321 
322 /*
323  * Verify the memory and the checker for an expected submap entry.
324  * Does not examine the contents of the submap.
325  * Returns the vm_region output for the entry in the parent map.
326  */
327 static void
assert_submap_checker_and_entry(vm_entry_checker_t * checker,mach_vm_address_t start,mach_vm_size_t size,vm_region_submap_info_data_64_t * const out_info)328 assert_submap_checker_and_entry(
329 	vm_entry_checker_t *checker,
330 	mach_vm_address_t start,
331 	mach_vm_size_t size,
332 	vm_region_submap_info_data_64_t * const out_info)
333 {
334 	assert(start % PAGE_SIZE == 0);
335 	assert(size % PAGE_SIZE == 0);
336 	assert(checker->kind == Submap);
337 	assert(checker->address == start);
338 	assert(checker->size == size);
339 	assert(checker->submap_depth == 0);  /* nested submaps not allowed */
340 
341 	mach_vm_address_t entry_start = start;
342 	mach_vm_size_t entry_size;
343 	assert(get_info_for_address(&entry_start, &entry_size, out_info, checker->submap_depth));
344 	assert(entry_start == start);
345 	assert(entry_size == size);
346 }
347 
348 
349 static test_result_t
test_single_entry_1(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)350 test_single_entry_1(
351 	checker_list_t *checker_list,
352 	mach_vm_address_t start,
353 	mach_vm_size_t size)
354 {
355 	/* test range is a single allocation */
356 	vm_entry_checker_t *checker = checker_list_nth(checker_list, 0);
357 	vm_region_submap_info_data_64_t info;
358 	assert_allocation_checker_and_entry(checker, start, size, &info);
359 
360 	return TestSucceeded;
361 }
362 
363 static test_result_t
test_single_entry_2(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)364 test_single_entry_2(
365 	checker_list_t *checker_list,
366 	mach_vm_address_t start,
367 	mach_vm_size_t size)
368 {
369 	vm_entry_checker_t *checker = checker_list_nth(checker_list, 0);
370 	vm_region_submap_info_data_64_t info;
371 
372 	/* test range excludes the end of the allocation */
373 	assert(size == DEFAULT_ENTRY_SIZE - DEFAULT_PARTIAL_ENTRY_SIZE);
374 	assert_allocation_checker_and_entry(checker,
375 	    start, DEFAULT_ENTRY_SIZE, &info);
376 
377 	return TestSucceeded;
378 }
379 
380 static test_result_t
test_single_entry_3(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)381 test_single_entry_3(
382 	checker_list_t *checker_list,
383 	mach_vm_address_t start,
384 	mach_vm_size_t size)
385 {
386 	vm_entry_checker_t *checker = checker_list_nth(checker_list, 0);
387 	vm_region_submap_info_data_64_t info;
388 
389 	/* test range excludes the start of the allocation */
390 	assert(size == DEFAULT_ENTRY_SIZE - DEFAULT_PARTIAL_ENTRY_SIZE);
391 	assert_allocation_checker_and_entry(checker,
392 	    start - DEFAULT_PARTIAL_ENTRY_SIZE, DEFAULT_ENTRY_SIZE, &info);
393 
394 	return TestSucceeded;
395 }
396 
397 static test_result_t
test_single_entry_4(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)398 test_single_entry_4(
399 	checker_list_t *checker_list,
400 	mach_vm_address_t start,
401 	mach_vm_size_t size)
402 {
403 	vm_entry_checker_t *checker = checker_list_nth(checker_list, 0);
404 	vm_region_submap_info_data_64_t info;
405 
406 	/* test range excludes the start and end of the allocation */
407 	assert(size == DEFAULT_ENTRY_SIZE - DEFAULT_PARTIAL_ENTRY_SIZE);
408 	assert_allocation_checker_and_entry(checker,
409 	    start - DEFAULT_PARTIAL_ENTRY_SIZE / 2, DEFAULT_ENTRY_SIZE, &info);
410 
411 	return TestSucceeded;
412 }
413 
414 
415 static test_result_t
test_multiple_entries_1(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)416 test_multiple_entries_1(
417 	checker_list_t *checker_list,
418 	mach_vm_address_t start,
419 	mach_vm_size_t size)
420 {
421 	assert_allocation_and_hole_pattern(checker_list, "##");
422 	assert(start == checker_range_start_address(checker_list->entries));
423 	assert(size == DEFAULT_ENTRY_SIZE * 2);
424 	return TestSucceeded;
425 }
426 
427 static test_result_t
test_multiple_entries_2(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)428 test_multiple_entries_2(
429 	checker_list_t *checker_list,
430 	mach_vm_address_t start,
431 	mach_vm_size_t size)
432 {
433 	assert_allocation_and_hole_pattern(checker_list, "###");
434 	assert(start == checker_range_start_address(checker_list->entries));
435 	assert(size == DEFAULT_ENTRY_SIZE * 3);
436 	return TestSucceeded;
437 }
438 
439 static test_result_t
test_multiple_entries_3(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)440 test_multiple_entries_3(
441 	checker_list_t *checker_list,
442 	mach_vm_address_t start,
443 	mach_vm_size_t size)
444 {
445 	assert_allocation_and_hole_pattern(checker_list,
446 	    "############"
447 	    "############"
448 	    "############"
449 	    "############");
450 	assert(start == checker_range_start_address(checker_list->entries));
451 	assert(size == DEFAULT_ENTRY_SIZE * 4 * 12);
452 	return TestSucceeded;
453 }
454 
455 static test_result_t
test_multiple_entries_4(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)456 test_multiple_entries_4(
457 	checker_list_t *checker_list,
458 	mach_vm_address_t start,
459 	mach_vm_size_t size)
460 {
461 	assert_allocation_and_hole_pattern(checker_list, "###");
462 	assert(start == checker_range_start_address(checker_list->entries));
463 	assert(size == DEFAULT_ENTRY_SIZE * 3 - DEFAULT_PARTIAL_ENTRY_SIZE);
464 	return TestSucceeded;
465 }
466 
467 static test_result_t
test_multiple_entries_5(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)468 test_multiple_entries_5(
469 	checker_list_t *checker_list,
470 	mach_vm_address_t start,
471 	mach_vm_size_t size)
472 {
473 	assert_allocation_and_hole_pattern(checker_list, "###");
474 	assert(start == checker_range_start_address(checker_list->entries) + DEFAULT_PARTIAL_ENTRY_SIZE);
475 	assert(size == DEFAULT_ENTRY_SIZE * 3 - DEFAULT_PARTIAL_ENTRY_SIZE);
476 	return TestSucceeded;
477 }
478 
479 static test_result_t
test_multiple_entries_6(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)480 test_multiple_entries_6(
481 	checker_list_t *checker_list,
482 	mach_vm_address_t start,
483 	mach_vm_size_t size)
484 {
485 	assert_allocation_and_hole_pattern(checker_list, "###");
486 	assert(start == checker_range_start_address(checker_list->entries) + DEFAULT_PARTIAL_ENTRY_SIZE / 2);
487 	assert(size == DEFAULT_ENTRY_SIZE * 3 - DEFAULT_PARTIAL_ENTRY_SIZE);
488 	return TestSucceeded;
489 }
490 
491 
492 static test_result_t
test_some_holes_1(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)493 test_some_holes_1(
494 	checker_list_t *checker_list,
495 	mach_vm_address_t start,
496 	mach_vm_size_t size)
497 {
498 	assert_allocation_and_hole_pattern(checker_list, ".#");
499 	assert(start == checker_range_start_address(checker_list->entries));
500 	assert(size == DEFAULT_ENTRY_SIZE * 2);
501 	return TestSucceeded;
502 }
503 
504 static test_result_t
test_some_holes_2(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)505 test_some_holes_2(
506 	checker_list_t *checker_list,
507 	mach_vm_address_t start,
508 	mach_vm_size_t size)
509 {
510 	assert_allocation_and_hole_pattern(checker_list, ".###");
511 	assert(start == checker_range_start_address(checker_list->entries));
512 	assert(size == DEFAULT_ENTRY_SIZE * 4);
513 	return TestSucceeded;
514 }
515 
516 static test_result_t
test_some_holes_3(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)517 test_some_holes_3(
518 	checker_list_t *checker_list,
519 	mach_vm_address_t start,
520 	mach_vm_size_t size)
521 {
522 	assert_allocation_and_hole_pattern(checker_list, ".#");
523 	assert(start == checker_range_start_address(checker_list->entries));
524 	assert(size == DEFAULT_ENTRY_SIZE * 2 - DEFAULT_PARTIAL_ENTRY_SIZE);
525 	return TestSucceeded;
526 }
527 
528 static test_result_t
test_some_holes_4(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)529 test_some_holes_4(
530 	checker_list_t *checker_list,
531 	mach_vm_address_t start,
532 	mach_vm_size_t size)
533 {
534 	assert_allocation_and_hole_pattern(checker_list, ".###");
535 	assert(start == checker_range_start_address(checker_list->entries));
536 	assert(size == DEFAULT_ENTRY_SIZE * 4 - DEFAULT_PARTIAL_ENTRY_SIZE);
537 	return TestSucceeded;
538 }
539 
540 static test_result_t
test_some_holes_5(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)541 test_some_holes_5(
542 	checker_list_t *checker_list,
543 	mach_vm_address_t start,
544 	mach_vm_size_t size)
545 {
546 	assert_allocation_and_hole_pattern(checker_list, "#.");
547 	assert(start == checker_range_start_address(checker_list->entries));
548 	assert(size == DEFAULT_ENTRY_SIZE * 2);
549 	return TestSucceeded;
550 }
551 
552 static test_result_t
test_some_holes_6(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)553 test_some_holes_6(
554 	checker_list_t *checker_list,
555 	mach_vm_address_t start,
556 	mach_vm_size_t size)
557 {
558 	assert_allocation_and_hole_pattern(checker_list, "###.");
559 	assert(start == checker_range_start_address(checker_list->entries));
560 	assert(size == DEFAULT_ENTRY_SIZE * 4);
561 	return TestSucceeded;
562 }
563 
564 static test_result_t
test_some_holes_7(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)565 test_some_holes_7(
566 	checker_list_t *checker_list,
567 	mach_vm_address_t start,
568 	mach_vm_size_t size)
569 {
570 	assert_allocation_and_hole_pattern(checker_list, "#.");
571 	assert(start == checker_range_start_address(checker_list->entries) + DEFAULT_PARTIAL_ENTRY_SIZE);
572 	assert(size == DEFAULT_ENTRY_SIZE * 2 - DEFAULT_PARTIAL_ENTRY_SIZE);
573 	return TestSucceeded;
574 }
575 
576 static test_result_t
test_some_holes_8(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)577 test_some_holes_8(
578 	checker_list_t *checker_list,
579 	mach_vm_address_t start,
580 	mach_vm_size_t size)
581 {
582 	assert_allocation_and_hole_pattern(checker_list, "###.");
583 	assert(start == checker_range_start_address(checker_list->entries) + DEFAULT_PARTIAL_ENTRY_SIZE);
584 	assert(size == DEFAULT_ENTRY_SIZE * 4 - DEFAULT_PARTIAL_ENTRY_SIZE);
585 	return TestSucceeded;
586 }
587 
588 static test_result_t
test_some_holes_9(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)589 test_some_holes_9(
590 	checker_list_t *checker_list,
591 	mach_vm_address_t start,
592 	mach_vm_size_t size)
593 {
594 	assert_allocation_and_hole_pattern(checker_list, "#.#");
595 	assert(start == checker_range_start_address(checker_list->entries));
596 	assert(size == DEFAULT_ENTRY_SIZE * 3);
597 	return TestSucceeded;
598 }
599 
600 static test_result_t
test_some_holes_10(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)601 test_some_holes_10(
602 	checker_list_t *checker_list,
603 	mach_vm_address_t start,
604 	mach_vm_size_t size)
605 {
606 	assert_allocation_and_hole_pattern(checker_list, "#.#.#");
607 	assert(start == checker_range_start_address(checker_list->entries));
608 	assert(size == DEFAULT_ENTRY_SIZE * 5);
609 	return TestSucceeded;
610 }
611 
612 static test_result_t
test_some_holes_11(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)613 test_some_holes_11(
614 	checker_list_t *checker_list,
615 	mach_vm_address_t start,
616 	mach_vm_size_t size)
617 {
618 	assert_allocation_and_hole_pattern(checker_list, "##.##.##");
619 	assert(start == checker_range_start_address(checker_list->entries));
620 	assert(size == DEFAULT_ENTRY_SIZE * 8);
621 	return TestSucceeded;
622 }
623 
624 static test_result_t
test_some_holes_12(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)625 test_some_holes_12(
626 	checker_list_t *checker_list,
627 	mach_vm_address_t start,
628 	mach_vm_size_t size)
629 {
630 	assert_allocation_and_hole_pattern(checker_list, "###.###.###");
631 	assert(start == checker_range_start_address(checker_list->entries));
632 	assert(size == DEFAULT_ENTRY_SIZE * 11);
633 	return TestSucceeded;
634 }
635 
636 
637 static test_result_t
test_all_holes_1(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)638 test_all_holes_1(
639 	checker_list_t *checker_list,
640 	mach_vm_address_t start,
641 	mach_vm_size_t size)
642 {
643 	assert_allocation_and_hole_pattern(checker_list, "#.#");
644 	assert(start == checker_range_start_address(checker_list->entries) + DEFAULT_ENTRY_SIZE);
645 	assert(size == DEFAULT_ENTRY_SIZE);
646 	return TestSucceeded;
647 }
648 
649 static test_result_t
test_all_holes_2(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)650 test_all_holes_2(
651 	checker_list_t *checker_list,
652 	mach_vm_address_t start,
653 	mach_vm_size_t size)
654 {
655 	assert_allocation_and_hole_pattern(checker_list, "#.");
656 	assert(start == checker_range_start_address(checker_list->entries) + DEFAULT_ENTRY_SIZE);
657 	assert(size == DEFAULT_PARTIAL_ENTRY_SIZE);
658 	return TestSucceeded;
659 }
660 
661 static test_result_t
test_all_holes_3(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)662 test_all_holes_3(
663 	checker_list_t *checker_list,
664 	mach_vm_address_t start,
665 	mach_vm_size_t size)
666 {
667 	assert_allocation_and_hole_pattern(checker_list, ".#");
668 	assert(start == checker_range_start_address(checker_list->entries) + DEFAULT_PARTIAL_ENTRY_SIZE);
669 	assert(size == DEFAULT_PARTIAL_ENTRY_SIZE);
670 	return TestSucceeded;
671 }
672 
673 static test_result_t
test_all_holes_4(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)674 test_all_holes_4(
675 	checker_list_t *checker_list,
676 	mach_vm_address_t start,
677 	mach_vm_size_t size)
678 {
679 	assert_allocation_and_hole_pattern(checker_list, ".");
680 	assert(start == checker_range_start_address(checker_list->entries) + DEFAULT_PARTIAL_ENTRY_SIZE / 2);
681 	assert(size == DEFAULT_PARTIAL_ENTRY_SIZE);
682 	return TestSucceeded;
683 }
684 
685 
686 static test_result_t
test_null_entry(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)687 test_null_entry(
688 	checker_list_t *checker_list,
689 	mach_vm_address_t start,
690 	mach_vm_size_t size)
691 {
692 	vm_entry_checker_t *checker = checker_list_nth(checker_list, 0);
693 	vm_region_submap_info_data_64_t info;
694 	assert_allocation_checker_and_entry(checker, start, size, &info);
695 
696 	/* entry's object is null */
697 	assert(info.object_id_full == 0);
698 	assert(checker->object->object_id == 0);
699 
700 	return TestSucceeded;
701 }
702 
703 static test_result_t
test_nonresident_entry(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)704 test_nonresident_entry(
705 	checker_list_t *checker_list,
706 	mach_vm_address_t start,
707 	mach_vm_size_t size)
708 {
709 	vm_entry_checker_t *checker = checker_list_nth(checker_list, 0);
710 	vm_region_submap_info_data_64_t info;
711 	assert_allocation_checker_and_entry(checker, start, size, &info);
712 
713 	/* entry has an object, but its pages are not resident */
714 	assert(info.object_id_full != 0);
715 	assert(info.pages_resident == 0);
716 
717 	assert(checker->object->object_id != 0);
718 	assert(checker->pages_resident == 0);
719 
720 	return TestSucceeded;
721 }
722 
723 static test_result_t
test_resident_entry(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)724 test_resident_entry(
725 	checker_list_t *checker_list,
726 	mach_vm_address_t start,
727 	mach_vm_size_t size)
728 {
729 	vm_entry_checker_t *checker = checker_list_nth(checker_list, 0);
730 	vm_region_submap_info_data_64_t info;
731 	assert_allocation_checker_and_entry(checker, start, size, &info);
732 
733 	/* entry has an object and its pages are resident */
734 	assert(info.pages_resident == size / PAGE_SIZE);
735 	assert(checker->pages_resident == size / PAGE_SIZE);
736 	assert(checker->object->object_id != 0);
737 
738 	return TestSucceeded;
739 }
740 
741 /* common code for two-shared-entry tests */
742 static void
test_one_shared_pair(checker_list_t * checker_list,mach_vm_address_t left_entry_start,mach_vm_address_t right_entry_start,mach_vm_size_t size,mach_vm_address_t right_object_offset)743 test_one_shared_pair(
744 	checker_list_t *checker_list,
745 	mach_vm_address_t left_entry_start,
746 	mach_vm_address_t right_entry_start,
747 	mach_vm_size_t size,
748 	mach_vm_address_t right_object_offset)
749 {
750 	/*
751 	 * Two entries, both have the same object with refcount two.
752 	 * Right entry's object offset varies.
753 	 */
754 	vm_entry_checker_t *left_checker =
755 	    checker_list_find_allocation(checker_list, left_entry_start);
756 	vm_entry_checker_t *right_checker =
757 	    checker_list_find_allocation(checker_list, right_entry_start);
758 	assert(left_checker);
759 	assert(right_checker);
760 
761 	vm_region_submap_info_data_64_t left_info, right_info;
762 	assert_allocation_checker_and_entry(left_checker, left_entry_start, size, &left_info);
763 	assert_allocation_checker_and_entry(right_checker, right_entry_start, size, &right_info);
764 
765 	assert(left_info.object_id_full != 0);
766 	assert(left_info.object_id_full == right_info.object_id_full);
767 	assert(left_info.ref_count == 2);
768 	assert(right_info.ref_count == 2);
769 	assert(left_info.share_mode == SM_TRUESHARED);
770 	assert(right_info.share_mode == SM_TRUESHARED);
771 	assert(left_info.offset == 0);
772 	assert(right_info.offset == right_object_offset);
773 	assert(left_info.user_tag != right_info.user_tag);
774 
775 	assert(left_checker->object == right_checker->object);
776 	/* checker doesn't distinguish SM_SHARED from SM_TRUESHARED */
777 	assert(checker_share_mode(left_checker) == SM_SHARED);
778 	assert(checker_share_mode(right_checker) == SM_SHARED);
779 	assert(left_checker->object_offset == 0);
780 	assert(right_checker->object_offset == right_object_offset);
781 	assert(left_checker->user_tag != right_checker->user_tag);
782 }
783 
784 static test_result_t
test_shared_entry(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)785 test_shared_entry(
786 	checker_list_t *checker_list,
787 	mach_vm_address_t start,
788 	mach_vm_size_t size)
789 {
790 	/* entries are both at object offset 0 */
791 	test_one_shared_pair(checker_list, start, start + size, size, 0);
792 	return TestSucceeded;
793 }
794 
795 static test_result_t
test_shared_entry_discontiguous(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)796 test_shared_entry_discontiguous(
797 	checker_list_t *checker_list,
798 	mach_vm_address_t start,
799 	mach_vm_size_t size)
800 {
801 	/*
802 	 * right entry's object offset begins
803 	 * after the left entry's range ends
804 	 */
805 	test_one_shared_pair(checker_list, start, start + size, size, DEFAULT_ENTRY_SIZE);
806 	return TestSucceeded;
807 }
808 
809 static test_result_t
test_shared_entry_partial(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)810 test_shared_entry_partial(
811 	checker_list_t *checker_list,
812 	mach_vm_address_t start,
813 	mach_vm_size_t size)
814 {
815 	/*
816 	 * right entry's object offset begins
817 	 * inside the left entry's range
818 	 */
819 	test_one_shared_pair(checker_list, start, start + size, size, DEFAULT_PARTIAL_ENTRY_SIZE);
820 	return TestSucceeded;
821 }
822 
823 static test_result_t
test_shared_entry_pairs(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)824 test_shared_entry_pairs(
825 	checker_list_t *checker_list,
826 	mach_vm_address_t start,
827 	mach_vm_size_t size)
828 {
829 	/*
830 	 * two shared pairs
831 	 */
832 	mach_vm_size_t entry_size = size / 4;
833 	mach_vm_address_t one = start;
834 	mach_vm_address_t two = one + entry_size;
835 	mach_vm_address_t three = two + entry_size;
836 	mach_vm_address_t four = three + entry_size;
837 
838 	test_one_shared_pair(checker_list, one, four, entry_size, 0);
839 	test_one_shared_pair(checker_list, two, three, entry_size, 0);
840 
841 	return TestSucceeded;
842 }
843 
844 static test_result_t
test_shared_entry_x1000(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)845 test_shared_entry_x1000(
846 	checker_list_t *checker_list,
847 	mach_vm_address_t start,
848 	mach_vm_size_t size)
849 {
850 	/* many entries, all of which share the same object */
851 
852 	entry_checker_range_t limit = checker_list_find_range(checker_list, start, size);
853 	assert(checker_range_count(limit) == 1000);
854 
855 	uint64_t shared_object_id = 0;
856 	FOREACH_CHECKER(checker, limit) {
857 		assert(checker->object);
858 		assert(checker->object->object_id_mode == object_has_known_id);
859 		if (!shared_object_id) {
860 			assert(checker->object->object_id != 0);
861 			shared_object_id = checker->object->object_id;
862 		}
863 		assert(checker->object->object_id == shared_object_id);
864 		assert(get_object_id_for_address(checker->address) == shared_object_id);
865 	}
866 
867 	return TestSucceeded;
868 }
869 
870 
871 /* common code for two-shared-entry tests */
872 static test_result_t
test_cow_entry(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)873 test_cow_entry(
874 	checker_list_t *checker_list,
875 	mach_vm_address_t start,
876 	mach_vm_size_t size)
877 {
878 	/*
879 	 * two entries, both have the same object and its refcount is two.
880 	 * [start, start + size) is only the first entry
881 	 */
882 	vm_entry_checker_t *left_checker = checker_list_nth(checker_list, 0);
883 	vm_region_submap_info_data_64_t left_info;
884 	assert_allocation_checker_and_entry(left_checker, start, size, &left_info);
885 
886 	vm_entry_checker_t *right_checker = checker_list_nth(checker_list, 1);
887 	vm_region_submap_info_data_64_t right_info;
888 	assert_allocation_checker_and_entry(right_checker, start + size, size, &right_info);
889 
890 	assert(left_info.object_id_full != 0);
891 	assert(left_info.object_id_full == right_info.object_id_full);
892 	assert(left_info.ref_count == 2);
893 	assert(right_info.ref_count == 2);
894 	assert(left_info.share_mode == SM_COW);
895 	assert(right_info.share_mode == SM_COW);
896 	assert(left_info.offset == 0);
897 	assert(right_info.offset == 0);
898 
899 	assert(left_checker->object == right_checker->object);
900 	assert(checker_share_mode(left_checker) == SM_COW);
901 	assert(checker_share_mode(right_checker) == SM_COW);
902 	assert(left_checker->object_offset == 0);
903 	assert(right_checker->object_offset == 0);
904 
905 	return TestSucceeded;
906 }
907 
908 static test_result_t
test_cow_unreferenced(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)909 test_cow_unreferenced(
910 	checker_list_t *checker_list,
911 	mach_vm_address_t start,
912 	mach_vm_size_t size)
913 {
914 	/*
915 	 * one COW entry with refcount 1
916 	 */
917 	vm_entry_checker_t *checker = checker_list_nth(checker_list, 0);
918 	vm_region_submap_info_data_64_t info;
919 	assert_allocation_checker_and_entry(checker, start, size, &info);
920 
921 	assert(info.share_mode == SM_COW);
922 	assert(info.object_id_full != 0);
923 	assert(info.ref_count == 1);
924 	assert(info.offset == 0);
925 
926 	assert(checker->object_offset == 0);
927 	assert(checker_share_mode(checker) == SM_COW);
928 	assert(checker->object);
929 	assert(checker->object->self_ref_count == 1);
930 
931 	return TestSucceeded;
932 }
933 
934 /* common checks for cow_nocow and nocow_cow */
935 static test_result_t
test_cow_nocow_common(vm_entry_checker_t * cow_checker,vm_entry_checker_t * plain_checker,mach_vm_address_t cow_start_address,mach_vm_address_t plain_start_address,mach_vm_size_t entry_size)936 test_cow_nocow_common(
937 	vm_entry_checker_t *cow_checker,
938 	vm_entry_checker_t *plain_checker,
939 	mach_vm_address_t cow_start_address,
940 	mach_vm_address_t plain_start_address,
941 	mach_vm_size_t entry_size)
942 {
943 	/* two entries: one is COW, one is not COW */
944 	vm_region_submap_info_data_64_t cow_info, plain_info;
945 	assert_allocation_checker_and_entry(cow_checker, cow_start_address, entry_size, &cow_info);
946 	assert_allocation_checker_and_entry(plain_checker, plain_start_address, entry_size, &plain_info);
947 
948 	assert(cow_info.share_mode == SM_COW);
949 	assert(plain_info.share_mode == SM_PRIVATE);
950 	assert(cow_info.object_id_full != 0);
951 	assert(cow_info.object_id_full != plain_info.object_id_full);
952 	assert(cow_info.ref_count == 2);
953 	assert(cow_info.offset == 0);
954 
955 	assert(checker_share_mode(cow_checker) == SM_COW);
956 	assert(checker_share_mode(plain_checker) == SM_PRIVATE);
957 	assert(cow_checker->object != NULL);
958 	assert(cow_checker->object != plain_checker->object);
959 	assert(cow_checker->object_offset == 0);
960 
961 	return TestSucceeded;
962 }
963 
964 static test_result_t
test_cow_nocow(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)965 test_cow_nocow(
966 	checker_list_t *checker_list,
967 	mach_vm_address_t start,
968 	mach_vm_size_t size)
969 {
970 	/*
971 	 * two entries: first is COW, second is not
972 	 */
973 	vm_entry_checker_t *cow_checker   = checker_list_nth(checker_list, 0);
974 	vm_entry_checker_t *plain_checker = checker_list_nth(checker_list, 1);
975 
976 	assert(size % 2 == 0);
977 	mach_vm_address_t cow_start = start;
978 	mach_vm_address_t plain_start = start + size / 2;
979 
980 	return test_cow_nocow_common(cow_checker, plain_checker,
981 	           cow_start, plain_start, size / 2);
982 }
983 
984 static test_result_t
test_nocow_cow(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)985 test_nocow_cow(
986 	checker_list_t *checker_list,
987 	mach_vm_address_t start,
988 	mach_vm_size_t size)
989 {
990 	/*
991 	 * two entries: first is not COW, second is COW
992 	 */
993 	vm_entry_checker_t *plain_checker = checker_list_nth(checker_list, 0);
994 	vm_entry_checker_t *cow_checker   = checker_list_nth(checker_list, 1);
995 
996 	assert(size % 2 == 0);
997 	mach_vm_address_t plain_start = start;
998 	mach_vm_address_t cow_start = start + size / 2;
999 
1000 	return test_cow_nocow_common(cow_checker, plain_checker,
1001 	           cow_start, plain_start, size / 2);
1002 }
1003 
1004 static test_result_t
test_cow_unreadable(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)1005 test_cow_unreadable(
1006 	checker_list_t *checker_list,
1007 	mach_vm_address_t start,
1008 	mach_vm_size_t size)
1009 {
1010 	/*
1011 	 * COW entry, unreadable
1012 	 */
1013 	vm_entry_checker_t *checker = checker_list_nth(checker_list, 0);
1014 	vm_region_submap_info_data_64_t info;
1015 	assert_allocation_checker_and_entry(checker, start, size, &info);
1016 
1017 	assert(info.share_mode == SM_COW);
1018 	assert(info.protection == VM_PROT_NONE);
1019 	assert(info.ref_count == 2);
1020 
1021 	assert(checker_share_mode(checker) == SM_COW);
1022 	assert(checker->protection == VM_PROT_NONE);
1023 	assert(checker->object != NULL);
1024 	assert(checker->object->self_ref_count == 2);
1025 
1026 	return TestSucceeded;
1027 }
1028 
1029 static test_result_t
test_cow_unwriteable(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)1030 test_cow_unwriteable(
1031 	checker_list_t *checker_list,
1032 	mach_vm_address_t start,
1033 	mach_vm_size_t size)
1034 {
1035 	/*
1036 	 * COW entry, readable but unwriteable
1037 	 */
1038 	vm_entry_checker_t *checker = checker_list_nth(checker_list, 0);
1039 	vm_region_submap_info_data_64_t info;
1040 	assert_allocation_checker_and_entry(checker, start, size, &info);
1041 
1042 	assert(info.share_mode == SM_COW);
1043 	assert(info.protection == VM_PROT_READ);
1044 	assert(info.ref_count == 2);
1045 
1046 	assert(checker_share_mode(checker) == SM_COW);
1047 	assert(checker->protection == VM_PROT_READ);
1048 	assert(checker->object != NULL);
1049 	assert(checker->object->self_ref_count == 2);
1050 
1051 	return TestSucceeded;
1052 }
1053 
1054 static test_result_t
test_permanent_entry(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)1055 test_permanent_entry(
1056 	checker_list_t *checker_list,
1057 	mach_vm_address_t start,
1058 	mach_vm_size_t size)
1059 {
1060 	destructively_assert_permanent_checker_and_entry(
1061 		checker_list_nth(checker_list, 0), start, size);
1062 
1063 	return TestSucceeded;
1064 }
1065 
1066 static test_result_t
test_permanent_before_permanent(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)1067 test_permanent_before_permanent(
1068 	checker_list_t *checker_list,
1069 	mach_vm_address_t start,
1070 	mach_vm_size_t size)
1071 {
1072 	destructively_assert_permanent_checker_and_entry(
1073 		checker_list_nth(checker_list, 0),
1074 		start, size / 2);
1075 	destructively_assert_permanent_checker_and_entry(
1076 		checker_list_nth(checker_list, 1),
1077 		start + size / 2, size / 2);
1078 
1079 	return TestSucceeded;
1080 }
1081 
1082 static test_result_t
test_permanent_before_allocation(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)1083 test_permanent_before_allocation(
1084 	checker_list_t *checker_list,
1085 	mach_vm_address_t start,
1086 	mach_vm_size_t size)
1087 {
1088 	destructively_assert_permanent_checker_and_entry(
1089 		checker_list_nth(checker_list, 0),
1090 		start, size / 2);
1091 	destructively_assert_nonpermanent_checker_and_entry(
1092 		checker_list,
1093 		checker_list_nth(checker_list, 1),
1094 		start + size / 2, size / 2);
1095 	assert_hole_checker_and_entry(
1096 		checker_list_nth(checker_list, 2),
1097 		start + size, DEFAULT_ENTRY_SIZE);
1098 	return TestSucceeded;
1099 }
1100 
1101 static test_result_t
test_permanent_before_allocation_2(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)1102 test_permanent_before_allocation_2(
1103 	checker_list_t *checker_list,
1104 	mach_vm_address_t start,
1105 	mach_vm_size_t size)
1106 {
1107 	vm_region_submap_info_data_64_t info;
1108 	destructively_assert_permanent_checker_and_entry(
1109 		checker_list_nth(checker_list, 0),
1110 		start, size / 2);
1111 	destructively_assert_nonpermanent_checker_and_entry(
1112 		checker_list,
1113 		checker_list_nth(checker_list, 1),
1114 		start + size / 2, size / 2);
1115 	assert_allocation_checker_and_entry(
1116 		checker_list_nth(checker_list, 2),
1117 		start + size, DEFAULT_ENTRY_SIZE, &info);
1118 
1119 	return TestSucceeded;
1120 }
1121 
1122 static test_result_t
test_permanent_before_hole(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)1123 test_permanent_before_hole(
1124 	checker_list_t *checker_list,
1125 	mach_vm_address_t start,
1126 	mach_vm_size_t size)
1127 {
1128 	destructively_assert_permanent_checker_and_entry(
1129 		checker_list_nth(checker_list, 0),
1130 		start, size / 2);
1131 	assert_hole_checker_and_entry(
1132 		checker_list_nth(checker_list, 1),
1133 		start + size / 2, size / 2);
1134 
1135 	return TestSucceeded;
1136 }
1137 
1138 static test_result_t
test_permanent_after_allocation(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)1139 test_permanent_after_allocation(
1140 	checker_list_t *checker_list,
1141 	mach_vm_address_t start,
1142 	mach_vm_size_t size)
1143 {
1144 	destructively_assert_nonpermanent_checker_and_entry(
1145 		checker_list,
1146 		checker_list_nth(checker_list, 0),
1147 		start, size / 2);
1148 	destructively_assert_permanent_checker_and_entry(
1149 		checker_list_nth(checker_list, 1),
1150 		start + size / 2, size / 2);
1151 
1152 	return TestSucceeded;
1153 }
1154 
1155 static test_result_t
test_permanent_after_hole(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)1156 test_permanent_after_hole(
1157 	checker_list_t *checker_list,
1158 	mach_vm_address_t start,
1159 	mach_vm_size_t size)
1160 {
1161 	assert_hole_checker_and_entry(
1162 		checker_list_nth(checker_list, 0),
1163 		start, size / 2);
1164 	destructively_assert_permanent_checker_and_entry(
1165 		checker_list_nth(checker_list, 1),
1166 		start + size / 2, size / 2);
1167 
1168 	return TestSucceeded;
1169 }
1170 
1171 
1172 static test_result_t
test_single_submap_single_entry_common(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)1173 test_single_submap_single_entry_common(
1174 	checker_list_t *checker_list,
1175 	mach_vm_address_t start,
1176 	mach_vm_size_t size)
1177 {
1178 	vm_region_submap_info_data_64_t info;
1179 
1180 	vm_entry_checker_t *submap_parent = checker_list_nth(checker_list, 0);
1181 	assert_submap_checker_and_entry(submap_parent, start, size, &info);
1182 
1183 	checker_list_t *submap_checkers DEFER_UNSLIDE =
1184 	    checker_get_and_slide_submap_checkers(submap_parent);
1185 
1186 	vm_entry_checker_t *submap_content = checker_list_nth(submap_checkers, 0);
1187 	assert_allocation_checker_and_entry(submap_content, start, size, &info);
1188 
1189 	return TestSucceeded;
1190 }
1191 
1192 static test_result_t
test_single_submap_single_entry(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)1193 test_single_submap_single_entry(
1194 	checker_list_t *checker_list,
1195 	mach_vm_address_t start,
1196 	mach_vm_size_t size)
1197 {
1198 	return test_single_submap_single_entry_common(
1199 		checker_list, start, size);
1200 }
1201 
1202 static test_result_t
test_single_submap_single_entry_first_pages(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)1203 test_single_submap_single_entry_first_pages(
1204 	checker_list_t *checker_list,
1205 	mach_vm_address_t start,
1206 	mach_vm_size_t size)
1207 {
1208 	/* tested range excludes the last 1/2 of the real entry */
1209 	mach_vm_size_t submap_size = size * 2;
1210 	mach_vm_address_t submap_start = start;
1211 	return test_single_submap_single_entry_common(
1212 		checker_list, submap_start, submap_size);
1213 }
1214 
1215 static test_result_t
test_single_submap_single_entry_last_pages(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)1216 test_single_submap_single_entry_last_pages(
1217 	checker_list_t *checker_list,
1218 	mach_vm_address_t start,
1219 	mach_vm_size_t size)
1220 {
1221 	/* tested range excludes the first 1/2 of the real entry */
1222 	mach_vm_size_t submap_size = size * 2;
1223 	mach_vm_address_t submap_start = start - submap_size / 2;
1224 	return test_single_submap_single_entry_common(
1225 		checker_list, submap_start, submap_size);
1226 }
1227 
1228 static test_result_t
test_single_submap_single_entry_middle_pages(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)1229 test_single_submap_single_entry_middle_pages(
1230 	checker_list_t *checker_list,
1231 	mach_vm_address_t start,
1232 	mach_vm_size_t size)
1233 {
1234 	/* tested range excludes the first 1/4 and last 1/4 of the real entry */
1235 	mach_vm_size_t submap_size = size * 2;
1236 	mach_vm_address_t submap_start = start - submap_size / 4;
1237 	return test_single_submap_single_entry_common(
1238 		checker_list, submap_start, submap_size);
1239 }
1240 
1241 static test_result_t
test_single_submap_oversize_entry_common(checker_list_t * checker_list,mach_vm_address_t parent_start,mach_vm_size_t parent_size,mach_vm_address_t parent_offset,mach_vm_size_t submap_size)1242 test_single_submap_oversize_entry_common(
1243 	checker_list_t *checker_list,
1244 	mach_vm_address_t parent_start,
1245 	mach_vm_size_t parent_size,
1246 	mach_vm_address_t parent_offset,
1247 	mach_vm_size_t submap_size)
1248 {
1249 	vm_region_submap_info_data_64_t parent_info, content_info;
1250 
1251 	vm_entry_checker_t *submap_parent = checker_list_nth(checker_list, 0);
1252 	assert_submap_checker_and_entry(submap_parent, parent_start, parent_size, &parent_info);
1253 	assert(submap_parent->object_offset == parent_offset);
1254 	assert(parent_info.offset == parent_offset);
1255 
1256 	checker_list_t *submap_checkers DEFER_UNSLIDE =
1257 	    checker_get_and_slide_submap_checkers(submap_parent);
1258 
1259 	/*
1260 	 * Actual entry in submap is clamped to the parent map submap view
1261 	 * by vm_region. Checker for that entry is unchanged.
1262 	 */
1263 	vm_entry_checker_t *submap_content = checker_list_nth(submap_checkers, 0);
1264 	assert_allocation_checker(submap_content, parent_start - parent_offset, submap_size);
1265 	assert(submap_content->submap_depth == 1);
1266 	assert_allocation_entry(parent_start, parent_size, 1 /* submap_depth */, &content_info);
1267 	assert(submap_content->object_offset == 0);
1268 	assert(content_info.offset == 0);
1269 
1270 	return TestSucceeded;
1271 }
1272 
1273 static test_result_t
test_single_submap_oversize_entry_at_start(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)1274 test_single_submap_oversize_entry_at_start(
1275 	checker_list_t *checker_list,
1276 	mach_vm_address_t start,
1277 	mach_vm_size_t size)
1278 {
1279 	/*
1280 	 * parent map:                     [start, start+size]
1281 	 * submap:       [0                (size)      size*2]
1282 	 */
1283 	return test_single_submap_oversize_entry_common(checker_list,
1284 	           start, size,
1285 	           size /* parent_offset */, size * 2 /* submap_size */);
1286 }
1287 
1288 static test_result_t
test_single_submap_oversize_entry_at_end(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)1289 test_single_submap_oversize_entry_at_end(
1290 	checker_list_t *checker_list,
1291 	mach_vm_address_t start,
1292 	mach_vm_size_t size)
1293 {
1294 	/*
1295 	 * parent map:   [start, start+size]
1296 	 * submap:       [0                (size)      size*2]
1297 	 */
1298 	return test_single_submap_oversize_entry_common(checker_list,
1299 	           start, size,
1300 	           0 /* parent_offset */, size * 2 /* submap_size */);
1301 }
1302 
1303 static test_result_t
test_single_submap_oversize_entry_at_both(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)1304 test_single_submap_oversize_entry_at_both(
1305 	checker_list_t *checker_list,
1306 	mach_vm_address_t start,
1307 	mach_vm_size_t size)
1308 {
1309 	/*
1310 	 * parent map:            [start, start+size]
1311 	 * submap:       [0       (size / 2)           size*2]
1312 	 */
1313 	return test_single_submap_oversize_entry_common(checker_list,
1314 	           start, size,
1315 	           size / 2 /* parent_offset */, size * 2 /* submap_size */);
1316 }
1317 
1318 static test_result_t
test_submap_before_allocation_common(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size,int submap_protection)1319 test_submap_before_allocation_common(
1320 	checker_list_t *checker_list,
1321 	mach_vm_address_t start,
1322 	mach_vm_size_t size,
1323 	int submap_protection)
1324 {
1325 	vm_region_submap_info_data_64_t submap_parent_info;
1326 	vm_entry_checker_t *submap_parent = checker_list_nth(checker_list, 0);
1327 	assert_submap_checker_and_entry(submap_parent,
1328 	    start, size / 2, &submap_parent_info);
1329 
1330 	vm_region_submap_info_data_64_t allocation_info;
1331 	vm_entry_checker_t *allocation = checker_list_nth(checker_list, 1);
1332 	assert_allocation_checker_and_entry(allocation,
1333 	    start + size / 2, size / 2, &allocation_info);
1334 
1335 	checker_list_t *submap_checkers DEFER_UNSLIDE =
1336 	    checker_get_and_slide_submap_checkers(submap_parent);
1337 
1338 	vm_region_submap_info_data_64_t submap_content_info;
1339 	vm_entry_checker_t *submap_content = checker_list_nth(submap_checkers, 0);
1340 	assert_allocation_checker(submap_content, start, size / 2);
1341 	assert_allocation_entry(start, size / 2, 1 /* submap_depth */, &submap_content_info);
1342 	assert_checker_and_entry_protection_equals(submap_content, &submap_content_info,
1343 	    submap_protection, submap_protection);
1344 
1345 	return TestSucceeded;
1346 }
1347 
1348 static test_result_t
test_submap_before_allocation(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)1349 test_submap_before_allocation(
1350 	checker_list_t *checker_list,
1351 	mach_vm_address_t start,
1352 	mach_vm_size_t size)
1353 {
1354 	return test_submap_before_allocation_common(checker_list,
1355 	           start, size, VM_PROT_READ | VM_PROT_WRITE);
1356 }
1357 
1358 static test_result_t
test_submap_before_allocation_ro(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)1359 test_submap_before_allocation_ro(
1360 	checker_list_t *checker_list,
1361 	mach_vm_address_t start,
1362 	mach_vm_size_t size)
1363 {
1364 	return test_submap_before_allocation_common(checker_list,
1365 	           start, size, VM_PROT_READ);
1366 }
1367 
1368 static test_result_t
test_submap_after_allocation_common(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size,int submap_protection)1369 test_submap_after_allocation_common(
1370 	checker_list_t *checker_list,
1371 	mach_vm_address_t start,
1372 	mach_vm_size_t size,
1373 	int submap_protection)
1374 {
1375 	vm_region_submap_info_data_64_t allocation_info;
1376 	vm_entry_checker_t *allocation = checker_list_nth(checker_list, 0);
1377 	assert_allocation_checker_and_entry(allocation,
1378 	    start, size / 2, &allocation_info);
1379 
1380 	vm_region_submap_info_data_64_t submap_parent_info;
1381 	vm_entry_checker_t *submap_parent = checker_list_nth(checker_list, 1);
1382 	assert_submap_checker_and_entry(submap_parent,
1383 	    start + size / 2, size / 2, &submap_parent_info);
1384 
1385 	checker_list_t *submap_checkers DEFER_UNSLIDE =
1386 	    checker_get_and_slide_submap_checkers(submap_parent);
1387 
1388 	vm_region_submap_info_data_64_t submap_content_info;
1389 	vm_entry_checker_t *submap_content = checker_list_nth(submap_checkers, 0);
1390 	assert_allocation_checker(submap_content, start + size / 2, size / 2);
1391 	assert_allocation_entry(start + size / 2, size / 2, 1 /* submap_depth */, &submap_content_info);
1392 	assert_checker_and_entry_protection_equals(submap_content, &submap_content_info,
1393 	    submap_protection, submap_protection);
1394 
1395 	return TestSucceeded;
1396 }
1397 
1398 static test_result_t
test_submap_after_allocation(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)1399 test_submap_after_allocation(
1400 	checker_list_t *checker_list,
1401 	mach_vm_address_t start,
1402 	mach_vm_size_t size)
1403 {
1404 	return test_submap_after_allocation_common(checker_list,
1405 	           start, size, VM_PROT_READ | VM_PROT_WRITE);
1406 }
1407 
1408 static test_result_t
test_submap_after_allocation_ro(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)1409 test_submap_after_allocation_ro(
1410 	checker_list_t *checker_list,
1411 	mach_vm_address_t start,
1412 	mach_vm_size_t size)
1413 {
1414 	return test_submap_after_allocation_common(checker_list,
1415 	           start, size, VM_PROT_READ);
1416 }
1417 
1418 static test_result_t
test_submap_before_hole_common(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size,int submap_protection)1419 test_submap_before_hole_common(
1420 	checker_list_t *checker_list,
1421 	mach_vm_address_t start,
1422 	mach_vm_size_t size,
1423 	int submap_protection)
1424 {
1425 	vm_region_submap_info_data_64_t submap_parent_info;
1426 	vm_entry_checker_t *submap_parent = checker_list_nth(checker_list, 0);
1427 	assert_submap_checker_and_entry(submap_parent,
1428 	    start, size / 2, &submap_parent_info);
1429 
1430 	vm_entry_checker_t *hole = checker_list_nth(checker_list, 1);
1431 	assert_hole_checker_and_entry(hole,
1432 	    start + size / 2, size / 2);
1433 
1434 	checker_list_t *submap_checkers DEFER_UNSLIDE =
1435 	    checker_get_and_slide_submap_checkers(submap_parent);
1436 
1437 	vm_region_submap_info_data_64_t submap_content_info;
1438 	vm_entry_checker_t *submap_content = checker_list_nth(submap_checkers, 0);
1439 	assert_allocation_checker(submap_content, start, size / 2);
1440 	assert_allocation_entry(start, size / 2, 1 /* submap_depth */, &submap_content_info);
1441 	assert_checker_and_entry_protection_equals(submap_content, &submap_content_info,
1442 	    submap_protection, submap_protection);
1443 
1444 	return TestSucceeded;
1445 }
1446 
1447 static test_result_t
test_submap_before_hole(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)1448 test_submap_before_hole(
1449 	checker_list_t *checker_list,
1450 	mach_vm_address_t start,
1451 	mach_vm_size_t size)
1452 {
1453 	return test_submap_before_hole_common(checker_list,
1454 	           start, size, VM_PROT_READ | VM_PROT_WRITE);
1455 }
1456 
1457 static test_result_t
test_submap_before_hole_ro(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)1458 test_submap_before_hole_ro(
1459 	checker_list_t *checker_list,
1460 	mach_vm_address_t start,
1461 	mach_vm_size_t size)
1462 {
1463 	return test_submap_before_hole_common(checker_list,
1464 	           start, size, VM_PROT_READ);
1465 }
1466 
1467 static test_result_t
test_submap_after_hole_common(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size,int submap_protection)1468 test_submap_after_hole_common(
1469 	checker_list_t *checker_list,
1470 	mach_vm_address_t start,
1471 	mach_vm_size_t size,
1472 	int submap_protection)
1473 {
1474 	vm_entry_checker_t *hole = checker_list_nth(checker_list, 0);
1475 	assert_hole_checker_and_entry(hole,
1476 	    start, size / 2);
1477 
1478 	vm_region_submap_info_data_64_t submap_parent_info;
1479 	vm_entry_checker_t *submap_parent = checker_list_nth(checker_list, 1);
1480 	assert_submap_checker_and_entry(submap_parent,
1481 	    start + size / 2, size / 2, &submap_parent_info);
1482 
1483 	checker_list_t *submap_checkers DEFER_UNSLIDE =
1484 	    checker_get_and_slide_submap_checkers(submap_parent);
1485 
1486 	vm_region_submap_info_data_64_t submap_content_info;
1487 	vm_entry_checker_t *submap_content = checker_list_nth(submap_checkers, 0);
1488 	assert_allocation_checker(submap_content, start + size / 2, size / 2);
1489 	assert_allocation_entry(start + size / 2, size / 2, 1 /* submap_depth */, &submap_content_info);
1490 	assert_checker_and_entry_protection_equals(submap_content, &submap_content_info,
1491 	    submap_protection, submap_protection);
1492 
1493 	return TestSucceeded;
1494 }
1495 
1496 static test_result_t
test_submap_after_hole(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)1497 test_submap_after_hole(
1498 	checker_list_t *checker_list,
1499 	mach_vm_address_t start,
1500 	mach_vm_size_t size)
1501 {
1502 	return test_submap_after_hole_common(checker_list,
1503 	           start, size, VM_PROT_READ | VM_PROT_WRITE);
1504 }
1505 
1506 static test_result_t
test_submap_after_hole_ro(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)1507 test_submap_after_hole_ro(
1508 	checker_list_t *checker_list,
1509 	mach_vm_address_t start,
1510 	mach_vm_size_t size)
1511 {
1512 	return test_submap_after_hole_common(checker_list,
1513 	           start, size, VM_PROT_READ);
1514 }
1515 
1516 
1517 /*
1518  * Verify that the checker list consists of three entries,
1519  * a submap mapping, an allocation, and a submap mapping,
1520  * all of default size.
1521  */
1522 static void
assert_submap_allocation_submap(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)1523 assert_submap_allocation_submap(
1524 	checker_list_t *checker_list,
1525 	mach_vm_address_t start,
1526 	mach_vm_size_t size)
1527 {
1528 	vm_region_submap_info_data_64_t info;
1529 	vm_entry_checker_t *checker;
1530 	mach_vm_size_t offset;
1531 
1532 	assert(checker_range_count(checker_list->entries) == 3);
1533 
1534 	offset = DEFAULT_ENTRY_SIZE * 0;
1535 	checker = checker_list_nth(checker_list, 0);
1536 	assert_submap_checker_and_entry(checker,
1537 	    start + offset, DEFAULT_ENTRY_SIZE, &info);
1538 	assert(checker->object_offset == offset);
1539 	assert(info.offset == offset);
1540 
1541 	offset = DEFAULT_ENTRY_SIZE * 1;
1542 	checker = checker_list_nth(checker_list, 1);
1543 	assert_allocation_checker_and_entry(checker,
1544 	    start + offset, DEFAULT_ENTRY_SIZE, &info);
1545 
1546 	offset = DEFAULT_ENTRY_SIZE * 2;
1547 	checker = checker_list_nth(checker_list, 2);
1548 	assert_submap_checker_and_entry(checker,
1549 	    start + offset, DEFAULT_ENTRY_SIZE, &info);
1550 	assert(checker->object_offset == offset);
1551 	assert(info.offset == offset);
1552 
1553 	offset = DEFAULT_ENTRY_SIZE * 3;
1554 	assert(size == offset);
1555 }
1556 
1557 static test_result_t
test_submap_allocation_submap_one_entry_common(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size,int submap_protection)1558 test_submap_allocation_submap_one_entry_common(
1559 	checker_list_t *checker_list,
1560 	mach_vm_address_t start,
1561 	mach_vm_size_t size,
1562 	int submap_protection)
1563 {
1564 	/* parent map is submap - allocation - submap */
1565 	assert_submap_allocation_submap(checker_list, start, size);
1566 
1567 	/* submap is one allocation entry */
1568 	checker_list_t *submap_checkers DEFER_UNSLIDE =
1569 	    checker_get_and_slide_submap_checkers(checker_list_nth(checker_list, 0));
1570 	assert(checker_range_count(submap_checkers->entries) == 1);
1571 	vm_entry_checker_t *submap_content = checker_list_nth(submap_checkers, 0);
1572 	assert_allocation_checker(submap_content, start, size);
1573 	assert(submap_content->protection == submap_protection);
1574 	assert(submap_content->max_protection == submap_protection);
1575 
1576 	return TestSucceeded;
1577 }
1578 
1579 static test_result_t
test_submap_allocation_submap_one_entry(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)1580 test_submap_allocation_submap_one_entry(
1581 	checker_list_t *checker_list,
1582 	mach_vm_address_t start,
1583 	mach_vm_size_t size)
1584 {
1585 	return test_submap_allocation_submap_one_entry_common(checker_list,
1586 	           start, size, VM_PROT_READ | VM_PROT_WRITE);
1587 }
1588 
1589 static test_result_t
test_submap_allocation_submap_one_entry_ro(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)1590 test_submap_allocation_submap_one_entry_ro(
1591 	checker_list_t *checker_list,
1592 	mach_vm_address_t start,
1593 	mach_vm_size_t size)
1594 {
1595 	return test_submap_allocation_submap_one_entry_common(checker_list,
1596 	           start, size, VM_PROT_READ);
1597 }
1598 
1599 static test_result_t
test_submap_allocation_submap_two_entries_common(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size,int submap_protection)1600 test_submap_allocation_submap_two_entries_common(
1601 	checker_list_t *checker_list,
1602 	mach_vm_address_t start,
1603 	mach_vm_size_t size,
1604 	int submap_protection)
1605 {
1606 	/* parent map is submap - allocation - submap */
1607 	assert_submap_allocation_submap(checker_list, start, size);
1608 
1609 	/* submap is two allocation entries */
1610 	checker_list_t *submap_checkers DEFER_UNSLIDE =
1611 	    checker_get_and_slide_submap_checkers(checker_list_nth(checker_list, 0));
1612 	assert(checker_range_count(submap_checkers->entries) == 2);
1613 
1614 	vm_entry_checker_t *submap_content = checker_list_nth(submap_checkers, 0);
1615 	assert_allocation_checker(submap_content, start, size / 2);
1616 	assert(submap_content->protection == submap_protection);
1617 	assert(submap_content->max_protection == submap_protection);
1618 
1619 	submap_content = checker_list_nth(submap_checkers, 1);
1620 	assert_allocation_checker(submap_content, start + size / 2, size / 2);
1621 	assert(submap_content->protection == submap_protection);
1622 	assert(submap_content->max_protection == submap_protection);
1623 
1624 	return TestSucceeded;
1625 }
1626 
1627 static test_result_t
test_submap_allocation_submap_two_entries(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)1628 test_submap_allocation_submap_two_entries(
1629 	checker_list_t *checker_list,
1630 	mach_vm_address_t start,
1631 	mach_vm_size_t size)
1632 {
1633 	return test_submap_allocation_submap_two_entries_common(checker_list,
1634 	           start, size, VM_PROT_READ | VM_PROT_WRITE);
1635 }
1636 
1637 static test_result_t
test_submap_allocation_submap_two_entries_ro(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)1638 test_submap_allocation_submap_two_entries_ro(
1639 	checker_list_t *checker_list,
1640 	mach_vm_address_t start,
1641 	mach_vm_size_t size)
1642 {
1643 	return test_submap_allocation_submap_two_entries_common(checker_list,
1644 	           start, size, VM_PROT_READ);
1645 }
1646 
1647 static test_result_t
test_submap_allocation_submap_three_entries_common(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size,int submap_protection)1648 test_submap_allocation_submap_three_entries_common(
1649 	checker_list_t *checker_list,
1650 	mach_vm_address_t start,
1651 	mach_vm_size_t size,
1652 	int submap_protection)
1653 {
1654 	/* parent map is submap - allocation - submap */
1655 	assert_submap_allocation_submap(checker_list, start, size);
1656 
1657 	/* submap is three allocation entries */
1658 	checker_list_t *submap_checkers DEFER_UNSLIDE =
1659 	    checker_get_and_slide_submap_checkers(checker_list_nth(checker_list, 0));
1660 	assert(checker_range_count(submap_checkers->entries) == 3);
1661 
1662 	vm_entry_checker_t *submap_content = checker_list_nth(submap_checkers, 0);
1663 	assert_allocation_checker(submap_content, start, size / 3);
1664 	assert(submap_content->protection == submap_protection);
1665 	assert(submap_content->max_protection == submap_protection);
1666 
1667 	submap_content = checker_list_nth(submap_checkers, 1);
1668 	assert_allocation_checker(submap_content, start + size / 3, size / 3);
1669 	assert(submap_content->protection == submap_protection);
1670 	assert(submap_content->max_protection == submap_protection);
1671 
1672 	submap_content = checker_list_nth(submap_checkers, 2);
1673 	assert_allocation_checker(submap_content, start + size / 3 * 2, size / 3);
1674 	assert(submap_content->protection == submap_protection);
1675 	assert(submap_content->max_protection == submap_protection);
1676 
1677 	return TestSucceeded;
1678 }
1679 
1680 static test_result_t
test_submap_allocation_submap_three_entries(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)1681 test_submap_allocation_submap_three_entries(
1682 	checker_list_t *checker_list,
1683 	mach_vm_address_t start,
1684 	mach_vm_size_t size)
1685 {
1686 	return test_submap_allocation_submap_three_entries_common(checker_list,
1687 	           start, size, VM_PROT_READ | VM_PROT_WRITE);
1688 }
1689 
1690 static test_result_t
test_submap_allocation_submap_three_entries_ro(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size)1691 test_submap_allocation_submap_three_entries_ro(
1692 	checker_list_t *checker_list,
1693 	mach_vm_address_t start,
1694 	mach_vm_size_t size)
1695 {
1696 	return test_submap_allocation_submap_three_entries_common(checker_list,
1697 	           start, size, VM_PROT_READ);
1698 }
1699 
1700 
1701 static void
assert_protection(mach_vm_address_t address,vm_prot_t prot,bool check_max,uint32_t submap_depth)1702 assert_protection(
1703 	mach_vm_address_t address,
1704 	vm_prot_t prot,
1705 	bool check_max,
1706 	uint32_t submap_depth)
1707 {
1708 	mach_vm_address_t info_address = address;
1709 	mach_vm_size_t info_size;
1710 	vm_region_submap_info_data_64_t info;
1711 	assert(get_info_for_address(&info_address, &info_size, &info, submap_depth));
1712 	assert(info_address == address);
1713 
1714 	if (check_max) {
1715 		T_QUIET; T_ASSERT_EQ(prot, info.max_protection, "entry max protection");
1716 	} else {
1717 		T_QUIET; T_ASSERT_EQ(prot, info.protection, "entry protection");
1718 	}
1719 }
1720 
1721 static test_result_t
test_protection_single_common(checker_list_t * checker_list,mach_vm_address_t address,vm_prot_t prot,vm_prot_t max)1722 test_protection_single_common(
1723 	checker_list_t *checker_list,
1724 	mach_vm_address_t address,
1725 	vm_prot_t prot, vm_prot_t max)
1726 {
1727 	vm_entry_checker_t *checker =
1728 	    checker_list_find_allocation(checker_list, address);
1729 	T_QUIET; T_ASSERT_NOTNULL(checker, "checker");
1730 	T_QUIET; T_ASSERT_EQ(checker->protection, prot, "checker protection");
1731 	T_QUIET; T_ASSERT_EQ(checker->max_protection, max, "checker max protection");
1732 
1733 	assert_protection(address, prot, false /* check max */, 0 /* submap depth */);
1734 	assert_protection(address, max, true /* check max */, 0 /* submap depth */);
1735 
1736 	return TestSucceeded;
1737 }
1738 
1739 static test_result_t
test_protection_pair_common(checker_list_t * checker_list,mach_vm_address_t address,vm_prot_t left_prot,vm_prot_t right_prot)1740 test_protection_pair_common(
1741 	checker_list_t *checker_list,
1742 	mach_vm_address_t address,
1743 	vm_prot_t left_prot,
1744 	vm_prot_t right_prot)
1745 {
1746 	vm_entry_checker_t *left_checker =
1747 	    checker_list_find_allocation(checker_list, address);
1748 	vm_entry_checker_t *right_checker = left_checker->next;
1749 
1750 	T_QUIET; T_ASSERT_NOTNULL(left_checker, "checker");
1751 	T_QUIET; T_ASSERT_EQ(left_checker->protection, left_prot, "left entry protection");
1752 	T_QUIET; T_ASSERT_EQ(right_checker->protection, right_prot, "right entry protection");
1753 
1754 	assert_protection(left_checker->address, left_prot, false /* check max */, 0 /* submap depth */);
1755 	assert_protection(right_checker->address, right_prot, false /* check max */, 0 /* submap depth */);
1756 
1757 	return TestSucceeded;
1758 }
1759 
1760 static test_result_t
test_protection_single_000_000(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size __unused)1761 test_protection_single_000_000(
1762 	checker_list_t *checker_list,
1763 	mach_vm_address_t start,
1764 	mach_vm_size_t size __unused)
1765 {
1766 	return test_protection_single_common(
1767 		checker_list, start, VM_PROT_NONE, VM_PROT_NONE);
1768 }
1769 
1770 static test_result_t
test_protection_single_000_r00(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size __unused)1771 test_protection_single_000_r00(
1772 	checker_list_t *checker_list,
1773 	mach_vm_address_t start,
1774 	mach_vm_size_t size __unused)
1775 {
1776 	return test_protection_single_common(
1777 		checker_list, start, VM_PROT_NONE, VM_PROT_READ);
1778 }
1779 
1780 static test_result_t
test_protection_single_000_0w0(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size __unused)1781 test_protection_single_000_0w0(
1782 	checker_list_t *checker_list,
1783 	mach_vm_address_t start,
1784 	mach_vm_size_t size __unused)
1785 {
1786 	return test_protection_single_common(
1787 		checker_list, start, VM_PROT_NONE, VM_PROT_WRITE);
1788 }
1789 
1790 static test_result_t
test_protection_single_000_rw0(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size __unused)1791 test_protection_single_000_rw0(
1792 	checker_list_t *checker_list,
1793 	mach_vm_address_t start,
1794 	mach_vm_size_t size __unused)
1795 {
1796 	return test_protection_single_common(
1797 		checker_list, start, VM_PROT_NONE, VM_PROT_READ | VM_PROT_WRITE);
1798 }
1799 
1800 static test_result_t
test_protection_single_r00_r00(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size __unused)1801 test_protection_single_r00_r00(
1802 	checker_list_t *checker_list,
1803 	mach_vm_address_t start,
1804 	mach_vm_size_t size __unused)
1805 {
1806 	return test_protection_single_common(
1807 		checker_list, start, VM_PROT_READ, VM_PROT_READ);
1808 }
1809 
1810 static test_result_t
test_protection_single_r00_rw0(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size __unused)1811 test_protection_single_r00_rw0(
1812 	checker_list_t *checker_list,
1813 	mach_vm_address_t start,
1814 	mach_vm_size_t size __unused)
1815 {
1816 	return test_protection_single_common(
1817 		checker_list, start, VM_PROT_READ, VM_PROT_READ | VM_PROT_WRITE);
1818 }
1819 
1820 static test_result_t
test_protection_single_0w0_0w0(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size __unused)1821 test_protection_single_0w0_0w0(
1822 	checker_list_t *checker_list,
1823 	mach_vm_address_t start,
1824 	mach_vm_size_t size __unused)
1825 {
1826 	return test_protection_single_common(
1827 		checker_list, start, VM_PROT_WRITE, VM_PROT_WRITE);
1828 }
1829 
1830 static test_result_t
test_protection_single_0w0_rw0(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size __unused)1831 test_protection_single_0w0_rw0(
1832 	checker_list_t *checker_list,
1833 	mach_vm_address_t start,
1834 	mach_vm_size_t size __unused)
1835 {
1836 	return test_protection_single_common(
1837 		checker_list, start, VM_PROT_WRITE, VM_PROT_READ | VM_PROT_WRITE);
1838 }
1839 
1840 static test_result_t
test_protection_single_rw0_rw0(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size __unused)1841 test_protection_single_rw0_rw0(
1842 	checker_list_t *checker_list,
1843 	mach_vm_address_t start,
1844 	mach_vm_size_t size __unused)
1845 {
1846 	return test_protection_single_common(
1847 		checker_list, start, VM_PROT_READ | VM_PROT_WRITE, VM_PROT_READ | VM_PROT_WRITE);
1848 }
1849 
1850 
1851 static test_result_t
test_protection_pair_000_000(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size __unused)1852 test_protection_pair_000_000(
1853 	checker_list_t *checker_list,
1854 	mach_vm_address_t start,
1855 	mach_vm_size_t size __unused)
1856 {
1857 	return test_protection_pair_common(
1858 		checker_list, start, VM_PROT_NONE, VM_PROT_NONE);
1859 }
1860 
1861 static test_result_t
test_protection_pair_000_r00(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size __unused)1862 test_protection_pair_000_r00(
1863 	checker_list_t *checker_list,
1864 	mach_vm_address_t start,
1865 	mach_vm_size_t size __unused)
1866 {
1867 	return test_protection_pair_common(
1868 		checker_list, start, VM_PROT_NONE, VM_PROT_READ);
1869 }
1870 
1871 static test_result_t
test_protection_pair_000_0w0(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size __unused)1872 test_protection_pair_000_0w0(
1873 	checker_list_t *checker_list,
1874 	mach_vm_address_t start,
1875 	mach_vm_size_t size __unused)
1876 {
1877 	return test_protection_pair_common(
1878 		checker_list, start, VM_PROT_NONE, VM_PROT_WRITE);
1879 }
1880 
1881 static test_result_t
test_protection_pair_000_rw0(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size __unused)1882 test_protection_pair_000_rw0(
1883 	checker_list_t *checker_list,
1884 	mach_vm_address_t start,
1885 	mach_vm_size_t size __unused)
1886 {
1887 	return test_protection_pair_common(
1888 		checker_list, start, VM_PROT_NONE, VM_PROT_READ | VM_PROT_WRITE);
1889 }
1890 
1891 static test_result_t
test_protection_pair_r00_000(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size __unused)1892 test_protection_pair_r00_000(
1893 	checker_list_t *checker_list,
1894 	mach_vm_address_t start,
1895 	mach_vm_size_t size __unused)
1896 {
1897 	return test_protection_pair_common(
1898 		checker_list, start, VM_PROT_READ, VM_PROT_NONE);
1899 }
1900 
1901 static test_result_t
test_protection_pair_r00_r00(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size __unused)1902 test_protection_pair_r00_r00(
1903 	checker_list_t *checker_list,
1904 	mach_vm_address_t start,
1905 	mach_vm_size_t size __unused)
1906 {
1907 	return test_protection_pair_common(
1908 		checker_list, start, VM_PROT_READ, VM_PROT_READ);
1909 }
1910 
1911 static test_result_t
test_protection_pair_r00_0w0(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size __unused)1912 test_protection_pair_r00_0w0(
1913 	checker_list_t *checker_list,
1914 	mach_vm_address_t start,
1915 	mach_vm_size_t size __unused)
1916 {
1917 	return test_protection_pair_common(
1918 		checker_list, start, VM_PROT_READ, VM_PROT_WRITE);
1919 }
1920 
1921 static test_result_t
test_protection_pair_r00_rw0(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size __unused)1922 test_protection_pair_r00_rw0(
1923 	checker_list_t *checker_list,
1924 	mach_vm_address_t start,
1925 	mach_vm_size_t size __unused)
1926 {
1927 	return test_protection_pair_common(
1928 		checker_list, start, VM_PROT_READ, VM_PROT_READ | VM_PROT_WRITE);
1929 }
1930 
1931 static test_result_t
test_protection_pair_0w0_000(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size __unused)1932 test_protection_pair_0w0_000(
1933 	checker_list_t *checker_list,
1934 	mach_vm_address_t start,
1935 	mach_vm_size_t size __unused)
1936 {
1937 	return test_protection_pair_common(
1938 		checker_list, start, VM_PROT_WRITE, VM_PROT_NONE);
1939 }
1940 
1941 static test_result_t
test_protection_pair_0w0_r00(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size __unused)1942 test_protection_pair_0w0_r00(
1943 	checker_list_t *checker_list,
1944 	mach_vm_address_t start,
1945 	mach_vm_size_t size __unused)
1946 {
1947 	return test_protection_pair_common(
1948 		checker_list, start, VM_PROT_WRITE, VM_PROT_READ);
1949 }
1950 
1951 static test_result_t
test_protection_pair_0w0_0w0(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size __unused)1952 test_protection_pair_0w0_0w0(
1953 	checker_list_t *checker_list,
1954 	mach_vm_address_t start,
1955 	mach_vm_size_t size __unused)
1956 {
1957 	return test_protection_pair_common(
1958 		checker_list, start, VM_PROT_WRITE, VM_PROT_WRITE);
1959 }
1960 
1961 static test_result_t
test_protection_pair_0w0_rw0(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size __unused)1962 test_protection_pair_0w0_rw0(
1963 	checker_list_t *checker_list,
1964 	mach_vm_address_t start,
1965 	mach_vm_size_t size __unused)
1966 {
1967 	return test_protection_pair_common(
1968 		checker_list, start, VM_PROT_WRITE, VM_PROT_READ | VM_PROT_WRITE);
1969 }
1970 
1971 static test_result_t
test_protection_pair_rw0_000(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size __unused)1972 test_protection_pair_rw0_000(
1973 	checker_list_t *checker_list,
1974 	mach_vm_address_t start,
1975 	mach_vm_size_t size __unused)
1976 {
1977 	return test_protection_pair_common(
1978 		checker_list, start, VM_PROT_READ | VM_PROT_WRITE, VM_PROT_NONE);
1979 }
1980 
1981 static test_result_t
test_protection_pair_rw0_r00(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size __unused)1982 test_protection_pair_rw0_r00(
1983 	checker_list_t *checker_list,
1984 	mach_vm_address_t start,
1985 	mach_vm_size_t size __unused)
1986 {
1987 	return test_protection_pair_common(
1988 		checker_list, start, VM_PROT_READ | VM_PROT_WRITE, VM_PROT_READ);
1989 }
1990 
1991 static test_result_t
test_protection_pair_rw0_0w0(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size __unused)1992 test_protection_pair_rw0_0w0(
1993 	checker_list_t *checker_list,
1994 	mach_vm_address_t start,
1995 	mach_vm_size_t size __unused)
1996 {
1997 	return test_protection_pair_common(
1998 		checker_list, start, VM_PROT_READ | VM_PROT_WRITE, VM_PROT_WRITE);
1999 }
2000 
2001 static test_result_t
test_protection_pair_rw0_rw0(checker_list_t * checker_list,mach_vm_address_t start,mach_vm_size_t size __unused)2002 test_protection_pair_rw0_rw0(
2003 	checker_list_t *checker_list,
2004 	mach_vm_address_t start,
2005 	mach_vm_size_t size __unused)
2006 {
2007 	return test_protection_pair_common(
2008 		checker_list, start, VM_PROT_READ | VM_PROT_WRITE, VM_PROT_READ | VM_PROT_WRITE);
2009 }
2010 
2011 
2012 T_DECL(test_vm_configurator,
2013     "spot-check VM states generated by vm configurator")
2014 {
2015 	vm_tests_t tests = {
2016 		.single_entry_1 = test_single_entry_1,
2017 		.single_entry_2 = test_single_entry_2,
2018 		.single_entry_3 = test_single_entry_3,
2019 		.single_entry_4 = test_single_entry_4,
2020 
2021 		.multiple_entries_1 = test_multiple_entries_1,
2022 		.multiple_entries_2 = test_multiple_entries_2,
2023 		.multiple_entries_3 = test_multiple_entries_3,
2024 		.multiple_entries_4 = test_multiple_entries_4,
2025 		.multiple_entries_5 = test_multiple_entries_5,
2026 		.multiple_entries_6 = test_multiple_entries_6,
2027 
2028 		.some_holes_1 = test_some_holes_1,
2029 		.some_holes_2 = test_some_holes_2,
2030 		.some_holes_3 = test_some_holes_3,
2031 		.some_holes_4 = test_some_holes_4,
2032 		.some_holes_5 = test_some_holes_5,
2033 		.some_holes_6 = test_some_holes_6,
2034 		.some_holes_7 = test_some_holes_7,
2035 		.some_holes_8 = test_some_holes_8,
2036 		.some_holes_9 = test_some_holes_9,
2037 		.some_holes_10 = test_some_holes_10,
2038 		.some_holes_11 = test_some_holes_11,
2039 		.some_holes_12 = test_some_holes_12,
2040 
2041 		.all_holes_1 = test_all_holes_1,
2042 		.all_holes_2 = test_all_holes_2,
2043 		.all_holes_3 = test_all_holes_3,
2044 		.all_holes_4 = test_all_holes_4,
2045 
2046 		.null_entry        = test_null_entry,
2047 		.nonresident_entry = test_nonresident_entry,
2048 		.resident_entry    = test_resident_entry,
2049 
2050 		.shared_entry               = test_shared_entry,
2051 		.shared_entry_discontiguous = test_shared_entry_discontiguous,
2052 		.shared_entry_partial       = test_shared_entry_partial,
2053 		.shared_entry_pairs         = test_shared_entry_pairs,
2054 		.shared_entry_x1000         = test_shared_entry_x1000,
2055 
2056 		.cow_entry = test_cow_entry,
2057 		.cow_unreferenced = test_cow_unreferenced,
2058 		.cow_nocow = test_cow_nocow,
2059 		.nocow_cow = test_nocow_cow,
2060 		.cow_unreadable = test_cow_unreadable,
2061 		.cow_unwriteable = test_cow_unwriteable,
2062 
2063 		.permanent_entry = test_permanent_entry,
2064 		.permanent_before_permanent = test_permanent_before_permanent,
2065 		.permanent_before_allocation = test_permanent_before_allocation,
2066 		.permanent_before_allocation_2 = test_permanent_before_allocation_2,
2067 		.permanent_before_hole = test_permanent_before_hole,
2068 		.permanent_after_allocation = test_permanent_after_allocation,
2069 		.permanent_after_hole = test_permanent_after_hole,
2070 
2071 		.single_submap_single_entry = test_single_submap_single_entry,
2072 		.single_submap_single_entry_first_pages = test_single_submap_single_entry_first_pages,
2073 		.single_submap_single_entry_last_pages = test_single_submap_single_entry_last_pages,
2074 		.single_submap_single_entry_middle_pages = test_single_submap_single_entry_middle_pages,
2075 		.single_submap_oversize_entry_at_start = test_single_submap_oversize_entry_at_start,
2076 		.single_submap_oversize_entry_at_end = test_single_submap_oversize_entry_at_end,
2077 		.single_submap_oversize_entry_at_both = test_single_submap_oversize_entry_at_both,
2078 
2079 		.submap_before_allocation = test_submap_before_allocation,
2080 		.submap_after_allocation = test_submap_after_allocation,
2081 		.submap_before_hole = test_submap_before_hole,
2082 		.submap_after_hole = test_submap_after_hole,
2083 		.submap_allocation_submap_one_entry = test_submap_allocation_submap_one_entry,
2084 		.submap_allocation_submap_two_entries = test_submap_allocation_submap_two_entries,
2085 		.submap_allocation_submap_three_entries = test_submap_allocation_submap_three_entries,
2086 
2087 		.submap_before_allocation_ro = test_submap_before_allocation_ro,
2088 		.submap_after_allocation_ro = test_submap_after_allocation_ro,
2089 		.submap_before_hole_ro = test_submap_before_hole_ro,
2090 		.submap_after_hole_ro = test_submap_after_hole_ro,
2091 		.submap_allocation_submap_one_entry_ro = test_submap_allocation_submap_one_entry_ro,
2092 		.submap_allocation_submap_two_entries_ro = test_submap_allocation_submap_two_entries_ro,
2093 		.submap_allocation_submap_three_entries_ro = test_submap_allocation_submap_three_entries_ro,
2094 
2095 		.protection_single_000_000 = test_protection_single_000_000,
2096 		.protection_single_000_r00 = test_protection_single_000_r00,
2097 		.protection_single_000_0w0 = test_protection_single_000_0w0,
2098 		.protection_single_000_rw0 = test_protection_single_000_rw0,
2099 		.protection_single_r00_r00 = test_protection_single_r00_r00,
2100 		.protection_single_r00_rw0 = test_protection_single_r00_rw0,
2101 		.protection_single_0w0_0w0 = test_protection_single_0w0_0w0,
2102 		.protection_single_0w0_rw0 = test_protection_single_0w0_rw0,
2103 		.protection_single_rw0_rw0 = test_protection_single_rw0_rw0,
2104 
2105 		.protection_pairs_000_000 = test_protection_pair_000_000,
2106 		.protection_pairs_000_r00 = test_protection_pair_000_r00,
2107 		.protection_pairs_000_0w0 = test_protection_pair_000_0w0,
2108 		.protection_pairs_000_rw0 = test_protection_pair_000_rw0,
2109 		.protection_pairs_r00_000 = test_protection_pair_r00_000,
2110 		.protection_pairs_r00_r00 = test_protection_pair_r00_r00,
2111 		.protection_pairs_r00_0w0 = test_protection_pair_r00_0w0,
2112 		.protection_pairs_r00_rw0 = test_protection_pair_r00_rw0,
2113 		.protection_pairs_0w0_000 = test_protection_pair_0w0_000,
2114 		.protection_pairs_0w0_r00 = test_protection_pair_0w0_r00,
2115 		.protection_pairs_0w0_0w0 = test_protection_pair_0w0_0w0,
2116 		.protection_pairs_0w0_rw0 = test_protection_pair_0w0_rw0,
2117 		.protection_pairs_rw0_000 = test_protection_pair_rw0_000,
2118 		.protection_pairs_rw0_r00 = test_protection_pair_rw0_r00,
2119 		.protection_pairs_rw0_0w0 = test_protection_pair_rw0_0w0,
2120 		.protection_pairs_rw0_rw0 = test_protection_pair_rw0_rw0,
2121 	};
2122 
2123 	run_vm_tests("test_vm_configurator", __FILE__, &tests, argc, argv);
2124 }
2125