xref: /xnu-8792.61.2/tests/reply_port_defense_client.c (revision 42e220869062b56f8d7d0726fd4c88954f87902c)
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 4
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_reply_port()27 alloc_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_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 /* The rcv right of the port would be marked immovable. */
44 static void
test_immovable_receive_right(void)45 test_immovable_receive_right(void)
46 {
47 	kern_return_t kr;
48 	mach_port_t server_port = MACH_PORT_NULL, reply_port = MACH_PORT_NULL;
49 	struct {
50 		mach_msg_header_t header;
51 		mach_msg_body_t body;
52 		mach_msg_port_descriptor_t desc;
53 	} msg;
54 
55 	server_port = alloc_server_port();
56 	reply_port = alloc_reply_port();
57 
58 	msg.header.msgh_remote_port = server_port;
59 	msg.header.msgh_local_port = MACH_PORT_NULL;
60 	msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0) | MACH_MSGH_BITS_COMPLEX;
61 	msg.header.msgh_size = sizeof msg;
62 
63 	msg.body.msgh_descriptor_count = 1;
64 
65 	msg.desc.name = reply_port;
66 	msg.desc.disposition = MACH_MSG_TYPE_MOVE_RECEIVE;
67 	msg.desc.type = MACH_MSG_PORT_DESCRIPTOR;
68 
69 	kr = mach_msg_send(&msg.header);
70 
71 	printf("[reply_port_defense_client test_immovable_receive_right]: mach_msg2() returned %d\n", kr);
72 }
73 
74 /* 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. */
75 static void
test_make_send_once_right(void)76 test_make_send_once_right(void)
77 {
78 	kern_return_t kr;
79 	mach_port_t reply_port = alloc_reply_port();
80 	kr = mach_port_insert_right(mach_task_self(), reply_port, reply_port, MACH_MSG_TYPE_MAKE_SEND_ONCE);
81 	printf("[reply_port_defense_client test_make_send_once_right]: mach_port_insert_right() returned %d\n", kr);
82 }
83 
84 /* The send right of the port would only used for guarding a name in ipc space, it would not allow to send a message. */
85 static void
test_using_send_right(void)86 test_using_send_right(void)
87 {
88 	kern_return_t kr;
89 	mach_port_t reply_port = alloc_reply_port();
90 	struct {
91 		mach_msg_header_t header;
92 		mach_msg_body_t body;
93 	} msg;
94 
95 	msg.header.msgh_remote_port = reply_port;
96 	msg.header.msgh_local_port = MACH_PORT_NULL;
97 	msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
98 	msg.header.msgh_size = sizeof msg;
99 
100 	kr = mach_msg_send(&msg.header);
101 	printf("[reply_port_defense_client test_using_send_right]: mach_msg2() returned %d\n", kr);
102 }
103 
104 /* The send right of the port would only used for guarding a name in ipc space, it would not allowed to get moved. */
105 static void
test_move_send_right(void)106 test_move_send_right(void)
107 {
108 	kern_return_t kr;
109 	mach_port_t server_port = MACH_PORT_NULL, reply_port = MACH_PORT_NULL;
110 	struct {
111 		mach_msg_header_t header;
112 		mach_msg_body_t body;
113 		mach_msg_port_descriptor_t desc;
114 	} msg;
115 
116 	server_port = alloc_server_port();
117 	reply_port = alloc_reply_port();
118 
119 	msg.header.msgh_remote_port = server_port;
120 	msg.header.msgh_local_port = MACH_PORT_NULL;
121 	msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0) | MACH_MSGH_BITS_COMPLEX;
122 	msg.header.msgh_size = sizeof msg;
123 
124 	msg.body.msgh_descriptor_count = 1;
125 
126 	msg.desc.name = reply_port;
127 	msg.desc.disposition = MACH_MSG_TYPE_MOVE_SEND;
128 	msg.desc.type = MACH_MSG_PORT_DESCRIPTOR;
129 
130 	kr = mach_msg_send(&msg.header);
131 	printf("[reply_port_defense_client test_move_send_right]: mach_msg2() returned %d\n", kr);
132 }
133 
134 int
main(int argc,char * argv[])135 main(int argc, char *argv[])
136 {
137 	printf("[reply_port_defense_client]: My Pid: %d\n", getpid());
138 
139 	void (*tests[MAX_TEST_NUM])(void) = {
140 		test_immovable_receive_right,
141 		test_make_send_once_right,
142 		test_using_send_right,
143 		test_move_send_right
144 	};
145 
146 	if (argc < 2) {
147 		printf("[reply_port_defense_client]: Specify a test to run.");
148 		exit(-1);
149 	}
150 
151 	int test_num = atoi(argv[1]);
152 	if (test_num >= 0 && test_num < MAX_TEST_NUM) {
153 		(*tests[test_num])();
154 	} else {
155 		printf("[reply_port_defense_client]: Invalid test num. Exiting...\n");
156 		exit(-1);
157 	}
158 
159 	exit(0);
160 }
161