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