1 #include <darwintest.h>
2 #include <servers/bootstrap.h>
3 #include <mach/mach.h>
4 #include <mach/message.h>
5 #include <stdlib.h>
6 #include <sys/sysctl.h>
7 #include <unistd.h>
8
9 T_GLOBAL_META(
10 T_META_NAMESPACE("xnu.ipc"),
11 T_META_RUN_CONCURRENTLY(TRUE),
12 T_META_RADAR_COMPONENT_NAME("xnu"),
13 T_META_RADAR_COMPONENT_VERSION("IPC"),
14 T_META_TAG_VM_PREFERRED);
15
16 typedef struct {
17 mach_msg_header_t header;
18 mach_msg_body_t body;
19 mach_msg_guarded_port_descriptor_t guarded_port_descriptor1;
20 mach_msg_guarded_port_descriptor_t guarded_port_descriptor2;
21 mach_msg_trailer_t trailer; // subtract this when sending
22 } ipc_complex_message;
23
24 static ipc_complex_message icm_request = {};
25
26 struct args {
27 const char *progname;
28 int verbose;
29 int voucher;
30 int num_msgs;
31 const char *server_port_name;
32 mach_port_t server_port;
33 mach_port_t reply_port;
34 mach_port_t voucher_port;
35 int request_msg_size;
36 void *request_msg;
37 int reply_msg_size;
38 void *reply_msg;
39 mach_port_t sp_voucher_port;
40 uint32_t persona_id;
41 long client_pid;
42 };
43
44 void parse_args(struct args *args);
45 void* create_buffer(int *buffer_size);
46 void client(struct args *args);
47 void server_setup(struct args* args);
48 void server(struct args *args);
49
50 void
parse_args(struct args * args)51 parse_args(struct args *args)
52 {
53 args->verbose = 0;
54 args->voucher = 0;
55 args->server_port_name = "TEST";
56 args->server_port = MACH_PORT_NULL;
57 args->reply_port = MACH_PORT_NULL;
58 args->voucher_port = MACH_PORT_NULL;
59 args->num_msgs = 1;
60 args->request_msg_size = sizeof(ipc_complex_message);
61 args->request_msg = &icm_request;
62 args->client_pid = getpid();
63 }
64
65 /* Create a mach IPC listener which will respond to the client's message */
66 void
server_setup(struct args * args)67 server_setup(struct args* args)
68 {
69 kern_return_t ret;
70 mach_port_t bsport;
71
72 ret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE,
73 &args->server_port);
74 T_ASSERT_MACH_SUCCESS(ret, "server: mach_port_allocate()");
75
76 ret = mach_port_insert_right(mach_task_self(), args->server_port, args->server_port,
77 MACH_MSG_TYPE_MAKE_SEND);
78 T_ASSERT_MACH_SUCCESS(ret, "server: mach_port_insert_right()");
79
80 ret = task_get_bootstrap_port(mach_task_self(), &bsport);
81 T_ASSERT_MACH_SUCCESS(ret, "server: task_get_bootstrap_port()");
82
83 ret = bootstrap_register(bsport, args->server_port_name, args->server_port);
84 T_ASSERT_MACH_SUCCESS(ret, "server: bootstrap_register()");
85
86 T_LOG("server: waiting for IPC messages from client on port '%s'.\n",
87 args->server_port_name);
88 }
89
90 /* Server process loop
91 *
92 * Listens for message.
93 *
94 */
95 void
server(struct args * args)96 server(struct args *args)
97 {
98 mach_msg_header_t *request;
99 mach_msg_option_t rcvoption;
100 kern_return_t ret;
101
102 request = (mach_msg_header_t *)args->request_msg;
103
104 rcvoption = MACH_RCV_MSG | MACH_RCV_INTERRUPT | MACH_RCV_GUARDED_DESC;
105
106 T_LOG("server: Awaiting message\n");
107 ret = mach_msg(request,
108 rcvoption,
109 0,
110 sizeof(ipc_complex_message),
111 args->server_port,
112 MACH_MSG_TIMEOUT_NONE,
113 MACH_PORT_NULL);
114
115 T_ASSERT_MACH_SUCCESS(ret, "server: mach_msg receive");
116
117 ipc_complex_message *request_complexmsg = (ipc_complex_message *)request;
118 T_ASSERT_NE(request_complexmsg->guarded_port_descriptor1.name, 0, "server: Should not receive mach_port_null; name = %x", request_complexmsg->guarded_port_descriptor1.name);
119 T_ASSERT_EQ((mach_msg_descriptor_type_t)request_complexmsg->guarded_port_descriptor1.type, MACH_MSG_GUARDED_PORT_DESCRIPTOR, "server: Received a guarded port descriptor");
120 T_ASSERT_EQ((mach_msg_type_name_t)request_complexmsg->guarded_port_descriptor1.disposition, MACH_MSG_TYPE_PORT_RECEIVE, "server: Received a receive right");
121 T_ASSERT_EQ(request_complexmsg->guarded_port_descriptor1.context, (unsigned long)request, "server: Received a port with correct context = %p", request);
122 T_LOG("Guard flags = %d", request_complexmsg->guarded_port_descriptor1.flags);
123
124 T_ASSERT_NE(request_complexmsg->guarded_port_descriptor2.name, 0, "server: Should not receive mach_port_null; name = %x", request_complexmsg->guarded_port_descriptor2.name);
125 T_ASSERT_EQ((mach_msg_descriptor_type_t)request_complexmsg->guarded_port_descriptor2.type, MACH_MSG_GUARDED_PORT_DESCRIPTOR, "server: Received a guarded port descriptor");
126 T_ASSERT_EQ((mach_msg_type_name_t)request_complexmsg->guarded_port_descriptor2.disposition, MACH_MSG_TYPE_PORT_RECEIVE, "server: Received a receive right");
127 T_ASSERT_EQ(request_complexmsg->guarded_port_descriptor2.context, (unsigned long)request, "server: Received a port with correct context = %p", request);
128
129 mach_port_status_t status;
130 mach_msg_type_number_t status_size = MACH_PORT_RECEIVE_STATUS_COUNT;
131
132 kern_return_t kr = mach_port_get_attributes(mach_task_self(), request_complexmsg->guarded_port_descriptor1.name,
133 MACH_PORT_RECEIVE_STATUS, (mach_port_info_t)&status, &status_size);
134 T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "mach_port_get_attributes for descriptor 1");
135 T_LOG("Status flags %d", status.mps_flags);
136 T_ASSERT_NE(0, (status.mps_flags & MACH_PORT_STATUS_FLAG_GUARD_IMMOVABLE_RECEIVE), "Imm rcv bit is set for descriptor1");
137
138 kr = mach_port_get_attributes(mach_task_self(), request_complexmsg->guarded_port_descriptor2.name,
139 MACH_PORT_RECEIVE_STATUS, (mach_port_info_t)&status, &status_size);
140 T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "mach_port_get_attributes for descriptor 2");
141 T_LOG("Status flags %d", status.mps_flags);
142 T_ASSERT_NE(0, (status.mps_flags & MACH_PORT_STATUS_FLAG_GUARD_IMMOVABLE_RECEIVE), "Imm rcv bit is set for descriptor2");
143
144 mach_msg_destroy(request);
145 }
146
147 void
client(struct args * args)148 client(struct args *args)
149 {
150 //Find the bootstrap port
151 mach_port_t bsport;
152 mach_port_t guarded_port;
153 mach_port_t unguarded_port;
154
155 kern_return_t ret = task_get_bootstrap_port(mach_task_self(), &bsport);
156 T_ASSERT_MACH_SUCCESS(ret, "client: task_get_bootstrap_port()");
157
158 //Look up the service port
159 ret = bootstrap_look_up(bsport, (char *)args->server_port_name,
160 &args->server_port);
161 T_ASSERT_MACH_SUCCESS(ret, "client: bootstrap_look_up()");
162
163 //Create the unguarded port
164 ret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE,
165 &unguarded_port);
166 T_ASSERT_MACH_SUCCESS(ret, "client: mach_port_allocate() reply port");
167
168 mach_port_options_t opts = {
169 .flags = MPO_CONTEXT_AS_GUARD
170 };
171
172 ret = mach_port_construct(mach_task_self(), &opts, 0x10, &guarded_port);
173 T_QUIET; T_ASSERT_MACH_SUCCESS(ret, "mach_port_construct");
174
175 //Construct the message
176 mach_msg_header_t *request = (mach_msg_header_t *)args->request_msg;
177 request->msgh_bits = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND_ONCE,
178 0, 0) | MACH_MSGH_BITS_COMPLEX;
179 request->msgh_size = (mach_msg_size_t)args->request_msg_size;
180 request->msgh_remote_port = args->server_port;
181 request->msgh_local_port = args->reply_port;
182 request->msgh_id = 1;
183
184 ipc_complex_message *complexmsg = (ipc_complex_message *)request;
185 complexmsg->body.msgh_descriptor_count = 2;
186 complexmsg->guarded_port_descriptor1.name = guarded_port;
187 complexmsg->guarded_port_descriptor1.disposition = MACH_MSG_TYPE_MOVE_RECEIVE;
188 complexmsg->guarded_port_descriptor1.flags = MACH_MSG_GUARD_FLAGS_IMMOVABLE_RECEIVE;
189 complexmsg->guarded_port_descriptor1.context = 0x10;
190 complexmsg->guarded_port_descriptor1.type = MACH_MSG_GUARDED_PORT_DESCRIPTOR;
191
192 complexmsg->guarded_port_descriptor2.name = unguarded_port;
193 complexmsg->guarded_port_descriptor2.disposition = MACH_MSG_TYPE_MOVE_RECEIVE;
194 complexmsg->guarded_port_descriptor2.flags = MACH_MSG_GUARD_FLAGS_IMMOVABLE_RECEIVE | MACH_MSG_GUARD_FLAGS_UNGUARDED_ON_SEND;
195 complexmsg->guarded_port_descriptor2.context = 0;
196 complexmsg->guarded_port_descriptor2.type = MACH_MSG_GUARDED_PORT_DESCRIPTOR;
197
198 mach_msg_option_t option = MACH_SEND_MSG;
199
200 //Listen for the reply on the reply port
201 T_LOG("client: Sending request\n");
202 ret = mach_msg(request,
203 option,
204 (mach_msg_size_t)args->request_msg_size,
205 0,
206 MACH_PORT_NULL,
207 MACH_MSG_TIMEOUT_NONE,
208 MACH_PORT_NULL);
209 T_ASSERT_MACH_SUCCESS(ret, "client: mach_msg_overwrite()");
210 }
211
212 T_DECL(mo_immovable_receive, "Send a message containing a guard port descriptor for an immovable receive right")
213 {
214 struct args args = {};
215 parse_args(&args);
216 args.request_msg_size -= sizeof(mach_msg_trailer_t);
217 args.reply_msg_size -= sizeof(mach_msg_trailer_t);
218
219 //Create the server
220 pid_t pid = fork();
221 if (pid == 0) {
222 T_LOG("Server is up");
223 server_setup(&args);
224 server(&args);
225 exit(0);
226 }
227
228 sleep(2);
229 T_LOG("Preparing client to send a request");
230 client(&args);
231 T_ASSERT_POSIX_SUCCESS(waitpid(pid, NULL, 0), "waitpid()");
232 }
233