xref: /xnu-11215.81.4/tests/ipc_mach_port.c (revision d4514f0bc1d3f944c22d92e68b646ac3fb40d452)
1 #include <darwintest.h>
2 #include <darwintest_multiprocess.h>
3 #include <launch.h>
4 #include <servers/bootstrap.h>
5 #include <sys/sysctl.h>
6 #include "exc_helpers.h"
7 
8 T_GLOBAL_META(
9 	T_META_NAMESPACE("xnu.ipc"),
10 	T_META_RADAR_COMPONENT_NAME("xnu"),
11 	T_META_RADAR_COMPONENT_VERSION("IPC"),
12 	T_META_RUN_CONCURRENTLY(true),
13 	T_META_TAG_VM_PREFERRED);
14 
15 #pragma mark - helpers
16 
17 #define SERVICE_NAME  "com.apple.xnu.test.mach_port"
18 
19 struct one_port_msg {
20 	mach_msg_header_t          header;
21 	mach_msg_body_t            body;
22 	mach_msg_port_descriptor_t port_descriptor;
23 	mach_msg_trailer_t         trailer;            // subtract this when sending
24 };
25 
26 static mach_port_t
server_checkin(void)27 server_checkin(void)
28 {
29 	mach_port_t mp;
30 	kern_return_t kr;
31 
32 	kr = bootstrap_check_in(bootstrap_port, SERVICE_NAME, &mp);
33 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "bootstrap_check_in");
34 	return mp;
35 }
36 
37 static mach_port_t
server_lookup(void)38 server_lookup(void)
39 {
40 	mach_port_t mp;
41 	kern_return_t kr;
42 
43 	kr = bootstrap_look_up(bootstrap_port, SERVICE_NAME, &mp);
44 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "bootstrap_look_up");
45 	return mp;
46 }
47 
48 static mach_port_t
make_sr_port(void)49 make_sr_port(void)
50 {
51 	mach_port_options_t opts = {
52 		.flags = MPO_INSERT_SEND_RIGHT,
53 	};
54 	kern_return_t kr;
55 	mach_port_t port;
56 
57 	kr = mach_port_construct(mach_task_self(), &opts, 0ull, &port);
58 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "mach_port_construct");
59 	return port;
60 }
61 
62 static void
destroy_port(mach_port_t port,bool receive,int srights)63 destroy_port(mach_port_t port, bool receive, int srights)
64 {
65 	kern_return_t kr;
66 
67 	if (srights) {
68 		kr = mach_port_mod_refs(mach_task_self(), port,
69 		    MACH_PORT_RIGHT_SEND, -srights);
70 		T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "srights -= %d", srights);
71 	}
72 	if (receive) {
73 		kr = mach_port_mod_refs(mach_task_self(), port,
74 		    MACH_PORT_RIGHT_RECEIVE, -1);
75 		T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "receive -= 1");
76 	}
77 }
78 
79 static void
send_port(mach_msg_id_t id,mach_port_t dest,mach_port_t right,mach_msg_type_name_t disp)80 send_port(
81 	mach_msg_id_t        id,
82 	mach_port_t          dest,
83 	mach_port_t          right,
84 	mach_msg_type_name_t disp)
85 {
86 	struct one_port_msg msg = {
87 		.header = {
88 			.msgh_remote_port = dest,
89 			.msgh_bits        = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_COPY_SEND,
90 	    0, MACH_MSG_TYPE_MOVE_SEND, MACH_MSGH_BITS_COMPLEX),
91 			.msgh_id          = id,
92 			.msgh_size        = offsetof(struct one_port_msg, trailer),
93 		},
94 		.body = {
95 			.msgh_descriptor_count = 1,
96 		},
97 		.port_descriptor = {
98 			.name        = right,
99 			.disposition = disp,
100 			.type        = MACH_MSG_PORT_DESCRIPTOR,
101 		},
102 	};
103 	kern_return_t kr;
104 
105 	kr = mach_msg(&msg.header, MACH_SEND_MSG | MACH_SEND_TIMEOUT,
106 	    msg.header.msgh_size, 0, MACH_PORT_NULL, 10000, 0);
107 
108 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "send(%d)", id);
109 }
110 
111 #pragma mark - basic test about right deduplication
112 
113 static mach_port_t
receive_port(mach_msg_id_t expected_id,mach_port_t rcv_port,mach_msg_type_name_t expected_disp)114 receive_port(
115 	mach_msg_id_t        expected_id,
116 	mach_port_t          rcv_port,
117 	mach_msg_type_name_t expected_disp)
118 {
119 	struct one_port_msg msg = { };
120 	kern_return_t kr;
121 
122 	T_LOG("waiting for message %d", expected_id);
123 	kr = mach_msg(&msg.header, MACH_RCV_MSG, 0,
124 	    sizeof(msg), rcv_port, 0, 0);
125 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "receive(%d)", expected_id);
126 	T_QUIET; T_ASSERT_EQ(msg.header.msgh_id, expected_id, "message id matches");
127 	T_QUIET; T_ASSERT_NE(msg.header.msgh_bits & MACH_MSGH_BITS_COMPLEX, 0,
128 	    "message is complex");
129 	T_QUIET; T_ASSERT_EQ(msg.body.msgh_descriptor_count, 1, "message has one right");
130 	T_QUIET; T_ASSERT_EQ((mach_msg_type_name_t)msg.port_descriptor.disposition, expected_disp,
131 	    "port has right disposition");
132 	return msg.port_descriptor.name;
133 }
134 
135 T_HELPER_DECL(right_dedup_server, "right_dedup_server")
136 {
137 	mach_port_t svc_port = server_checkin();
138 	mach_port_t ports[3];
139 
140 	ports[0] = receive_port(1, svc_port, MACH_MSG_TYPE_MOVE_RECEIVE);
141 	ports[1] = receive_port(2, svc_port, MACH_MSG_TYPE_MOVE_SEND);
142 	ports[2] = receive_port(3, svc_port, MACH_MSG_TYPE_MOVE_SEND);
143 	T_ASSERT_EQ(ports[0], ports[1], "receive, send, send");
144 	T_ASSERT_EQ(ports[0], ports[2], "receive, send, send");
145 	destroy_port(ports[0], true, 2);
146 
147 	ports[0] = receive_port(4, svc_port, MACH_MSG_TYPE_MOVE_SEND);
148 	ports[1] = receive_port(5, svc_port, MACH_MSG_TYPE_MOVE_RECEIVE);
149 	ports[2] = receive_port(6, svc_port, MACH_MSG_TYPE_MOVE_SEND);
150 	T_ASSERT_EQ(ports[0], ports[1], "send, receive, send");
151 	T_ASSERT_EQ(ports[0], ports[2], "send, receive, send");
152 	destroy_port(ports[0], true, 2);
153 
154 	ports[0] = receive_port(7, svc_port, MACH_MSG_TYPE_MOVE_SEND);
155 	ports[1] = receive_port(8, svc_port, MACH_MSG_TYPE_MOVE_SEND);
156 	ports[2] = receive_port(9, svc_port, MACH_MSG_TYPE_MOVE_RECEIVE);
157 	T_ASSERT_EQ(ports[0], ports[1], "send, send, receive");
158 	T_ASSERT_EQ(ports[0], ports[2], "send, send, receive");
159 	destroy_port(ports[0], true, 2);
160 
161 	T_END;
162 }
163 
164 T_HELPER_DECL(right_dedup_client, "right_dedup_client")
165 {
166 	mach_port_t svc_port = server_lookup();
167 	mach_port_t port;
168 
169 	port = make_sr_port();
170 	send_port(1, svc_port, port, MACH_MSG_TYPE_MOVE_RECEIVE);
171 	send_port(2, svc_port, port, MACH_MSG_TYPE_COPY_SEND);
172 	send_port(3, svc_port, port, MACH_MSG_TYPE_MOVE_SEND);
173 
174 	port = make_sr_port();
175 	send_port(4, svc_port, port, MACH_MSG_TYPE_COPY_SEND);
176 	send_port(5, svc_port, port, MACH_MSG_TYPE_MOVE_RECEIVE);
177 	send_port(6, svc_port, port, MACH_MSG_TYPE_MOVE_SEND);
178 
179 	port = make_sr_port();
180 	send_port(7, svc_port, port, MACH_MSG_TYPE_COPY_SEND);
181 	send_port(8, svc_port, port, MACH_MSG_TYPE_MOVE_SEND);
182 	send_port(9, svc_port, port, MACH_MSG_TYPE_MOVE_RECEIVE);
183 }
184 
185 T_DECL(right_dedup, "make sure right deduplication works")
186 {
187 	dt_helper_t helpers[] = {
188 		dt_launchd_helper_domain("com.apple.xnu.test.mach_port.plist",
189 	    "right_dedup_server", NULL, LAUNCH_SYSTEM_DOMAIN),
190 		dt_fork_helper("right_dedup_client"),
191 	};
192 	dt_run_helpers(helpers, 2, 600);
193 }
194