xref: /xnu-10002.1.13/tests/reply_port_defense_client.c (revision 1031c584a5e37aff177559b9f69dbd3c8c3fd30a)
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <pthread.h>
4 #include <unistd.h>
5 #include <mach/mach.h>
6 #include <mach/task.h>
7 #include <assert.h>
8 
9 #define MAX_TEST_NUM 5
10 
11 static mach_port_t
alloc_server_port(void)12 alloc_server_port(void)
13 {
14 	mach_port_t server_port = MACH_PORT_NULL;
15 	kern_return_t kr;
16 
17 	kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &server_port);
18 	assert(kr == 0);
19 
20 	kr = mach_port_insert_right(mach_task_self(), server_port, server_port, MACH_MSG_TYPE_MAKE_SEND);
21 	assert(kr == 0);
22 
23 	return server_port;
24 }
25 
26 static mach_port_t
alloc_provisional_reply_port()27 alloc_provisional_reply_port()
28 {
29 	kern_return_t kr;
30 	mach_port_t reply_port = MACH_PORT_NULL;
31 	mach_port_t task = mach_task_self();
32 
33 	mach_port_options_t opts = {
34 		.flags = MPO_PROVISIONAL_REPLY_PORT | MPO_INSERT_SEND_RIGHT,
35 	};
36 
37 	kr = mach_port_construct(mach_task_self(), &opts, 0, &reply_port);
38 	assert(kr == 0);
39 
40 	return reply_port;
41 }
42 
43 static mach_port_t
alloc_reply_port()44 alloc_reply_port()
45 {
46 	kern_return_t kr;
47 	mach_port_t reply_port = MACH_PORT_NULL;
48 	mach_port_t task = mach_task_self();
49 
50 	mach_port_options_t opts = {
51 		.flags = MPO_REPLY_PORT | MPO_INSERT_SEND_RIGHT,
52 	};
53 
54 	kr = mach_port_construct(mach_task_self(), &opts, 0, &reply_port);
55 	assert(kr == 0);
56 
57 	return reply_port;
58 }
59 
60 /* The rcv right of the port would be marked immovable. */
61 static void
test_immovable_receive_right(void)62 test_immovable_receive_right(void)
63 {
64 	kern_return_t kr;
65 	mach_port_t server_port = MACH_PORT_NULL, reply_port = MACH_PORT_NULL;
66 	struct {
67 		mach_msg_header_t header;
68 		mach_msg_body_t body;
69 		mach_msg_port_descriptor_t desc;
70 	} msg;
71 
72 	server_port = alloc_server_port();
73 	reply_port = alloc_reply_port();
74 
75 	msg.header.msgh_remote_port = server_port;
76 	msg.header.msgh_local_port = MACH_PORT_NULL;
77 	msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0) | MACH_MSGH_BITS_COMPLEX;
78 	msg.header.msgh_size = sizeof msg;
79 
80 	msg.body.msgh_descriptor_count = 1;
81 
82 	msg.desc.name = reply_port;
83 	msg.desc.disposition = MACH_MSG_TYPE_MOVE_RECEIVE;
84 	msg.desc.type = MACH_MSG_PORT_DESCRIPTOR;
85 
86 	kr = mach_msg_send(&msg.header);
87 
88 	printf("[reply_port_defense_client test_immovable_receive_right]: mach_msg2() returned %d\n", kr);
89 }
90 
91 /* 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. */
92 static void
test_make_send_once_right(void)93 test_make_send_once_right(void)
94 {
95 	kern_return_t kr;
96 	mach_port_t reply_port = alloc_reply_port();
97 	kr = mach_port_insert_right(mach_task_self(), reply_port, reply_port, MACH_MSG_TYPE_MAKE_SEND_ONCE);
98 	printf("[reply_port_defense_client test_make_send_once_right]: mach_port_insert_right() returned %d\n", kr);
99 }
100 
101 /* The send right of the port would only used for guarding a name in ipc space, it would not allow to send a message. */
102 static void
test_using_send_right(void)103 test_using_send_right(void)
104 {
105 	kern_return_t kr;
106 	mach_port_t reply_port = alloc_reply_port();
107 	struct {
108 		mach_msg_header_t header;
109 		mach_msg_body_t body;
110 	} msg;
111 
112 	msg.header.msgh_remote_port = reply_port;
113 	msg.header.msgh_local_port = MACH_PORT_NULL;
114 	msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
115 	msg.header.msgh_size = sizeof msg;
116 
117 	kr = mach_msg_send(&msg.header);
118 	printf("[reply_port_defense_client test_using_send_right]: mach_msg2() returned %d\n", kr);
119 }
120 
121 /* The send right of the port would only used for guarding a name in ipc space, it would not allowed to get moved. */
122 static void
test_move_send_right(void)123 test_move_send_right(void)
124 {
125 	kern_return_t kr;
126 	mach_port_t server_port = MACH_PORT_NULL, reply_port = MACH_PORT_NULL;
127 	struct {
128 		mach_msg_header_t header;
129 		mach_msg_body_t body;
130 		mach_msg_port_descriptor_t desc;
131 	} msg;
132 
133 	server_port = alloc_server_port();
134 	reply_port = alloc_reply_port();
135 
136 	msg.header.msgh_remote_port = server_port;
137 	msg.header.msgh_local_port = MACH_PORT_NULL;
138 	msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0) | MACH_MSGH_BITS_COMPLEX;
139 	msg.header.msgh_size = sizeof msg;
140 
141 	msg.body.msgh_descriptor_count = 1;
142 
143 	msg.desc.name = reply_port;
144 	msg.desc.disposition = MACH_MSG_TYPE_MOVE_SEND;
145 	msg.desc.type = MACH_MSG_PORT_DESCRIPTOR;
146 
147 	kr = mach_msg_send(&msg.header);
148 	printf("[reply_port_defense_client test_move_send_right]: mach_msg2() returned %d\n", kr);
149 }
150 
151 static void
test_move_provisional_reply_port(void)152 test_move_provisional_reply_port(void)
153 {
154 	kern_return_t kr;
155 	mach_port_t server_port = MACH_PORT_NULL, reply_port = MACH_PORT_NULL;
156 	struct {
157 		mach_msg_header_t header;
158 		mach_msg_body_t body;
159 		mach_msg_port_descriptor_t desc;
160 	} msg;
161 
162 	server_port = alloc_server_port();
163 	reply_port = alloc_provisional_reply_port();
164 
165 	msg.header.msgh_remote_port = server_port;
166 	msg.header.msgh_local_port = MACH_PORT_NULL;
167 	msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0) | MACH_MSGH_BITS_COMPLEX;
168 	msg.header.msgh_size = sizeof msg;
169 
170 	msg.body.msgh_descriptor_count = 1;
171 
172 	msg.desc.name = reply_port;
173 	msg.desc.disposition = MACH_MSG_TYPE_MOVE_RECEIVE;
174 	msg.desc.type = MACH_MSG_PORT_DESCRIPTOR;
175 
176 	kr = mach_msg_send(&msg.header);
177 
178 	printf("[reply_port_defense_client test_immovable_receive_right]: mach_msg2() returned %d\n", kr);
179 }
180 
181 int
main(int argc,char * argv[])182 main(int argc, char *argv[])
183 {
184 	printf("[reply_port_defense_client]: My Pid: %d\n", getpid());
185 
186 	void (*tests[MAX_TEST_NUM])(void) = {
187 		test_immovable_receive_right,
188 		test_make_send_once_right,
189 		test_using_send_right,
190 		test_move_send_right,
191 		test_move_provisional_reply_port
192 	};
193 
194 	if (argc < 2) {
195 		printf("[reply_port_defense_client]: Specify a test to run.");
196 		exit(-1);
197 	}
198 
199 	int test_num = atoi(argv[1]);
200 	if (test_num >= 0 && test_num < MAX_TEST_NUM) {
201 		(*tests[test_num])();
202 	} else {
203 		printf("[reply_port_defense_client]: Invalid test num. Exiting...\n");
204 		exit(-1);
205 	}
206 	exit(0);
207 }
208