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