xref: /xnu-11215.61.5/tests/ipc/hardened_exceptions.c (revision 4f1223e81cd707a65cc109d0b8ad6653699da3c4)
1*4f1223e8SApple OSS Distributions #include "exc_helpers.h"
2*4f1223e8SApple OSS Distributions #include <darwintest.h>
3*4f1223e8SApple OSS Distributions 
4*4f1223e8SApple OSS Distributions #include <mach/mach_init.h>
5*4f1223e8SApple OSS Distributions #include <mach/mach_port.h>
6*4f1223e8SApple OSS Distributions #include <pthread/private.h>
7*4f1223e8SApple OSS Distributions #include <pthread.h>
8*4f1223e8SApple OSS Distributions #include <sys/sysctl.h>
9*4f1223e8SApple OSS Distributions #include <mach/task.h>
10*4f1223e8SApple OSS Distributions #include <mach/thread_status.h>
11*4f1223e8SApple OSS Distributions #include <ptrauth.h>
12*4f1223e8SApple OSS Distributions #include <stdbool.h>
13*4f1223e8SApple OSS Distributions #include <stdlib.h>
14*4f1223e8SApple OSS Distributions #include <unistd.h>
15*4f1223e8SApple OSS Distributions #include <mach/mach.h>
16*4f1223e8SApple OSS Distributions #include <mach/exception.h>
17*4f1223e8SApple OSS Distributions #include <mach/thread_status.h>
18*4f1223e8SApple OSS Distributions #include <sys/types.h>
19*4f1223e8SApple OSS Distributions #include <sys/sysctl.h>
20*4f1223e8SApple OSS Distributions #include <sys/code_signing.h>
21*4f1223e8SApple OSS Distributions #include <TargetConditionals.h>
22*4f1223e8SApple OSS Distributions #include <mach/semaphore.h>
23*4f1223e8SApple OSS Distributions 
24*4f1223e8SApple OSS Distributions #if __arm64__
25*4f1223e8SApple OSS Distributions #define EXCEPTION_THREAD_STATE          ARM_THREAD_STATE64
26*4f1223e8SApple OSS Distributions #define EXCEPTION_THREAD_STATE_COUNT    ARM_THREAD_STATE64_COUNT
27*4f1223e8SApple OSS Distributions #elif __x86_64__
28*4f1223e8SApple OSS Distributions #define EXCEPTION_THREAD_STATE          x86_THREAD_STATE
29*4f1223e8SApple OSS Distributions #define EXCEPTION_THREAD_STATE_COUNT    x86_THREAD_STATE_COUNT
30*4f1223e8SApple OSS Distributions #else
31*4f1223e8SApple OSS Distributions #error Unsupported architecture
32*4f1223e8SApple OSS Distributions #endif
33*4f1223e8SApple OSS Distributions 
34*4f1223e8SApple OSS Distributions T_GLOBAL_META(
35*4f1223e8SApple OSS Distributions 	T_META_NAMESPACE("xnu.ipc"),
36*4f1223e8SApple OSS Distributions 	T_META_RADAR_COMPONENT_NAME("xnu"),
37*4f1223e8SApple OSS Distributions 	T_META_RADAR_COMPONENT_VERSION("IPC"),
38*4f1223e8SApple OSS Distributions 	T_META_RUN_CONCURRENTLY(true));
39*4f1223e8SApple OSS Distributions 
40*4f1223e8SApple OSS Distributions struct mach_exception_options {
41*4f1223e8SApple OSS Distributions 	mach_port_t exc_port;
42*4f1223e8SApple OSS Distributions 	exception_mask_t exceptions_allowed;
43*4f1223e8SApple OSS Distributions 	exception_behavior_t behaviors_allowed;
44*4f1223e8SApple OSS Distributions 	thread_state_flavor_t flavors_allowed;
45*4f1223e8SApple OSS Distributions };
46*4f1223e8SApple OSS Distributions 
47*4f1223e8SApple OSS Distributions #if __arm64__
48*4f1223e8SApple OSS Distributions static void
bad_access_func(void)49*4f1223e8SApple OSS Distributions bad_access_func(void)
50*4f1223e8SApple OSS Distributions {
51*4f1223e8SApple OSS Distributions 	T_QUIET; T_LOG("Crashing");
52*4f1223e8SApple OSS Distributions 	*(void *volatile *)5 = 0;
53*4f1223e8SApple OSS Distributions 	T_QUIET; T_LOG("Recoverd!");
54*4f1223e8SApple OSS Distributions 	return;
55*4f1223e8SApple OSS Distributions }
56*4f1223e8SApple OSS Distributions #endif /* __arm64__ */
57*4f1223e8SApple OSS Distributions 
58*4f1223e8SApple OSS Distributions static int num_exceptions = 0;
59*4f1223e8SApple OSS Distributions 
60*4f1223e8SApple OSS Distributions static uint32_t signing_key = (uint32_t)(0xa8000000 & 0xff000000);
61*4f1223e8SApple OSS Distributions static size_t
exc_handler_state_identity_protected(task_id_token_t token,uint64_t thread_id,exception_type_t type,__unused exception_data_t codes,thread_state_t in_state,mach_msg_type_number_t in_state_count,thread_state_t out_state,mach_msg_type_number_t * out_state_count)62*4f1223e8SApple OSS Distributions exc_handler_state_identity_protected(
63*4f1223e8SApple OSS Distributions 	task_id_token_t token,
64*4f1223e8SApple OSS Distributions 	uint64_t thread_id,
65*4f1223e8SApple OSS Distributions 	exception_type_t type,
66*4f1223e8SApple OSS Distributions 	__unused exception_data_t codes,
67*4f1223e8SApple OSS Distributions 	thread_state_t in_state,
68*4f1223e8SApple OSS Distributions 	mach_msg_type_number_t in_state_count,
69*4f1223e8SApple OSS Distributions 	thread_state_t out_state,
70*4f1223e8SApple OSS Distributions 	mach_msg_type_number_t *out_state_count)
71*4f1223e8SApple OSS Distributions {
72*4f1223e8SApple OSS Distributions 	mach_port_t port1, port2;
73*4f1223e8SApple OSS Distributions 	#pragma unused(port1)
74*4f1223e8SApple OSS Distributions 	#pragma unused(port2)
75*4f1223e8SApple OSS Distributions 	#pragma unused(token)
76*4f1223e8SApple OSS Distributions 	#pragma unused(thread_id)
77*4f1223e8SApple OSS Distributions 	#pragma unused(type)
78*4f1223e8SApple OSS Distributions 	#pragma unused(in_state)
79*4f1223e8SApple OSS Distributions 	#pragma unused(in_state_count)
80*4f1223e8SApple OSS Distributions 	#pragma unused(out_state)
81*4f1223e8SApple OSS Distributions 	#pragma unused(out_state_count)
82*4f1223e8SApple OSS Distributions 	*out_state_count = in_state_count;
83*4f1223e8SApple OSS Distributions 	T_LOG("Got protected exception!");
84*4f1223e8SApple OSS Distributions 	num_exceptions++;
85*4f1223e8SApple OSS Distributions #if __arm64__
86*4f1223e8SApple OSS Distributions 	arm_thread_state64_t *state = (arm_thread_state64_t*)(void *)out_state;
87*4f1223e8SApple OSS Distributions 	void *func_pc = (void *)arm_thread_state64_get_pc(*state);
88*4f1223e8SApple OSS Distributions 
89*4f1223e8SApple OSS Distributions 	/* Sign a PC which skips over the faulting instruction */
90*4f1223e8SApple OSS Distributions 	func_pc = ptrauth_strip(func_pc, ptrauth_key_function_pointer);
91*4f1223e8SApple OSS Distributions 	func_pc += 4;
92*4f1223e8SApple OSS Distributions 	uint64_t pc_discriminator = ptrauth_blend_discriminator((void *)(unsigned long)signing_key, ptrauth_string_discriminator("pc"));
93*4f1223e8SApple OSS Distributions 	func_pc = ptrauth_sign_unauthenticated(func_pc, ptrauth_key_function_pointer, pc_discriminator);
94*4f1223e8SApple OSS Distributions 
95*4f1223e8SApple OSS Distributions 	// Set/Sign the PC of the excepting thread
96*4f1223e8SApple OSS Distributions 	T_LOG("userspace discriminator=%llu\n", pc_discriminator);
97*4f1223e8SApple OSS Distributions 	arm_thread_state64_set_pc_presigned_fptr(*state, func_pc);
98*4f1223e8SApple OSS Distributions 
99*4f1223e8SApple OSS Distributions 	/* Corrupting the thread state should not crash as only the PC is accepted in hardened exceptions */
100*4f1223e8SApple OSS Distributions 	arm_thread_state64_set_lr_presigned_fptr(*state, func_pc);
101*4f1223e8SApple OSS Distributions 	arm_thread_state64_set_sp(*state, 0);
102*4f1223e8SApple OSS Distributions 	arm_thread_state64_set_fp(*state, 0);
103*4f1223e8SApple OSS Distributions 
104*4f1223e8SApple OSS Distributions #endif /* __arm64__ */
105*4f1223e8SApple OSS Distributions 
106*4f1223e8SApple OSS Distributions 	return KERN_SUCCESS;
107*4f1223e8SApple OSS Distributions }
108*4f1223e8SApple OSS Distributions 
109*4f1223e8SApple OSS Distributions static void
thread_register_handler(mach_port_t exc_port,const struct mach_exception_options meo)110*4f1223e8SApple OSS Distributions thread_register_handler(mach_port_t exc_port,
111*4f1223e8SApple OSS Distributions     const struct mach_exception_options meo)
112*4f1223e8SApple OSS Distributions {
113*4f1223e8SApple OSS Distributions 	kern_return_t kr = thread_adopt_exception_handler(
114*4f1223e8SApple OSS Distributions 		mach_thread_self(), exc_port, meo.exceptions_allowed,
115*4f1223e8SApple OSS Distributions 		meo.behaviors_allowed, meo.flavors_allowed);
116*4f1223e8SApple OSS Distributions 
117*4f1223e8SApple OSS Distributions 	T_ASSERT_MACH_SUCCESS(kr, "thread register handler");
118*4f1223e8SApple OSS Distributions }
119*4f1223e8SApple OSS Distributions 
120*4f1223e8SApple OSS Distributions static mach_port_t
create_hardened_exception_port(const struct mach_exception_options meo,uint32_t signing_key_local)121*4f1223e8SApple OSS Distributions create_hardened_exception_port(const struct mach_exception_options meo,
122*4f1223e8SApple OSS Distributions     uint32_t signing_key_local)
123*4f1223e8SApple OSS Distributions {
124*4f1223e8SApple OSS Distributions #if !__arm64__
125*4f1223e8SApple OSS Distributions 	T_SKIP("Hardened exceptions not supported on !arm64");
126*4f1223e8SApple OSS Distributions 	return MACH_PORT_NULL;
127*4f1223e8SApple OSS Distributions #else /* !__arm64__ */
128*4f1223e8SApple OSS Distributions 	kern_return_t kr;
129*4f1223e8SApple OSS Distributions 	mach_port_t exc_port;
130*4f1223e8SApple OSS Distributions 	mach_port_options_t opts = {
131*4f1223e8SApple OSS Distributions 		.flags = MPO_INSERT_SEND_RIGHT | MPO_EXCEPTION_PORT,
132*4f1223e8SApple OSS Distributions 	};
133*4f1223e8SApple OSS Distributions 
134*4f1223e8SApple OSS Distributions 	kr = mach_port_construct(mach_task_self(), &opts, 0ull, &exc_port);
135*4f1223e8SApple OSS Distributions 	T_ASSERT_MACH_SUCCESS(kr, "constructing mach port");
136*4f1223e8SApple OSS Distributions 
137*4f1223e8SApple OSS Distributions 	T_LOG("register with pc_signing_key=0x%x\n", signing_key_local);
138*4f1223e8SApple OSS Distributions 	kr = task_register_hardened_exception_handler(current_task(),
139*4f1223e8SApple OSS Distributions 	    signing_key_local, meo.exceptions_allowed,
140*4f1223e8SApple OSS Distributions 	    meo.behaviors_allowed, meo.flavors_allowed, exc_port);
141*4f1223e8SApple OSS Distributions 	T_ASSERT_MACH_SUCCESS(kr, "registering an exception handler port");
142*4f1223e8SApple OSS Distributions 	T_ASSERT_NE_UINT(exc_port, 0, "new exception port not null");
143*4f1223e8SApple OSS Distributions 
144*4f1223e8SApple OSS Distributions 	return exc_port;
145*4f1223e8SApple OSS Distributions #endif /* !__arm64__ */
146*4f1223e8SApple OSS Distributions }
147*4f1223e8SApple OSS Distributions 
148*4f1223e8SApple OSS Distributions T_DECL(hardened_exceptions_default,
149*4f1223e8SApple OSS Distributions     "Test creating and using hardened exception ports") {
150*4f1223e8SApple OSS Distributions #if !__arm64__
151*4f1223e8SApple OSS Distributions 	T_SKIP("Hardened exceptions not supported on !arm64");
152*4f1223e8SApple OSS Distributions #else /* !__arm64__ */
153*4f1223e8SApple OSS Distributions 	struct mach_exception_options meo;
154*4f1223e8SApple OSS Distributions 	meo.exceptions_allowed = EXC_MASK_BAD_ACCESS;
155*4f1223e8SApple OSS Distributions 	meo.behaviors_allowed = EXCEPTION_STATE_IDENTITY_PROTECTED | MACH_EXCEPTION_CODES;
156*4f1223e8SApple OSS Distributions 	meo.flavors_allowed = ARM_THREAD_STATE64;
157*4f1223e8SApple OSS Distributions 
158*4f1223e8SApple OSS Distributions 	mach_port_t exc_port = create_hardened_exception_port(meo, signing_key);
159*4f1223e8SApple OSS Distributions 
160*4f1223e8SApple OSS Distributions 	thread_register_handler(exc_port, meo);
161*4f1223e8SApple OSS Distributions 
162*4f1223e8SApple OSS Distributions 	run_exception_handler_behavior64(exc_port, NULL,
163*4f1223e8SApple OSS Distributions 	    (void*)exc_handler_state_identity_protected,
164*4f1223e8SApple OSS Distributions 	    EXCEPTION_STATE_IDENTITY_PROTECTED | MACH_EXCEPTION_CODES, true);
165*4f1223e8SApple OSS Distributions 	bad_access_func();
166*4f1223e8SApple OSS Distributions 
167*4f1223e8SApple OSS Distributions 	printf("Successfully recovered from the exception!\n");
168*4f1223e8SApple OSS Distributions #endif /* !__arm64__ */
169*4f1223e8SApple OSS Distributions }
170*4f1223e8SApple OSS Distributions 
171*4f1223e8SApple OSS Distributions extern char *__progname;
172*4f1223e8SApple OSS Distributions 
173*4f1223e8SApple OSS Distributions T_DECL(entitled_process_exceptions_disallowed,
174*4f1223e8SApple OSS Distributions     "Test that when you have the special entitlement you may not use the hardened exception flow, unless you have debugger entitlements",
175*4f1223e8SApple OSS Distributions     T_META_IGNORECRASHES("*hardened_exceptions_entitled")) {
176*4f1223e8SApple OSS Distributions #if !__arm64__
177*4f1223e8SApple OSS Distributions 	T_SKIP("Hardened exceptions not supported on !arm64");
178*4f1223e8SApple OSS Distributions #else /* !__arm64__ */
179*4f1223e8SApple OSS Distributions 
180*4f1223e8SApple OSS Distributions 	bool entitled = strstr(__progname, "entitled") != NULL;
181*4f1223e8SApple OSS Distributions 	bool debugger = strstr(__progname, "debugger") != NULL;
182*4f1223e8SApple OSS Distributions 	/* thread_set_exception_ports as a hardened binary should fail */
183*4f1223e8SApple OSS Distributions 	kern_return_t kr = thread_set_exception_ports(
184*4f1223e8SApple OSS Distributions 		mach_thread_self(),
185*4f1223e8SApple OSS Distributions 		EXC_MASK_ALL,
186*4f1223e8SApple OSS Distributions 		MACH_PORT_NULL,
187*4f1223e8SApple OSS Distributions 		(exception_behavior_t)((unsigned int)EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES),
188*4f1223e8SApple OSS Distributions 		EXCEPTION_THREAD_STATE);
189*4f1223e8SApple OSS Distributions 
190*4f1223e8SApple OSS Distributions 	if (!entitled && !debugger) {
191*4f1223e8SApple OSS Distributions 		T_ASSERT_MACH_SUCCESS(kr, "unentitled works normally");
192*4f1223e8SApple OSS Distributions 	} else if (entitled && !debugger) {
193*4f1223e8SApple OSS Distributions 		T_FAIL("We should have already crashed due to hardening entitlement");
194*4f1223e8SApple OSS Distributions 	} else if (entitled && debugger) {
195*4f1223e8SApple OSS Distributions 		T_ASSERT_MACH_SUCCESS(kr, "debugger entitlement works normally");
196*4f1223e8SApple OSS Distributions 	} else {
197*4f1223e8SApple OSS Distributions 		T_FAIL("invalid configuration");
198*4f1223e8SApple OSS Distributions 	}
199*4f1223e8SApple OSS Distributions #endif /* !__arm64__ */
200*4f1223e8SApple OSS Distributions }
201