xref: /xnu-8792.81.2/tests/mach_service_port.c (revision 19c3b8c28c31cb8130e034cfb5df6bf9ba342d90)
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 #include <mach/port.h>
9 #include <mach/mach_port.h>
10 #include <stdint.h>
11 #include <stdio.h>
12 #include <unistd.h>
13 #include <pthread.h>
14 #include <err.h>
15 #include <sysexits.h>
16 
17 #include "notifyServer.h"
18 
19 T_GLOBAL_META(T_META_RUN_CONCURRENTLY(true),
20     T_META_NAMESPACE("xnu.ipc"),
21     T_META_RADAR_COMPONENT_NAME("xnu"),
22     T_META_RADAR_COMPONENT_VERSION("IPC"));
23 
24 static mach_port_t service_port = MACH_PORT_NULL;
25 
26 #define SP_CONTEXT (0x1803)
27 #define NEW_SP_CONTEXT (0x0318)
28 #define SERVICE_NAME "com.apple.testservice"
29 #define SERVICE_DOMAIN (1)
30 
31 T_DECL(mach_service_port, "Create a port with a service port label", T_META_CHECK_LEAKS(false)) {
32 	mach_port_t connection_port;
33 	mach_port_t notify_port;
34 	mach_port_t previous;
35 	uint64_t fpid = 0;
36 
37 	struct mach_service_port_info sp_info = {};
38 
39 	strcpy(sp_info.mspi_string_name, SERVICE_NAME);
40 	sp_info.mspi_domain_type = (uint8_t)SERVICE_DOMAIN;
41 	kern_return_t kr;
42 
43 	mach_port_options_t opts = {
44 		.flags = MPO_SERVICE_PORT | MPO_INSERT_SEND_RIGHT | MPO_CONTEXT_AS_GUARD | MPO_STRICT,
45 		.service_port_info = &sp_info,
46 	};
47 
48 	kr = mach_port_construct(mach_task_self(), &opts, SP_CONTEXT, &service_port);
49 	T_ASSERT_MACH_SUCCESS(kr, "mach_port_construct %u", service_port);
50 
51 	mach_port_options_t opts2 = {
52 		.flags = MPO_CONNECTION_PORT,
53 		.service_port_name = service_port,
54 	};
55 
56 	kr = mach_port_construct(mach_task_self(), &opts2, 0x0, &connection_port);
57 	T_ASSERT_MACH_SUCCESS(kr, "mach_port_construct %u", connection_port);
58 
59 	kr = mach_port_is_connection_for_service(mach_task_self(), connection_port, service_port, &fpid);
60 	if (kr != KERN_SUCCESS || kr != KERN_NOT_SUPPORTED) {
61 		T_LOG("mach_port_is_connection_for_service kr = %d, fpid = %llu", kr, fpid);
62 	}
63 
64 	// notification port for the service port to come back on
65 	kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &notify_port);
66 	T_ASSERT_MACH_SUCCESS(kr, "mach_port_allocate notify_port");
67 
68 	kr = mach_port_insert_right(mach_task_self(), notify_port, notify_port, MACH_MSG_TYPE_MAKE_SEND);
69 	T_ASSERT_MACH_SUCCESS(kr, "mach_port_insert_right notify_port");
70 
71 	T_LOG("service port: 0x%x, notify port: 0x%x\n", service_port, notify_port);
72 
73 	kr = mach_port_request_notification(mach_task_self(), service_port, MACH_NOTIFY_PORT_DESTROYED, 0, notify_port,
74 	    MACH_MSG_TYPE_MAKE_SEND_ONCE, &previous);
75 	T_ASSERT_MACH_SUCCESS(kr, "mach_port_request_notification service_port");
76 	T_ASSERT_EQ(previous, MACH_PORT_NULL, "previous null");
77 
78 	/* Attempt to destroy port */
79 	kr = mach_port_destruct(mach_task_self(), service_port, 0, SP_CONTEXT);
80 	T_ASSERT_MACH_SUCCESS(kr, "mach_port_destruct service_port");
81 
82 	/*
83 	 * Recover the service port because the port must have been destroyed and sent the notification by now
84 	 */
85 	kr = mach_msg_server_once(notify_server, MACH_MSG_SIZE_RELIABLE, notify_port, MACH_RCV_TIMEOUT);
86 	T_ASSERT_MACH_SUCCESS(kr, "mach_msg_server_once notify_port");
87 
88 	T_LOG("done");
89 }
90 
91 kern_return_t
do_mach_notify_port_destroyed(mach_port_t notify,mach_port_t name)92 do_mach_notify_port_destroyed(mach_port_t notify, mach_port_t name)
93 {
94 	kern_return_t kr;
95 
96 	T_LOG("Received a service port destroyed notification notify = 0x%x name = 0x%x", notify, name);
97 	if (name == MACH_PORT_NULL) {
98 		T_FAIL("do_mach_notify_port_destroyed: MACH_PORT_NULL?");
99 	}
100 
101 	if (name != service_port) {
102 		T_FAIL("do_mach_notify_port_destroyed: name 0x%x != service_port: 0x%x", name, service_port);
103 	}
104 
105 	struct mach_service_port_info sp_info = {};
106 	kr = mach_port_get_service_port_info(mach_task_self(), service_port, &sp_info);
107 	T_ASSERT_MACH_SUCCESS(kr, "mach_port_get_service_port_info");
108 
109 	if (strcmp(sp_info.mspi_string_name, SERVICE_NAME)) {
110 		T_FAIL("Service port name = %s is incorrect", sp_info.mspi_string_name);
111 	}
112 	T_ASSERT_EQ(sp_info.mspi_domain_type, SERVICE_DOMAIN, "Service domain = %u", sp_info.mspi_domain_type);
113 
114 	mach_port_guard_info_t mpgi = {SP_CONTEXT};
115 	kr = mach_port_assert_attributes(mach_task_self(), service_port, MACH_PORT_GUARD_INFO, (mach_port_info_t)&mpgi, MACH_PORT_GUARD_INFO_COUNT);
116 	T_ASSERT_MACH_SUCCESS(kr, "mach_port_assert_attributes");
117 
118 	return KERN_SUCCESS;
119 }
120 
121 kern_return_t
do_mach_notify_port_deleted(__unused mach_port_t notify,__unused mach_port_name_t name)122 do_mach_notify_port_deleted(__unused mach_port_t notify, __unused mach_port_name_t name)
123 {
124 	return KERN_SUCCESS;
125 }
126 
127 kern_return_t
do_mach_notify_no_senders(__unused mach_port_t notify,__unused mach_port_mscount_t mscount)128 do_mach_notify_no_senders(__unused mach_port_t notify, __unused mach_port_mscount_t mscount)
129 {
130 	return KERN_SUCCESS;
131 }
132 
133 kern_return_t
do_mach_notify_send_once(__unused mach_port_t notify)134 do_mach_notify_send_once(__unused mach_port_t notify)
135 {
136 	return KERN_SUCCESS;
137 }
138 
139 kern_return_t
do_mach_notify_dead_name(__unused mach_port_t notify,__unused mach_port_name_t name)140 do_mach_notify_dead_name(__unused mach_port_t notify, __unused mach_port_name_t name)
141 {
142 	return KERN_SUCCESS;
143 }
144 
145 #define SERVICE_NAME_2 "com.apple.testservice2"
146 #define SERVICE_DOMAIN_2 (2)
147 
148 T_DECL(mach_fake_service_port, "Create a connection port with a fake service port", T_META_CHECK_LEAKS(false))
149 {
150 	mach_port_t connection_port;
151 	mach_port_t fake_service_port;
152 	mach_port_t service_port_2;
153 
154 	kern_return_t kr;
155 
156 	struct mach_service_port_info sp_info = {};
157 
158 	strcpy(sp_info.mspi_string_name, SERVICE_NAME_2);
159 	sp_info.mspi_domain_type = (uint8_t)SERVICE_DOMAIN_2;
160 
161 	mach_port_options_t opts = {
162 		.flags = MPO_CONNECTION_PORT | MPO_SERVICE_PORT | MPO_INSERT_SEND_RIGHT | MPO_CONTEXT_AS_GUARD,
163 		.service_port_info = &sp_info,
164 	};
165 
166 	kr = mach_port_construct(mach_task_self(), &opts, SP_CONTEXT, &service_port_2);
167 	T_ASSERT_MACH_ERROR(kr, KERN_INVALID_ARGUMENT, "mach_port_construct with extra flags %u", service_port_2);
168 
169 	mach_port_options_t opts2 = {
170 		.flags = MPO_SERVICE_PORT | MPO_INSERT_SEND_RIGHT | MPO_CONTEXT_AS_GUARD,
171 		.service_port_info = NULL,
172 	};
173 
174 	kr = mach_port_construct(mach_task_self(), &opts2, SP_CONTEXT, &service_port_2);
175 	T_ASSERT_MACH_ERROR(kr, KERN_INVALID_ARGUMENT, "mach_port_construct with missing service port info %u", service_port_2);
176 
177 	mach_port_options_t opts3 = {
178 		.flags = MPO_INSERT_SEND_RIGHT | MPO_CONTEXT_AS_GUARD,
179 	};
180 
181 	kr = mach_port_construct(mach_task_self(), &opts3, SP_CONTEXT, &fake_service_port);
182 	T_ASSERT_MACH_SUCCESS(kr, "mach_port_construct with missing flag %u", fake_service_port);
183 
184 	struct mach_service_port_info sp_info3 = {};
185 	kr = mach_port_get_service_port_info(mach_task_self(), fake_service_port, &sp_info3);
186 	T_ASSERT_MACH_ERROR(kr, KERN_INVALID_CAPABILITY, "mach_port_get_service_port_info");
187 
188 	mach_port_options_t opts4 = {
189 		.flags = MPO_CONNECTION_PORT,
190 		.service_port_name = fake_service_port,
191 	};
192 
193 	kr = mach_port_construct(mach_task_self(), &opts4, 0x0, &connection_port);
194 	T_ASSERT_MACH_ERROR(kr, KERN_INVALID_CAPABILITY, "mach_port_construct connection port %u", connection_port);
195 
196 	T_LOG("done");
197 }
198 
199 T_DECL(mach_dead_service_port, "Create a connection port with a dead service port", T_META_CHECK_LEAKS(false))
200 {
201 	mach_port_t connection_port;
202 	mach_port_t service_port_2;
203 
204 	kern_return_t kr;
205 
206 	struct mach_service_port_info sp_info = {};
207 
208 	strcpy(sp_info.mspi_string_name, SERVICE_NAME_2);
209 	sp_info.mspi_domain_type = (uint8_t)SERVICE_DOMAIN_2;
210 
211 	mach_port_options_t opts = {
212 		.flags = MPO_SERVICE_PORT | MPO_INSERT_SEND_RIGHT,
213 		.service_port_info = &sp_info,
214 	};
215 
216 	kr = mach_port_construct(mach_task_self(), &opts, 0, &service_port_2);
217 	T_ASSERT_MACH_SUCCESS(kr, "mach_port_construct %u", service_port_2);
218 
219 	kr = mach_port_mod_refs(mach_task_self(), service_port_2, MACH_PORT_RIGHT_RECEIVE, -1);
220 	T_ASSERT_MACH_SUCCESS(kr, "mach_port_mod_refs");
221 
222 	mach_port_options_t opts3 = {
223 		.flags = MPO_CONNECTION_PORT,
224 		.service_port_name = service_port_2,
225 	};
226 
227 	kr = mach_port_construct(mach_task_self(), &opts3, 0x0, &connection_port);
228 	T_LOG("mach_port_construct connection port kr = %d", kr);
229 
230 	if (kr == KERN_INVALID_RIGHT || kr == KERN_INVALID_NAME) {
231 		T_PASS("Invalid service port");
232 	} else {
233 		T_FAIL("mach_port_construct incorrect return value");
234 	}
235 
236 	T_LOG("done");
237 }
238