xref: /xnu-12377.61.12/tests/exc_guard_helper_test.c (revision 4d495c6e23c53686cf65f45067f79024cf5dcee8)
1*4d495c6eSApple OSS Distributions /*
2*4d495c6eSApple OSS Distributions  * Copyright (c) 2024 Apple Inc. All rights reserved.
3*4d495c6eSApple OSS Distributions  *
4*4d495c6eSApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5*4d495c6eSApple OSS Distributions  *
6*4d495c6eSApple OSS Distributions  * This file contains Original Code and/or Modifications of Original Code
7*4d495c6eSApple OSS Distributions  * as defined in and that are subject to the Apple Public Source License
8*4d495c6eSApple OSS Distributions  * Version 2.0 (the 'License'). You may not use this file except in
9*4d495c6eSApple OSS Distributions  * compliance with the License. The rights granted to you under the License
10*4d495c6eSApple OSS Distributions  * may not be used to create, or enable the creation or redistribution of,
11*4d495c6eSApple OSS Distributions  * unlawful or unlicensed copies of an Apple operating system, or to
12*4d495c6eSApple OSS Distributions  * circumvent, violate, or enable the circumvention or violation of, any
13*4d495c6eSApple OSS Distributions  * terms of an Apple operating system software license agreement.
14*4d495c6eSApple OSS Distributions  *
15*4d495c6eSApple OSS Distributions  * Please obtain a copy of the License at
16*4d495c6eSApple OSS Distributions  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17*4d495c6eSApple OSS Distributions  *
18*4d495c6eSApple OSS Distributions  * The Original Code and all software distributed under the License are
19*4d495c6eSApple OSS Distributions  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20*4d495c6eSApple OSS Distributions  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21*4d495c6eSApple OSS Distributions  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22*4d495c6eSApple OSS Distributions  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23*4d495c6eSApple OSS Distributions  * Please see the License for the specific language governing rights and
24*4d495c6eSApple OSS Distributions  * limitations under the License.
25*4d495c6eSApple OSS Distributions  *
26*4d495c6eSApple OSS Distributions  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27*4d495c6eSApple OSS Distributions  */
28*4d495c6eSApple OSS Distributions 
29*4d495c6eSApple OSS Distributions /*
30*4d495c6eSApple OSS Distributions  * exc_guard_helper_test.c
31*4d495c6eSApple OSS Distributions  *
32*4d495c6eSApple OSS Distributions  * Test the testing helper functions in exc_guard_helper.h.
33*4d495c6eSApple OSS Distributions  */
34*4d495c6eSApple OSS Distributions 
35*4d495c6eSApple OSS Distributions #include "exc_guard_helper.h"
36*4d495c6eSApple OSS Distributions 
37*4d495c6eSApple OSS Distributions #include <darwintest.h>
38*4d495c6eSApple OSS Distributions #include <sys/types.h>
39*4d495c6eSApple OSS Distributions #include <sys/sysctl.h>
40*4d495c6eSApple OSS Distributions #include <mach/mach.h>
41*4d495c6eSApple OSS Distributions #include <mach/mach_vm.h>
42*4d495c6eSApple OSS Distributions #include <mach/task_info.h>
43*4d495c6eSApple OSS Distributions #include "test_utils.h"
44*4d495c6eSApple OSS Distributions 
45*4d495c6eSApple OSS Distributions T_GLOBAL_META(
46*4d495c6eSApple OSS Distributions 	T_META_NAMESPACE("xnu"),
47*4d495c6eSApple OSS Distributions 	T_META_RADAR_COMPONENT_NAME("xnu"),
48*4d495c6eSApple OSS Distributions 	T_META_RADAR_COMPONENT_VERSION("vm"),
49*4d495c6eSApple OSS Distributions 	T_META_RUN_CONCURRENTLY(true),
50*4d495c6eSApple OSS Distributions 	T_META_ALL_VALID_ARCHS(true)
51*4d495c6eSApple OSS Distributions 	);
52*4d495c6eSApple OSS Distributions 
53*4d495c6eSApple OSS Distributions /* Convenience macro for compile-time array size */
54*4d495c6eSApple OSS Distributions #define countof(array)                                                  \
55*4d495c6eSApple OSS Distributions 	_Pragma("clang diagnostic push")                                \
56*4d495c6eSApple OSS Distributions 	_Pragma("clang diagnostic error \"-Wsizeof-pointer-div\"")      \
57*4d495c6eSApple OSS Distributions 	(sizeof(array)/sizeof((array)[0]))                              \
58*4d495c6eSApple OSS Distributions 	_Pragma("clang diagnostic pop")
59*4d495c6eSApple OSS Distributions 
60*4d495c6eSApple OSS Distributions /*
61*4d495c6eSApple OSS Distributions  * Return true if [query_start, query_start + query_size) is unallocated memory.
62*4d495c6eSApple OSS Distributions  */
63*4d495c6eSApple OSS Distributions static bool
is_hole(mach_vm_address_t query_start,mach_vm_size_t query_size)64*4d495c6eSApple OSS Distributions is_hole(mach_vm_address_t query_start, mach_vm_size_t query_size)
65*4d495c6eSApple OSS Distributions {
66*4d495c6eSApple OSS Distributions 	mach_vm_address_t entry_start = query_start;
67*4d495c6eSApple OSS Distributions 	mach_vm_size_t entry_size;
68*4d495c6eSApple OSS Distributions 	vm_region_submap_info_data_64_t info;
69*4d495c6eSApple OSS Distributions 	uint32_t depth = 0;
70*4d495c6eSApple OSS Distributions 	mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64;
71*4d495c6eSApple OSS Distributions 	kern_return_t kr = mach_vm_region_recurse(mach_task_self(),
72*4d495c6eSApple OSS Distributions 	    &entry_start, &entry_size, &depth,
73*4d495c6eSApple OSS Distributions 	    (vm_region_recurse_info_t)&info, &count);
74*4d495c6eSApple OSS Distributions 
75*4d495c6eSApple OSS Distributions 	if (kr == KERN_INVALID_ADDRESS) {
76*4d495c6eSApple OSS Distributions 		/*
77*4d495c6eSApple OSS Distributions 		 * query_start is unmapped, and so is everything after it,
78*4d495c6eSApple OSS Distributions 		 * therefore the query range is a hole
79*4d495c6eSApple OSS Distributions 		 */
80*4d495c6eSApple OSS Distributions 		return true;
81*4d495c6eSApple OSS Distributions 	}
82*4d495c6eSApple OSS Distributions 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "vm_region");
83*4d495c6eSApple OSS Distributions 
84*4d495c6eSApple OSS Distributions 	/* this code does not handle submaps */
85*4d495c6eSApple OSS Distributions 	T_QUIET; T_ASSERT_EQ(depth, 0, "submaps unimplemented");
86*4d495c6eSApple OSS Distributions 
87*4d495c6eSApple OSS Distributions 	/*
88*4d495c6eSApple OSS Distributions 	 * entry_start is mapped memory, and either
89*4d495c6eSApple OSS Distributions 	 * (1) entry_start's mapping contains query_start, OR
90*4d495c6eSApple OSS Distributions 	 * (2) query_start is unmapped and entry_start is the next mapped memory
91*4d495c6eSApple OSS Distributions 	 */
92*4d495c6eSApple OSS Distributions 
93*4d495c6eSApple OSS Distributions 	if (entry_start >= query_start + query_size) {
94*4d495c6eSApple OSS Distributions 		/*
95*4d495c6eSApple OSS Distributions 		 * entry_start's mapping does not contain query_start,
96*4d495c6eSApple OSS Distributions 		 * and entry_start's mapping begins after the query range,
97*4d495c6eSApple OSS Distributions 		 * therefore the query range is a hole
98*4d495c6eSApple OSS Distributions 		 */
99*4d495c6eSApple OSS Distributions 		return true;
100*4d495c6eSApple OSS Distributions 	} else {
101*4d495c6eSApple OSS Distributions 		return false;
102*4d495c6eSApple OSS Distributions 	}
103*4d495c6eSApple OSS Distributions }
104*4d495c6eSApple OSS Distributions 
105*4d495c6eSApple OSS Distributions /* Call enable_exc_guard_of_type(), and test its behavior. */
106*4d495c6eSApple OSS Distributions static void
enable_exc_guard_of_type_and_verify(unsigned int guard_type)107*4d495c6eSApple OSS Distributions enable_exc_guard_of_type_and_verify(unsigned int guard_type)
108*4d495c6eSApple OSS Distributions {
109*4d495c6eSApple OSS Distributions 	struct {
110*4d495c6eSApple OSS Distributions 		const char *name;
111*4d495c6eSApple OSS Distributions 		task_exc_guard_behavior_t all_mask;
112*4d495c6eSApple OSS Distributions 		task_exc_guard_behavior_t deliver_mask;
113*4d495c6eSApple OSS Distributions 		task_exc_guard_behavior_t fatal_mask;
114*4d495c6eSApple OSS Distributions 	} guards[] = {
115*4d495c6eSApple OSS Distributions 		[GUARD_TYPE_VIRT_MEMORY] = {
116*4d495c6eSApple OSS Distributions 			.name = "VM",
117*4d495c6eSApple OSS Distributions 			.all_mask = TASK_EXC_GUARD_VM_ALL,
118*4d495c6eSApple OSS Distributions 			.deliver_mask = TASK_EXC_GUARD_VM_DELIVER,
119*4d495c6eSApple OSS Distributions 			.fatal_mask = TASK_EXC_GUARD_VM_FATAL
120*4d495c6eSApple OSS Distributions 		},
121*4d495c6eSApple OSS Distributions 		[GUARD_TYPE_MACH_PORT] = {
122*4d495c6eSApple OSS Distributions 			.name = "Mach port",
123*4d495c6eSApple OSS Distributions 			.all_mask = TASK_EXC_GUARD_MP_ALL,
124*4d495c6eSApple OSS Distributions 			.deliver_mask = TASK_EXC_GUARD_MP_DELIVER,
125*4d495c6eSApple OSS Distributions 			.fatal_mask = TASK_EXC_GUARD_MP_FATAL
126*4d495c6eSApple OSS Distributions 		}
127*4d495c6eSApple OSS Distributions 	};
128*4d495c6eSApple OSS Distributions 
129*4d495c6eSApple OSS Distributions 	kern_return_t kr;
130*4d495c6eSApple OSS Distributions 	task_exc_guard_behavior_t disabling_behavior, old_behavior, new_behavior;
131*4d495c6eSApple OSS Distributions 
132*4d495c6eSApple OSS Distributions 	T_QUIET; T_ASSERT_TRUE(guard_type < countof(guards) && guards[guard_type].name != NULL,
133*4d495c6eSApple OSS Distributions 	    "guard type in enable_exc_guard_of_type_and_verify");
134*4d495c6eSApple OSS Distributions 
135*4d495c6eSApple OSS Distributions 	/* disable guard exceptions of this type, then verify that enable_exc_guard_of_type enables them */
136*4d495c6eSApple OSS Distributions 
137*4d495c6eSApple OSS Distributions 	kr = task_get_exc_guard_behavior(mach_task_self(), &disabling_behavior);
138*4d495c6eSApple OSS Distributions 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "get old behavior");
139*4d495c6eSApple OSS Distributions 	disabling_behavior &= ~guards[guard_type].all_mask;
140*4d495c6eSApple OSS Distributions 	kr = task_set_exc_guard_behavior(mach_task_self(), disabling_behavior);
141*4d495c6eSApple OSS Distributions 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "set empty behavior");
142*4d495c6eSApple OSS Distributions 
143*4d495c6eSApple OSS Distributions 	old_behavior = enable_exc_guard_of_type(guard_type);
144*4d495c6eSApple OSS Distributions 	T_QUIET; T_ASSERT_EQ(old_behavior, disabling_behavior, "enable_exc_guard_of_type return value");
145*4d495c6eSApple OSS Distributions 	T_QUIET; T_ASSERT_FALSE(old_behavior & guards[guard_type].deliver_mask,
146*4d495c6eSApple OSS Distributions 	    "%s guard exceptions must not be enabled", guards[guard_type].name);
147*4d495c6eSApple OSS Distributions 
148*4d495c6eSApple OSS Distributions 	kr = task_get_exc_guard_behavior(mach_task_self(), &new_behavior);
149*4d495c6eSApple OSS Distributions 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "get new behavior");
150*4d495c6eSApple OSS Distributions 	T_ASSERT_TRUE(new_behavior & guards[guard_type].deliver_mask,
151*4d495c6eSApple OSS Distributions 	    "enable_exc_guard_of_type enabled %s guard exceptions", guards[guard_type].name);
152*4d495c6eSApple OSS Distributions 	T_ASSERT_FALSE(new_behavior & guards[guard_type].fatal_mask,
153*4d495c6eSApple OSS Distributions 	    "enable_exc_guard_of_type set %s guard exceptions to non-fatal", guards[guard_type].name);
154*4d495c6eSApple OSS Distributions }
155*4d495c6eSApple OSS Distributions 
156*4d495c6eSApple OSS Distributions 
157*4d495c6eSApple OSS Distributions T_DECL(exc_guard_helper_test_vm,
158*4d495c6eSApple OSS Distributions     "test the test helper function block_raised_exc_guard_of_type with VM guard exceptions")
159*4d495c6eSApple OSS Distributions {
160*4d495c6eSApple OSS Distributions 	if (process_is_translated()) {
161*4d495c6eSApple OSS Distributions 		T_SKIP("VM guard exceptions not supported on Rosetta (rdar://142438840)");
162*4d495c6eSApple OSS Distributions 	}
163*4d495c6eSApple OSS Distributions 
164*4d495c6eSApple OSS Distributions 	kern_return_t kr;
165*4d495c6eSApple OSS Distributions 	exc_guard_helper_info_t exc_info;
166*4d495c6eSApple OSS Distributions 
167*4d495c6eSApple OSS Distributions 	exc_guard_helper_init();
168*4d495c6eSApple OSS Distributions 	enable_exc_guard_of_type_and_verify(GUARD_TYPE_VIRT_MEMORY);
169*4d495c6eSApple OSS Distributions 
170*4d495c6eSApple OSS Distributions 	/*
171*4d495c6eSApple OSS Distributions 	 * Test guard exceptions by deallocating unallocated VM space.
172*4d495c6eSApple OSS Distributions 	 * Problem: Rosetta asynchronously allocates memory in the process
173*4d495c6eSApple OSS Distributions 	 * to store translated instructions. These allocations can land
174*4d495c6eSApple OSS Distributions 	 * inside our unallocated space, disrupting our test and crashing
175*4d495c6eSApple OSS Distributions 	 * after we call vm_deallocate() on space that we thought was empty.
176*4d495c6eSApple OSS Distributions 	 * Solution:
177*4d495c6eSApple OSS Distributions 	 * - use VM_FLAGS_RANDOM_ADDR in the hope of moving our allocation
178*4d495c6eSApple OSS Distributions 	 *   away from VM's ordinary next allocation space
179*4d495c6eSApple OSS Distributions 	 * - try to verify that the unallocated space is empty before
180*4d495c6eSApple OSS Distributions 	 *   calling vm_deallocate, and retry several times if it is not empty
181*4d495c6eSApple OSS Distributions 	 */
182*4d495c6eSApple OSS Distributions 
183*4d495c6eSApple OSS Distributions #define LAST_RETRY 10
184*4d495c6eSApple OSS Distributions 	for (int retry_count = 0; retry_count <= LAST_RETRY; retry_count++) {
185*4d495c6eSApple OSS Distributions 		/* allocate three pages */
186*4d495c6eSApple OSS Distributions 		mach_vm_address_t allocated = 0;
187*4d495c6eSApple OSS Distributions 		kr = mach_vm_allocate(mach_task_self(), &allocated, PAGE_SIZE * 3,
188*4d495c6eSApple OSS Distributions 		    VM_FLAGS_ANYWHERE | VM_FLAGS_RANDOM_ADDR);
189*4d495c6eSApple OSS Distributions 		T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "allocate space");
190*4d495c6eSApple OSS Distributions 
191*4d495c6eSApple OSS Distributions 		/* deallocate the page in the middle; no EXC_GUARD from successful deallocation */
192*4d495c6eSApple OSS Distributions 		if (block_raised_exc_guard_of_type(GUARD_TYPE_VIRT_MEMORY, &exc_info, ^{
193*4d495c6eSApple OSS Distributions 			kern_return_t kr;
194*4d495c6eSApple OSS Distributions 			kr = mach_vm_deallocate(mach_task_self(), allocated + PAGE_SIZE, PAGE_SIZE);
195*4d495c6eSApple OSS Distributions 			T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "create hole");
196*4d495c6eSApple OSS Distributions 		})) {
197*4d495c6eSApple OSS Distributions 			T_FAIL("unexpected guard exception");
198*4d495c6eSApple OSS Distributions 		} else {
199*4d495c6eSApple OSS Distributions 			T_ASSERT_EQ(exc_info.catch_count, 0, "block_raised_exc_guard_of_type(VM) with no exceptions");
200*4d495c6eSApple OSS Distributions 		}
201*4d495c6eSApple OSS Distributions 
202*4d495c6eSApple OSS Distributions 		/* try to deallocate the hole, twice, and detect the guard exceptions */
203*4d495c6eSApple OSS Distributions 		__block bool retry = false;
204*4d495c6eSApple OSS Distributions 		bool caught_exception = block_raised_exc_guard_of_type(GUARD_TYPE_VIRT_MEMORY, &exc_info, ^{
205*4d495c6eSApple OSS Distributions 			kern_return_t kr;
206*4d495c6eSApple OSS Distributions 
207*4d495c6eSApple OSS Distributions 			/* deallocate page-hole-page; EXC_GUARD expected from deallocating a hole */
208*4d495c6eSApple OSS Distributions 			if (!is_hole(allocated + PAGE_SIZE, PAGE_SIZE)) {
209*4d495c6eSApple OSS Distributions 			        retry = true;  /* somebody allocated inside our unallocated space; retry */
210*4d495c6eSApple OSS Distributions 			        return;
211*4d495c6eSApple OSS Distributions 			}
212*4d495c6eSApple OSS Distributions 			kr = mach_vm_deallocate(mach_task_self(), allocated, PAGE_SIZE * 3);
213*4d495c6eSApple OSS Distributions 			T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "vm_deallocate a hole");
214*4d495c6eSApple OSS Distributions 
215*4d495c6eSApple OSS Distributions 			/* deallocate again, now all holes; EXC_GUARD expected from deallocating a hole */
216*4d495c6eSApple OSS Distributions 			if (!is_hole(allocated, PAGE_SIZE * 3)) {
217*4d495c6eSApple OSS Distributions 			        retry = true;  /* somebody allocated inside our unallocated space; retry */
218*4d495c6eSApple OSS Distributions 			        return;
219*4d495c6eSApple OSS Distributions 			}
220*4d495c6eSApple OSS Distributions 			kr = mach_vm_deallocate(mach_task_self(), allocated, PAGE_SIZE * 3);
221*4d495c6eSApple OSS Distributions 			T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "vm_deallocate a hole again");
222*4d495c6eSApple OSS Distributions 
223*4d495c6eSApple OSS Distributions 			if (!is_hole(allocated, PAGE_SIZE * 3)) {
224*4d495c6eSApple OSS Distributions 			        retry = true;  /* somebody allocated inside our unallocated space; retry */
225*4d495c6eSApple OSS Distributions 			        return;
226*4d495c6eSApple OSS Distributions 			}
227*4d495c6eSApple OSS Distributions 		});
228*4d495c6eSApple OSS Distributions 
229*4d495c6eSApple OSS Distributions 		if (retry) {
230*4d495c6eSApple OSS Distributions 			if (retry_count < LAST_RETRY) {
231*4d495c6eSApple OSS Distributions 				T_LOG("unallocated space was found to be allocated, retrying");
232*4d495c6eSApple OSS Distributions 			} else {
233*4d495c6eSApple OSS Distributions 				T_FAIL("intended unallocated space was repeatedly found to be allocated, giving up");
234*4d495c6eSApple OSS Distributions 			}
235*4d495c6eSApple OSS Distributions 		} else if (caught_exception) {
236*4d495c6eSApple OSS Distributions 			/* caught an exception as expected: verify what we caught */
237*4d495c6eSApple OSS Distributions 			T_ASSERT_EQ(exc_info.catch_count, 2, "block_raised_exc_guard_of_type(VM) with 2 exceptions");
238*4d495c6eSApple OSS Distributions 			T_ASSERT_EQ(exc_info.guard_type, GUARD_TYPE_VIRT_MEMORY, "caught exception's type");
239*4d495c6eSApple OSS Distributions 			T_ASSERT_EQ(exc_info.guard_flavor, kGUARD_EXC_DEALLOC_GAP, "caught exception's flavor");
240*4d495c6eSApple OSS Distributions 			T_ASSERT_EQ(exc_info.guard_payload, allocated + PAGE_SIZE, "caught exception's payload");
241*4d495c6eSApple OSS Distributions 			break;  /* done retrying */
242*4d495c6eSApple OSS Distributions 		} else {
243*4d495c6eSApple OSS Distributions 			/* where's the beef? */
244*4d495c6eSApple OSS Distributions 			T_FAIL("no VM guard exception caught");
245*4d495c6eSApple OSS Distributions 			break;  /* done retrying */
246*4d495c6eSApple OSS Distributions 		}
247*4d495c6eSApple OSS Distributions 	}
248*4d495c6eSApple OSS Distributions }
249*4d495c6eSApple OSS Distributions 
250*4d495c6eSApple OSS Distributions 
251*4d495c6eSApple OSS Distributions T_DECL(exc_guard_helper_test_mach_port,
252*4d495c6eSApple OSS Distributions     "test the test helper function block_raised_exc_guard_of_type with Mach port guard exceptions")
253*4d495c6eSApple OSS Distributions {
254*4d495c6eSApple OSS Distributions 	kern_return_t kr;
255*4d495c6eSApple OSS Distributions 	exc_guard_helper_info_t exc_info;
256*4d495c6eSApple OSS Distributions 	mach_port_t port;
257*4d495c6eSApple OSS Distributions 
258*4d495c6eSApple OSS Distributions 	exc_guard_helper_init();
259*4d495c6eSApple OSS Distributions 	enable_exc_guard_of_type_and_verify(GUARD_TYPE_MACH_PORT);
260*4d495c6eSApple OSS Distributions 
261*4d495c6eSApple OSS Distributions 	/*
262*4d495c6eSApple OSS Distributions 	 * Test guard exceptions by overflowing the send right count for a port.
263*4d495c6eSApple OSS Distributions 	 */
264*4d495c6eSApple OSS Distributions 
265*4d495c6eSApple OSS Distributions 	kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port);
266*4d495c6eSApple OSS Distributions 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "new port");
267*4d495c6eSApple OSS Distributions 	kr = mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND);
268*4d495c6eSApple OSS Distributions 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "make send");
269*4d495c6eSApple OSS Distributions 
270*4d495c6eSApple OSS Distributions 	/* add and remove one send right, should succeed */
271*4d495c6eSApple OSS Distributions 	if (block_raised_exc_guard_of_type(GUARD_TYPE_MACH_PORT, &exc_info, ^{
272*4d495c6eSApple OSS Distributions 		kern_return_t kr;
273*4d495c6eSApple OSS Distributions 		kr = mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND, +1);
274*4d495c6eSApple OSS Distributions 		T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "add one send right");
275*4d495c6eSApple OSS Distributions 		kr = mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND, -1);
276*4d495c6eSApple OSS Distributions 		T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "remove one send right");
277*4d495c6eSApple OSS Distributions 	})) {
278*4d495c6eSApple OSS Distributions 		T_FAIL("unexpected guard exception");
279*4d495c6eSApple OSS Distributions 	} else {
280*4d495c6eSApple OSS Distributions 		T_ASSERT_EQ(exc_info.catch_count, 0, "block_raised_exc_guard_of_type(MACH_PORT) with no exceptions");
281*4d495c6eSApple OSS Distributions 	}
282*4d495c6eSApple OSS Distributions 
283*4d495c6eSApple OSS Distributions 	/* try to overflow the port's send right count, twice, and catch the exceptions */
284*4d495c6eSApple OSS Distributions 	bool caught_exception = block_raised_exc_guard_of_type(GUARD_TYPE_MACH_PORT, &exc_info, ^{
285*4d495c6eSApple OSS Distributions 		kern_return_t kr;
286*4d495c6eSApple OSS Distributions 		unsigned expected_error;
287*4d495c6eSApple OSS Distributions 		if (process_is_translated()) {
288*4d495c6eSApple OSS Distributions 		        expected_error = 0x1000013;  /* KERN_UREFS_OVERFLOW plus another bit? */
289*4d495c6eSApple OSS Distributions 		} else {
290*4d495c6eSApple OSS Distributions 		        expected_error = KERN_INVALID_VALUE;
291*4d495c6eSApple OSS Distributions 		}
292*4d495c6eSApple OSS Distributions 		kr = mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND, INT32_MAX);
293*4d495c6eSApple OSS Distributions 		T_QUIET; T_ASSERT_MACH_ERROR(kr, expected_error, "add too many send rights");
294*4d495c6eSApple OSS Distributions 		kr = mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND, INT32_MAX);
295*4d495c6eSApple OSS Distributions 		T_QUIET; T_ASSERT_MACH_ERROR(kr, expected_error, "add too many send rights, again");
296*4d495c6eSApple OSS Distributions 	});
297*4d495c6eSApple OSS Distributions 	if (caught_exception) {
298*4d495c6eSApple OSS Distributions 		/* caught an exception as expected: verify what we caught */
299*4d495c6eSApple OSS Distributions 		T_ASSERT_EQ(exc_info.catch_count, 2, "block_raised_exc_guard_of_type(MACH_PORT) with 2 exceptions");
300*4d495c6eSApple OSS Distributions 		T_ASSERT_EQ(exc_info.guard_type, GUARD_TYPE_MACH_PORT, "caught exception's type");
301*4d495c6eSApple OSS Distributions 		T_ASSERT_EQ(exc_info.guard_flavor, kGUARD_EXC_INVALID_VALUE, "caught exception's flavor");
302*4d495c6eSApple OSS Distributions 		T_ASSERT_EQ(exc_info.guard_target, port, "caught exception's target");
303*4d495c6eSApple OSS Distributions 	} else {
304*4d495c6eSApple OSS Distributions 		/* where's the beef? */
305*4d495c6eSApple OSS Distributions 		T_FAIL("no Mach port guard exception caught");
306*4d495c6eSApple OSS Distributions 	}
307*4d495c6eSApple OSS Distributions }
308