xref: /xnu-10063.121.3/tests/reply_port_defense_client.c (revision 2c2f96dc2b9a4408a43d3150ae9c105355ca3daa)
1*2c2f96dcSApple OSS Distributions #include <mach/kern_return.h>
2*2c2f96dcSApple OSS Distributions #include <stdlib.h>
3*2c2f96dcSApple OSS Distributions #include <stdio.h>
4*2c2f96dcSApple OSS Distributions #include <pthread.h>
5*2c2f96dcSApple OSS Distributions #include <unistd.h>
6*2c2f96dcSApple OSS Distributions #include <mach/mach.h>
7*2c2f96dcSApple OSS Distributions #include <mach/task.h>
8*2c2f96dcSApple OSS Distributions #include <mach/thread_status.h>
9*2c2f96dcSApple OSS Distributions #include <assert.h>
10*2c2f96dcSApple OSS Distributions #include <sys/codesign.h>
11*2c2f96dcSApple OSS Distributions #include <stdbool.h>
12*2c2f96dcSApple OSS Distributions #include "cs_helpers.h"
13*2c2f96dcSApple OSS Distributions 
14*2c2f96dcSApple OSS Distributions #define MAX_TEST_NUM 7
15*2c2f96dcSApple OSS Distributions 
16*2c2f96dcSApple OSS Distributions #if __arm64__
17*2c2f96dcSApple OSS Distributions #define machine_thread_state_t          arm_thread_state64_t
18*2c2f96dcSApple OSS Distributions #define EXCEPTION_THREAD_STATE          ARM_THREAD_STATE64
19*2c2f96dcSApple OSS Distributions #define EXCEPTION_THREAD_STATE_COUNT    ARM_THREAD_STATE64_COUNT
20*2c2f96dcSApple OSS Distributions #elif __x86_64__
21*2c2f96dcSApple OSS Distributions #define machine_thread_state_t          x86_thread_state_t
22*2c2f96dcSApple OSS Distributions #define EXCEPTION_THREAD_STATE          x86_THREAD_STATE
23*2c2f96dcSApple OSS Distributions #define EXCEPTION_THREAD_STATE_COUNT    x86_THREAD_STATE_COUNT
24*2c2f96dcSApple OSS Distributions #else
25*2c2f96dcSApple OSS Distributions #error Unsupported architecture
26*2c2f96dcSApple OSS Distributions #endif
27*2c2f96dcSApple OSS Distributions 
28*2c2f96dcSApple OSS Distributions static mach_port_t
alloc_server_port(void)29*2c2f96dcSApple OSS Distributions alloc_server_port(void)
30*2c2f96dcSApple OSS Distributions {
31*2c2f96dcSApple OSS Distributions 	mach_port_t server_port = MACH_PORT_NULL;
32*2c2f96dcSApple OSS Distributions 	kern_return_t kr;
33*2c2f96dcSApple OSS Distributions 
34*2c2f96dcSApple OSS Distributions 	kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &server_port);
35*2c2f96dcSApple OSS Distributions 	assert(kr == 0);
36*2c2f96dcSApple OSS Distributions 
37*2c2f96dcSApple OSS Distributions 	kr = mach_port_insert_right(mach_task_self(), server_port, server_port, MACH_MSG_TYPE_MAKE_SEND);
38*2c2f96dcSApple OSS Distributions 	assert(kr == 0);
39*2c2f96dcSApple OSS Distributions 
40*2c2f96dcSApple OSS Distributions 	return server_port;
41*2c2f96dcSApple OSS Distributions }
42*2c2f96dcSApple OSS Distributions 
43*2c2f96dcSApple OSS Distributions static mach_port_t
alloc_provisional_reply_port()44*2c2f96dcSApple OSS Distributions alloc_provisional_reply_port()
45*2c2f96dcSApple OSS Distributions {
46*2c2f96dcSApple OSS Distributions 	kern_return_t kr;
47*2c2f96dcSApple OSS Distributions 	mach_port_t reply_port = MACH_PORT_NULL;
48*2c2f96dcSApple OSS Distributions 	mach_port_t task = mach_task_self();
49*2c2f96dcSApple OSS Distributions 
50*2c2f96dcSApple OSS Distributions 	mach_port_options_t opts = {
51*2c2f96dcSApple OSS Distributions 		.flags = MPO_PROVISIONAL_REPLY_PORT | MPO_INSERT_SEND_RIGHT,
52*2c2f96dcSApple OSS Distributions 	};
53*2c2f96dcSApple OSS Distributions 
54*2c2f96dcSApple OSS Distributions 	kr = mach_port_construct(mach_task_self(), &opts, 0, &reply_port);
55*2c2f96dcSApple OSS Distributions 	assert(kr == 0);
56*2c2f96dcSApple OSS Distributions 
57*2c2f96dcSApple OSS Distributions 	return reply_port;
58*2c2f96dcSApple OSS Distributions }
59*2c2f96dcSApple OSS Distributions 
60*2c2f96dcSApple OSS Distributions static mach_port_t
alloc_reply_port()61*2c2f96dcSApple OSS Distributions alloc_reply_port()
62*2c2f96dcSApple OSS Distributions {
63*2c2f96dcSApple OSS Distributions 	kern_return_t kr;
64*2c2f96dcSApple OSS Distributions 	mach_port_t reply_port = MACH_PORT_NULL;
65*2c2f96dcSApple OSS Distributions 	mach_port_t task = mach_task_self();
66*2c2f96dcSApple OSS Distributions 
67*2c2f96dcSApple OSS Distributions 	mach_port_options_t opts = {
68*2c2f96dcSApple OSS Distributions 		.flags = MPO_REPLY_PORT | MPO_INSERT_SEND_RIGHT,
69*2c2f96dcSApple OSS Distributions 	};
70*2c2f96dcSApple OSS Distributions 
71*2c2f96dcSApple OSS Distributions 	kr = mach_port_construct(mach_task_self(), &opts, 0, &reply_port);
72*2c2f96dcSApple OSS Distributions 	assert(kr == 0);
73*2c2f96dcSApple OSS Distributions 
74*2c2f96dcSApple OSS Distributions 	return reply_port;
75*2c2f96dcSApple OSS Distributions }
76*2c2f96dcSApple OSS Distributions 
77*2c2f96dcSApple OSS Distributions /* The rcv right of the port would be marked immovable. */
78*2c2f96dcSApple OSS Distributions static void
test_immovable_receive_right(void)79*2c2f96dcSApple OSS Distributions test_immovable_receive_right(void)
80*2c2f96dcSApple OSS Distributions {
81*2c2f96dcSApple OSS Distributions 	kern_return_t kr;
82*2c2f96dcSApple OSS Distributions 	mach_port_t server_port = MACH_PORT_NULL, reply_port = MACH_PORT_NULL;
83*2c2f96dcSApple OSS Distributions 	struct {
84*2c2f96dcSApple OSS Distributions 		mach_msg_header_t header;
85*2c2f96dcSApple OSS Distributions 		mach_msg_body_t body;
86*2c2f96dcSApple OSS Distributions 		mach_msg_port_descriptor_t desc;
87*2c2f96dcSApple OSS Distributions 	} msg;
88*2c2f96dcSApple OSS Distributions 
89*2c2f96dcSApple OSS Distributions 	server_port = alloc_server_port();
90*2c2f96dcSApple OSS Distributions 	reply_port = alloc_reply_port();
91*2c2f96dcSApple OSS Distributions 
92*2c2f96dcSApple OSS Distributions 	msg.header.msgh_remote_port = server_port;
93*2c2f96dcSApple OSS Distributions 	msg.header.msgh_local_port = MACH_PORT_NULL;
94*2c2f96dcSApple OSS Distributions 	msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0) | MACH_MSGH_BITS_COMPLEX;
95*2c2f96dcSApple OSS Distributions 	msg.header.msgh_size = sizeof msg;
96*2c2f96dcSApple OSS Distributions 
97*2c2f96dcSApple OSS Distributions 	msg.body.msgh_descriptor_count = 1;
98*2c2f96dcSApple OSS Distributions 
99*2c2f96dcSApple OSS Distributions 	msg.desc.name = reply_port;
100*2c2f96dcSApple OSS Distributions 	msg.desc.disposition = MACH_MSG_TYPE_MOVE_RECEIVE;
101*2c2f96dcSApple OSS Distributions 	msg.desc.type = MACH_MSG_PORT_DESCRIPTOR;
102*2c2f96dcSApple OSS Distributions 	kr = mach_msg_send(&msg.header);
103*2c2f96dcSApple OSS Distributions 
104*2c2f96dcSApple OSS Distributions 	printf("[reply_port_defense_client test_immovable_receive_right]: mach_msg2() returned %d\n", kr);
105*2c2f96dcSApple OSS Distributions }
106*2c2f96dcSApple OSS Distributions 
107*2c2f96dcSApple OSS Distributions /* The only way you could create a send once right is when you send the port in local port of a mach msg with MAKE_SEND_ONCE disposition. */
108*2c2f96dcSApple OSS Distributions static void
test_make_send_once_right(void)109*2c2f96dcSApple OSS Distributions test_make_send_once_right(void)
110*2c2f96dcSApple OSS Distributions {
111*2c2f96dcSApple OSS Distributions 	kern_return_t kr;
112*2c2f96dcSApple OSS Distributions 	mach_port_t reply_port = alloc_reply_port();
113*2c2f96dcSApple OSS Distributions 	kr = mach_port_insert_right(mach_task_self(), reply_port, reply_port, MACH_MSG_TYPE_MAKE_SEND_ONCE);
114*2c2f96dcSApple OSS Distributions 	printf("[reply_port_defense_client test_make_send_once_right]: mach_port_insert_right() returned %d\n", kr);
115*2c2f96dcSApple OSS Distributions }
116*2c2f96dcSApple OSS Distributions 
117*2c2f96dcSApple OSS Distributions /* The send right of the port would only used for guarding a name in ipc space, it would not allow to send a message. */
118*2c2f96dcSApple OSS Distributions static void
test_using_send_right(void)119*2c2f96dcSApple OSS Distributions test_using_send_right(void)
120*2c2f96dcSApple OSS Distributions {
121*2c2f96dcSApple OSS Distributions 	kern_return_t kr;
122*2c2f96dcSApple OSS Distributions 	mach_port_t reply_port = alloc_reply_port();
123*2c2f96dcSApple OSS Distributions 	struct {
124*2c2f96dcSApple OSS Distributions 		mach_msg_header_t header;
125*2c2f96dcSApple OSS Distributions 		mach_msg_body_t body;
126*2c2f96dcSApple OSS Distributions 	} msg;
127*2c2f96dcSApple OSS Distributions 
128*2c2f96dcSApple OSS Distributions 	msg.header.msgh_remote_port = reply_port;
129*2c2f96dcSApple OSS Distributions 	msg.header.msgh_local_port = MACH_PORT_NULL;
130*2c2f96dcSApple OSS Distributions 	msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
131*2c2f96dcSApple OSS Distributions 	msg.header.msgh_size = sizeof msg;
132*2c2f96dcSApple OSS Distributions 
133*2c2f96dcSApple OSS Distributions 	kr = mach_msg_send(&msg.header);
134*2c2f96dcSApple OSS Distributions 	printf("[reply_port_defense_client test_using_send_right]: mach_msg2() returned %d\n", kr);
135*2c2f96dcSApple OSS Distributions }
136*2c2f96dcSApple OSS Distributions 
137*2c2f96dcSApple OSS Distributions /* The send right of the port would only used for guarding a name in ipc space, it would not allowed to get moved. */
138*2c2f96dcSApple OSS Distributions static void
test_move_send_right(void)139*2c2f96dcSApple OSS Distributions test_move_send_right(void)
140*2c2f96dcSApple OSS Distributions {
141*2c2f96dcSApple OSS Distributions 	kern_return_t kr;
142*2c2f96dcSApple OSS Distributions 	mach_port_t server_port = MACH_PORT_NULL, reply_port = MACH_PORT_NULL;
143*2c2f96dcSApple OSS Distributions 	struct {
144*2c2f96dcSApple OSS Distributions 		mach_msg_header_t header;
145*2c2f96dcSApple OSS Distributions 		mach_msg_body_t body;
146*2c2f96dcSApple OSS Distributions 		mach_msg_port_descriptor_t desc;
147*2c2f96dcSApple OSS Distributions 	} msg;
148*2c2f96dcSApple OSS Distributions 
149*2c2f96dcSApple OSS Distributions 	server_port = alloc_server_port();
150*2c2f96dcSApple OSS Distributions 	reply_port = alloc_reply_port();
151*2c2f96dcSApple OSS Distributions 
152*2c2f96dcSApple OSS Distributions 	msg.header.msgh_remote_port = server_port;
153*2c2f96dcSApple OSS Distributions 	msg.header.msgh_local_port = MACH_PORT_NULL;
154*2c2f96dcSApple OSS Distributions 	msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0) | MACH_MSGH_BITS_COMPLEX;
155*2c2f96dcSApple OSS Distributions 	msg.header.msgh_size = sizeof msg;
156*2c2f96dcSApple OSS Distributions 
157*2c2f96dcSApple OSS Distributions 	msg.body.msgh_descriptor_count = 1;
158*2c2f96dcSApple OSS Distributions 
159*2c2f96dcSApple OSS Distributions 	msg.desc.name = reply_port;
160*2c2f96dcSApple OSS Distributions 	msg.desc.disposition = MACH_MSG_TYPE_MOVE_SEND;
161*2c2f96dcSApple OSS Distributions 	msg.desc.type = MACH_MSG_PORT_DESCRIPTOR;
162*2c2f96dcSApple OSS Distributions 
163*2c2f96dcSApple OSS Distributions 	kr = mach_msg_send(&msg.header);
164*2c2f96dcSApple OSS Distributions 	printf("[reply_port_defense_client test_move_send_right]: mach_msg2() returned %d\n", kr);
165*2c2f96dcSApple OSS Distributions }
166*2c2f96dcSApple OSS Distributions 
167*2c2f96dcSApple OSS Distributions static void
test_move_provisional_reply_port(void)168*2c2f96dcSApple OSS Distributions test_move_provisional_reply_port(void)
169*2c2f96dcSApple OSS Distributions {
170*2c2f96dcSApple OSS Distributions 	kern_return_t kr;
171*2c2f96dcSApple OSS Distributions 	mach_port_t server_port = MACH_PORT_NULL, reply_port = MACH_PORT_NULL;
172*2c2f96dcSApple OSS Distributions 	struct {
173*2c2f96dcSApple OSS Distributions 		mach_msg_header_t header;
174*2c2f96dcSApple OSS Distributions 		mach_msg_body_t body;
175*2c2f96dcSApple OSS Distributions 		mach_msg_port_descriptor_t desc;
176*2c2f96dcSApple OSS Distributions 	} msg;
177*2c2f96dcSApple OSS Distributions 
178*2c2f96dcSApple OSS Distributions 	server_port = alloc_server_port();
179*2c2f96dcSApple OSS Distributions 	reply_port = alloc_provisional_reply_port();
180*2c2f96dcSApple OSS Distributions 
181*2c2f96dcSApple OSS Distributions 	msg.header.msgh_remote_port = server_port;
182*2c2f96dcSApple OSS Distributions 	msg.header.msgh_local_port = MACH_PORT_NULL;
183*2c2f96dcSApple OSS Distributions 	msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0) | MACH_MSGH_BITS_COMPLEX;
184*2c2f96dcSApple OSS Distributions 	msg.header.msgh_size = sizeof msg;
185*2c2f96dcSApple OSS Distributions 
186*2c2f96dcSApple OSS Distributions 	msg.body.msgh_descriptor_count = 1;
187*2c2f96dcSApple OSS Distributions 
188*2c2f96dcSApple OSS Distributions 	msg.desc.name = reply_port;
189*2c2f96dcSApple OSS Distributions 	msg.desc.disposition = MACH_MSG_TYPE_MOVE_RECEIVE;
190*2c2f96dcSApple OSS Distributions 	msg.desc.type = MACH_MSG_PORT_DESCRIPTOR;
191*2c2f96dcSApple OSS Distributions 
192*2c2f96dcSApple OSS Distributions 	kr = mach_msg_send(&msg.header);
193*2c2f96dcSApple OSS Distributions 
194*2c2f96dcSApple OSS Distributions 	printf("[reply_port_defense_client test_immovable_receive_right]: mach_msg2() returned %d\n", kr);
195*2c2f96dcSApple OSS Distributions }
196*2c2f96dcSApple OSS Distributions 
197*2c2f96dcSApple OSS Distributions static void
test_unentitled_thread_set_state(void)198*2c2f96dcSApple OSS Distributions test_unentitled_thread_set_state(void)
199*2c2f96dcSApple OSS Distributions {
200*2c2f96dcSApple OSS Distributions 	machine_thread_state_t ts;
201*2c2f96dcSApple OSS Distributions 	mach_msg_type_number_t count = MACHINE_THREAD_STATE_COUNT;
202*2c2f96dcSApple OSS Distributions 
203*2c2f96dcSApple OSS Distributions 	/* thread_set_state as a hardened binary should fail */
204*2c2f96dcSApple OSS Distributions 	kern_return_t kr = thread_get_state(mach_thread_self(), MACHINE_THREAD_STATE, (thread_state_t)&ts, &count);
205*2c2f96dcSApple OSS Distributions 
206*2c2f96dcSApple OSS Distributions 	kr = thread_set_state(mach_thread_self(), MACHINE_THREAD_STATE, (thread_state_t)&ts, count);
207*2c2f96dcSApple OSS Distributions 	assert(kr != KERN_SUCCESS);
208*2c2f96dcSApple OSS Distributions 	exit(-1); /* Should have crashed before here! */
209*2c2f96dcSApple OSS Distributions }
210*2c2f96dcSApple OSS Distributions 
211*2c2f96dcSApple OSS Distributions static void
test_unentitled_thread_set_exception_ports(void)212*2c2f96dcSApple OSS Distributions test_unentitled_thread_set_exception_ports(void)
213*2c2f96dcSApple OSS Distributions {
214*2c2f96dcSApple OSS Distributions 	mach_port_t exc_port = alloc_server_port();
215*2c2f96dcSApple OSS Distributions 
216*2c2f96dcSApple OSS Distributions 	/* thread_set_exception_ports as a hardened binary should fail */
217*2c2f96dcSApple OSS Distributions 	kern_return_t kr = thread_set_exception_ports(
218*2c2f96dcSApple OSS Distributions 		mach_thread_self(),
219*2c2f96dcSApple OSS Distributions 		EXC_MASK_ALL,
220*2c2f96dcSApple OSS Distributions 		exc_port,
221*2c2f96dcSApple OSS Distributions 		(exception_behavior_t)((unsigned int)EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES),
222*2c2f96dcSApple OSS Distributions 		EXCEPTION_THREAD_STATE);
223*2c2f96dcSApple OSS Distributions 
224*2c2f96dcSApple OSS Distributions 	/* thread_set_exception_ports is supposed to crash, unless the policy is turned off.
225*2c2f96dcSApple OSS Distributions 	 * Things that disable the policy: AMFI boot-args in use, SIP disabled,
226*2c2f96dcSApple OSS Distributions 	 * third party plugins in a process. The caller of this client will check
227*2c2f96dcSApple OSS Distributions 	 * whether the test crashed and correctly adhered to these policies.
228*2c2f96dcSApple OSS Distributions 	 */
229*2c2f96dcSApple OSS Distributions 	printf("thread_set_exception_ports did not crash\n");
230*2c2f96dcSApple OSS Distributions }
231*2c2f96dcSApple OSS Distributions 
232*2c2f96dcSApple OSS Distributions int
main(int argc,char * argv[])233*2c2f96dcSApple OSS Distributions main(int argc, char *argv[])
234*2c2f96dcSApple OSS Distributions {
235*2c2f96dcSApple OSS Distributions 	uint32_t my_csflags = 0;
236*2c2f96dcSApple OSS Distributions 	bool thirdparty_hardened = !strcmp(argv[0], "./reply_port_defense_client_3P_hardened");
237*2c2f96dcSApple OSS Distributions 
238*2c2f96dcSApple OSS Distributions 	if (my_csflags & CS_PLATFORM_BINARY == thirdparty_hardened) {
239*2c2f96dcSApple OSS Distributions 		printf("platform binary does not match expected\n");
240*2c2f96dcSApple OSS Distributions 		return -1;
241*2c2f96dcSApple OSS Distributions 	}
242*2c2f96dcSApple OSS Distributions 
243*2c2f96dcSApple OSS Distributions 
244*2c2f96dcSApple OSS Distributions 	void (*tests[MAX_TEST_NUM])(void) = {
245*2c2f96dcSApple OSS Distributions 		test_immovable_receive_right, /* 0 */
246*2c2f96dcSApple OSS Distributions 		test_make_send_once_right,
247*2c2f96dcSApple OSS Distributions 		test_using_send_right,
248*2c2f96dcSApple OSS Distributions 		test_move_send_right,
249*2c2f96dcSApple OSS Distributions 		test_move_provisional_reply_port,
250*2c2f96dcSApple OSS Distributions 		test_unentitled_thread_set_exception_ports,
251*2c2f96dcSApple OSS Distributions 		test_unentitled_thread_set_state /* 6 */
252*2c2f96dcSApple OSS Distributions 	};
253*2c2f96dcSApple OSS Distributions 
254*2c2f96dcSApple OSS Distributions 	if (argc < 2) {
255*2c2f96dcSApple OSS Distributions 		printf("[reply_port_defense_client]: Specify a test to run.");
256*2c2f96dcSApple OSS Distributions 		exit(-1);
257*2c2f96dcSApple OSS Distributions 	}
258*2c2f96dcSApple OSS Distributions 
259*2c2f96dcSApple OSS Distributions 	int test_num = atoi(argv[1]);
260*2c2f96dcSApple OSS Distributions 	printf("[reply_port_defense_client]: My Pid: %d Test num: %d third_party_hardened: %s\n",
261*2c2f96dcSApple OSS Distributions 	    getpid(), test_num, thirdparty_hardened ? "yes" : "no");
262*2c2f96dcSApple OSS Distributions 	fflush(stdout);
263*2c2f96dcSApple OSS Distributions 	if (test_num >= 0 && test_num < MAX_TEST_NUM) {
264*2c2f96dcSApple OSS Distributions 		(*tests[test_num])();
265*2c2f96dcSApple OSS Distributions 	} else {
266*2c2f96dcSApple OSS Distributions 		printf("[reply_port_defense_client]: Invalid test num. Exiting...\n");
267*2c2f96dcSApple OSS Distributions 		exit(-1);
268*2c2f96dcSApple OSS Distributions 	}
269*2c2f96dcSApple OSS Distributions 	printf("Child exiting cleanly!!\n");
270*2c2f96dcSApple OSS Distributions 	fflush(stdout);
271*2c2f96dcSApple OSS Distributions 	// return 0;
272*2c2f96dcSApple OSS Distributions 	exit(0);
273*2c2f96dcSApple OSS Distributions }
274