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