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