1*0f4c859eSApple OSS Distributions /*
2*0f4c859eSApple OSS Distributions * Test based on POC attached to rdar://96567281 (Knote Use-after-Free in XNU)
3*0f4c859eSApple OSS Distributions *
4*0f4c859eSApple OSS Distributions */
5*0f4c859eSApple OSS Distributions #include <darwintest.h>
6*0f4c859eSApple OSS Distributions #include <mach/mach.h>
7*0f4c859eSApple OSS Distributions #include <pthread.h>
8*0f4c859eSApple OSS Distributions #include <sys/event.h>
9*0f4c859eSApple OSS Distributions #include <stdlib.h>
10*0f4c859eSApple OSS Distributions
11*0f4c859eSApple OSS Distributions T_GLOBAL_META(
12*0f4c859eSApple OSS Distributions T_META_NAMESPACE("xnu.ipc"),
13*0f4c859eSApple OSS Distributions T_META_RADAR_COMPONENT_NAME("xnu"),
14*0f4c859eSApple OSS Distributions T_META_RADAR_COMPONENT_VERSION("IPC"),
15*0f4c859eSApple OSS Distributions T_META_RUN_CONCURRENTLY(TRUE));
16*0f4c859eSApple OSS Distributions
17*0f4c859eSApple OSS Distributions typedef struct knote_context_s knote_context_t;
18*0f4c859eSApple OSS Distributions struct knote_context_s {
19*0f4c859eSApple OSS Distributions volatile int initialized;
20*0f4c859eSApple OSS Distributions volatile int start;
21*0f4c859eSApple OSS Distributions };
22*0f4c859eSApple OSS Distributions
23*0f4c859eSApple OSS Distributions static void *
th_allocate_knotes(void * arg)24*0f4c859eSApple OSS Distributions th_allocate_knotes(void *arg)
25*0f4c859eSApple OSS Distributions {
26*0f4c859eSApple OSS Distributions knote_context_t *context = (knote_context_t *)arg;
27*0f4c859eSApple OSS Distributions kern_return_t kr = KERN_SUCCESS;
28*0f4c859eSApple OSS Distributions T_QUIET; T_ASSERT_EQ(context->initialized, (int)0, "th_allocate_knotes context is initialized.");
29*0f4c859eSApple OSS Distributions
30*0f4c859eSApple OSS Distributions mach_port_t sync_port = MACH_PORT_NULL;
31*0f4c859eSApple OSS Distributions kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &sync_port);
32*0f4c859eSApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "mach_port_allocate sync_port");
33*0f4c859eSApple OSS Distributions
34*0f4c859eSApple OSS Distributions mach_port_t kq_port = MACH_PORT_NULL;
35*0f4c859eSApple OSS Distributions kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &kq_port);
36*0f4c859eSApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "mach_port_allocate kq_port");
37*0f4c859eSApple OSS Distributions
38*0f4c859eSApple OSS Distributions int kq = kqueue();
39*0f4c859eSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(kq, "kqueue");
40*0f4c859eSApple OSS Distributions
41*0f4c859eSApple OSS Distributions #define PORTS_COUNT 0x1000
42*0f4c859eSApple OSS Distributions
43*0f4c859eSApple OSS Distributions mach_port_t *ports = calloc(PORTS_COUNT, sizeof(mach_port_t));
44*0f4c859eSApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(ports, "calloc");
45*0f4c859eSApple OSS Distributions
46*0f4c859eSApple OSS Distributions for (size_t i = 0; i < PORTS_COUNT; i++) {
47*0f4c859eSApple OSS Distributions mach_port_t port = MACH_PORT_NULL;
48*0f4c859eSApple OSS Distributions kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port);
49*0f4c859eSApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "mach_port_allocate");
50*0f4c859eSApple OSS Distributions
51*0f4c859eSApple OSS Distributions typedef struct move_receive_request_s move_receive_request_t;
52*0f4c859eSApple OSS Distributions typedef struct move_receive_reply_s move_receive_reply_t;
53*0f4c859eSApple OSS Distributions
54*0f4c859eSApple OSS Distributions struct move_receive_request_s {
55*0f4c859eSApple OSS Distributions mach_msg_header_t header;
56*0f4c859eSApple OSS Distributions mach_msg_body_t body;
57*0f4c859eSApple OSS Distributions mach_msg_port_descriptor_t port;
58*0f4c859eSApple OSS Distributions mach_msg_port_descriptor_t kq_port;
59*0f4c859eSApple OSS Distributions };
60*0f4c859eSApple OSS Distributions
61*0f4c859eSApple OSS Distributions struct move_receive_reply_s {
62*0f4c859eSApple OSS Distributions mach_msg_header_t header;
63*0f4c859eSApple OSS Distributions mach_msg_body_t body;
64*0f4c859eSApple OSS Distributions mach_msg_port_descriptor_t port;
65*0f4c859eSApple OSS Distributions mach_msg_port_descriptor_t kq_port;
66*0f4c859eSApple OSS Distributions mach_msg_trailer_t trailer;
67*0f4c859eSApple OSS Distributions };
68*0f4c859eSApple OSS Distributions
69*0f4c859eSApple OSS Distributions union {
70*0f4c859eSApple OSS Distributions move_receive_request_t request;
71*0f4c859eSApple OSS Distributions move_receive_reply_t reply;
72*0f4c859eSApple OSS Distributions } message;
73*0f4c859eSApple OSS Distributions
74*0f4c859eSApple OSS Distributions move_receive_request_t *request = &message.request;
75*0f4c859eSApple OSS Distributions move_receive_reply_t *reply = &message.reply;
76*0f4c859eSApple OSS Distributions
77*0f4c859eSApple OSS Distributions request->header = (mach_msg_header_t){
78*0f4c859eSApple OSS Distributions .msgh_remote_port = sync_port,
79*0f4c859eSApple OSS Distributions .msgh_local_port = MACH_PORT_NULL,
80*0f4c859eSApple OSS Distributions .msgh_voucher_port = MACH_PORT_NULL,
81*0f4c859eSApple OSS Distributions .msgh_id = (mach_msg_id_t)0x88888888,
82*0f4c859eSApple OSS Distributions .msgh_size = sizeof(*request),
83*0f4c859eSApple OSS Distributions .msgh_bits = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_MAKE_SEND, 0, 0, MACH_MSGH_BITS_COMPLEX),
84*0f4c859eSApple OSS Distributions };
85*0f4c859eSApple OSS Distributions
86*0f4c859eSApple OSS Distributions request->body = (mach_msg_body_t){
87*0f4c859eSApple OSS Distributions .msgh_descriptor_count = 2,
88*0f4c859eSApple OSS Distributions };
89*0f4c859eSApple OSS Distributions
90*0f4c859eSApple OSS Distributions request->port = (mach_msg_port_descriptor_t){
91*0f4c859eSApple OSS Distributions .name = port,
92*0f4c859eSApple OSS Distributions .disposition = MACH_MSG_TYPE_MOVE_RECEIVE,
93*0f4c859eSApple OSS Distributions .type = MACH_MSG_PORT_DESCRIPTOR,
94*0f4c859eSApple OSS Distributions };
95*0f4c859eSApple OSS Distributions request->kq_port = (mach_msg_port_descriptor_t){
96*0f4c859eSApple OSS Distributions .name = kq_port,
97*0f4c859eSApple OSS Distributions .disposition = MACH_MSG_TYPE_MOVE_RECEIVE,
98*0f4c859eSApple OSS Distributions .type = MACH_MSG_PORT_DESCRIPTOR,
99*0f4c859eSApple OSS Distributions };
100*0f4c859eSApple OSS Distributions
101*0f4c859eSApple OSS Distributions kr = mach_msg(&request->header, MACH_SEND_MSG, sizeof(*request), 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
102*0f4c859eSApple OSS Distributions T_QUIET; T_ASSERT_EQ(kr, MACH_MSG_SUCCESS, "mach_msg");
103*0f4c859eSApple OSS Distributions
104*0f4c859eSApple OSS Distributions struct kevent_qos_s event = {
105*0f4c859eSApple OSS Distributions .ident = sync_port,
106*0f4c859eSApple OSS Distributions .filter = EVFILT_MACHPORT,
107*0f4c859eSApple OSS Distributions .flags = EV_ADD | EV_ENABLE | EV_DISPATCH,
108*0f4c859eSApple OSS Distributions .qos = 0xA00,
109*0f4c859eSApple OSS Distributions .udata = 0x42424242,
110*0f4c859eSApple OSS Distributions .fflags = MACH_RCV_MSG,
111*0f4c859eSApple OSS Distributions .xflags = 0x00,
112*0f4c859eSApple OSS Distributions .data = 0x00,
113*0f4c859eSApple OSS Distributions .ext = {(uint64_t)reply, sizeof(*reply), 0, 0},
114*0f4c859eSApple OSS Distributions };
115*0f4c859eSApple OSS Distributions
116*0f4c859eSApple OSS Distributions struct kevent_qos_s out_events[1];
117*0f4c859eSApple OSS Distributions
118*0f4c859eSApple OSS Distributions int nevents = kevent_qos(kq, &event, 1, out_events, 1, NULL, NULL, 0);
119*0f4c859eSApple OSS Distributions T_QUIET; T_ASSERT_EQ(nevents, (int)1, "kevent_qos");
120*0f4c859eSApple OSS Distributions T_QUIET; T_ASSERT_EQ(out_events[0].udata, (uint64_t)0x42424242, "kevent_qos");
121*0f4c859eSApple OSS Distributions T_QUIET; T_ASSERT_BITS_SET(reply->header.msgh_bits, MACH_MSGH_BITS_COMPLEX, "message is complex");
122*0f4c859eSApple OSS Distributions T_QUIET; T_ASSERT_EQ(reply->body.msgh_descriptor_count, (mach_msg_size_t)2, "mach_msg");
123*0f4c859eSApple OSS Distributions
124*0f4c859eSApple OSS Distributions ports[i] = reply->port.name;
125*0f4c859eSApple OSS Distributions kq_port = reply->kq_port.name;
126*0f4c859eSApple OSS Distributions }
127*0f4c859eSApple OSS Distributions
128*0f4c859eSApple OSS Distributions context->initialized = 1;
129*0f4c859eSApple OSS Distributions while (!context->start) {
130*0f4c859eSApple OSS Distributions }
131*0f4c859eSApple OSS Distributions
132*0f4c859eSApple OSS Distributions for (size_t i = 0; i < PORTS_COUNT; i++) {
133*0f4c859eSApple OSS Distributions uint32_t wl_id = (uint32_t)0x99999999;
134*0f4c859eSApple OSS Distributions
135*0f4c859eSApple OSS Distributions struct kevent_qos_s event = {
136*0f4c859eSApple OSS Distributions .ident = ports[i],
137*0f4c859eSApple OSS Distributions .filter = EVFILT_WORKLOOP,
138*0f4c859eSApple OSS Distributions .flags = EV_ADD | EV_DISABLE,
139*0f4c859eSApple OSS Distributions .qos = 0x00,
140*0f4c859eSApple OSS Distributions .udata = 0x88888888,
141*0f4c859eSApple OSS Distributions .fflags = NOTE_WL_SYNC_IPC,
142*0f4c859eSApple OSS Distributions .xflags = 0x00,
143*0f4c859eSApple OSS Distributions .data = 0x66666666,
144*0f4c859eSApple OSS Distributions .ext = {0x00, 0x00, 0x00, 0x00},
145*0f4c859eSApple OSS Distributions };
146*0f4c859eSApple OSS Distributions struct kevent_qos_s output = { };
147*0f4c859eSApple OSS Distributions int ret = kevent_id(wl_id, &event, 1, &output, 1, NULL, NULL,
148*0f4c859eSApple OSS Distributions KEVENT_FLAG_WORKLOOP | KEVENT_FLAG_ERROR_EVENTS);
149*0f4c859eSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "kevent_id");
150*0f4c859eSApple OSS Distributions }
151*0f4c859eSApple OSS Distributions return NULL;
152*0f4c859eSApple OSS Distributions }
153*0f4c859eSApple OSS Distributions
154*0f4c859eSApple OSS Distributions T_DECL(test_knote_use_after_free,
155*0f4c859eSApple OSS Distributions "Verify knote use-after-free issue does not reproduce - rdar://96567281 (Knote Use-after-Free in XNU)",
156*0f4c859eSApple OSS Distributions T_META_CHECK_LEAKS(false))
157*0f4c859eSApple OSS Distributions {
158*0f4c859eSApple OSS Distributions mach_port_t task = mach_task_self();
159*0f4c859eSApple OSS Distributions
160*0f4c859eSApple OSS Distributions knote_context_t context = {
161*0f4c859eSApple OSS Distributions .initialized = 0,
162*0f4c859eSApple OSS Distributions .start = 0,
163*0f4c859eSApple OSS Distributions };
164*0f4c859eSApple OSS Distributions
165*0f4c859eSApple OSS Distributions pthread_t thknote;
166*0f4c859eSApple OSS Distributions T_ASSERT_POSIX_ZERO(pthread_create(&thknote, NULL, th_allocate_knotes, &context), "pthread_create");
167*0f4c859eSApple OSS Distributions
168*0f4c859eSApple OSS Distributions int kq = kqueue();
169*0f4c859eSApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(kq, "kqueue");
170*0f4c859eSApple OSS Distributions
171*0f4c859eSApple OSS Distributions #define KNOTE_PORT_COUNT 2
172*0f4c859eSApple OSS Distributions
173*0f4c859eSApple OSS Distributions kern_return_t kr = KERN_SUCCESS;
174*0f4c859eSApple OSS Distributions mach_port_t sync_port = MACH_PORT_NULL, knote_port[KNOTE_PORT_COUNT];
175*0f4c859eSApple OSS Distributions kr = mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, &sync_port);
176*0f4c859eSApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "mach_port_allocate sync_port");
177*0f4c859eSApple OSS Distributions
178*0f4c859eSApple OSS Distributions for (size_t i = 0; i < KNOTE_PORT_COUNT; i++) {
179*0f4c859eSApple OSS Distributions knote_port[i] = MACH_PORT_NULL;
180*0f4c859eSApple OSS Distributions kr = mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, &knote_port[i]);
181*0f4c859eSApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "mach_port_allocate knote_port");
182*0f4c859eSApple OSS Distributions }
183*0f4c859eSApple OSS Distributions
184*0f4c859eSApple OSS Distributions typedef struct sync_knote_msg_local_s sync_knote_msg_local_t;
185*0f4c859eSApple OSS Distributions typedef struct sync_knote_msg_remote_s sync_knote_msg_remote_t;
186*0f4c859eSApple OSS Distributions
187*0f4c859eSApple OSS Distributions #pragma pack(4)
188*0f4c859eSApple OSS Distributions struct sync_knote_msg_local_s {
189*0f4c859eSApple OSS Distributions mach_msg_header_t header;
190*0f4c859eSApple OSS Distributions mach_msg_body_t body;
191*0f4c859eSApple OSS Distributions mach_msg_port_descriptor_t port[KNOTE_PORT_COUNT];
192*0f4c859eSApple OSS Distributions uint64_t sequence;
193*0f4c859eSApple OSS Distributions };
194*0f4c859eSApple OSS Distributions #pragma pack(0)
195*0f4c859eSApple OSS Distributions
196*0f4c859eSApple OSS Distributions #pragma pack(4)
197*0f4c859eSApple OSS Distributions struct sync_knote_msg_remote_s {
198*0f4c859eSApple OSS Distributions mach_msg_header_t header;
199*0f4c859eSApple OSS Distributions mach_msg_body_t body;
200*0f4c859eSApple OSS Distributions mach_msg_port_descriptor_t port[KNOTE_PORT_COUNT];
201*0f4c859eSApple OSS Distributions uint64_t sequence;
202*0f4c859eSApple OSS Distributions mach_msg_trailer_t trailer;
203*0f4c859eSApple OSS Distributions };
204*0f4c859eSApple OSS Distributions #pragma pack(0)
205*0f4c859eSApple OSS Distributions
206*0f4c859eSApple OSS Distributions union {
207*0f4c859eSApple OSS Distributions sync_knote_msg_local_t local;
208*0f4c859eSApple OSS Distributions sync_knote_msg_remote_t remote;
209*0f4c859eSApple OSS Distributions } message;
210*0f4c859eSApple OSS Distributions
211*0f4c859eSApple OSS Distributions sync_knote_msg_local_t *local = &message.local;
212*0f4c859eSApple OSS Distributions sync_knote_msg_remote_t *remote = &message.remote;
213*0f4c859eSApple OSS Distributions
214*0f4c859eSApple OSS Distributions local->header = (mach_msg_header_t){
215*0f4c859eSApple OSS Distributions .msgh_bits = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_MAKE_SEND, 0, 0, MACH_MSGH_BITS_COMPLEX),
216*0f4c859eSApple OSS Distributions .msgh_remote_port = sync_port,
217*0f4c859eSApple OSS Distributions .msgh_local_port = MACH_PORT_NULL,
218*0f4c859eSApple OSS Distributions .msgh_voucher_port = MACH_PORT_NULL,
219*0f4c859eSApple OSS Distributions .msgh_size = sizeof(sync_knote_msg_local_t),
220*0f4c859eSApple OSS Distributions .msgh_id = (mach_msg_id_t)0x88888888,
221*0f4c859eSApple OSS Distributions };
222*0f4c859eSApple OSS Distributions local->body.msgh_descriptor_count = KNOTE_PORT_COUNT;
223*0f4c859eSApple OSS Distributions for (size_t i = 0; i < KNOTE_PORT_COUNT; i++) {
224*0f4c859eSApple OSS Distributions local->port[i] = (mach_msg_port_descriptor_t){
225*0f4c859eSApple OSS Distributions .name = knote_port[i],
226*0f4c859eSApple OSS Distributions .disposition = MACH_MSG_TYPE_MOVE_RECEIVE,
227*0f4c859eSApple OSS Distributions .type = MACH_MSG_PORT_DESCRIPTOR,
228*0f4c859eSApple OSS Distributions };
229*0f4c859eSApple OSS Distributions }
230*0f4c859eSApple OSS Distributions local->sequence = 0x6666666666666666;
231*0f4c859eSApple OSS Distributions kr = mach_msg(&local->header, MACH_SEND_MSG, sizeof(sync_knote_msg_local_t), 0, MACH_PORT_NULL,
232*0f4c859eSApple OSS Distributions 0, MACH_PORT_NULL);
233*0f4c859eSApple OSS Distributions T_QUIET; T_ASSERT_EQ(kr, MACH_MSG_SUCCESS, "mach_msg");
234*0f4c859eSApple OSS Distributions
235*0f4c859eSApple OSS Distributions struct kevent_qos_s event = {
236*0f4c859eSApple OSS Distributions .ident = sync_port,
237*0f4c859eSApple OSS Distributions .filter = EVFILT_MACHPORT,
238*0f4c859eSApple OSS Distributions .flags = EV_ADD | EV_ENABLE | EV_DISPATCH,
239*0f4c859eSApple OSS Distributions .qos = 0xA00,
240*0f4c859eSApple OSS Distributions .udata = 42424242,
241*0f4c859eSApple OSS Distributions .fflags = MACH_RCV_MSG,
242*0f4c859eSApple OSS Distributions .xflags = 0x00,
243*0f4c859eSApple OSS Distributions .data = 0x00,
244*0f4c859eSApple OSS Distributions .ext = {(uint64_t)remote, sizeof(*remote), 0, 0},
245*0f4c859eSApple OSS Distributions };
246*0f4c859eSApple OSS Distributions
247*0f4c859eSApple OSS Distributions struct kevent_qos_s out_events[1];
248*0f4c859eSApple OSS Distributions
249*0f4c859eSApple OSS Distributions int nevents = kevent_qos(kq, &event, 1, out_events, 1, NULL, NULL, 0);
250*0f4c859eSApple OSS Distributions T_QUIET; T_ASSERT_EQ(nevents, (int)1, "kevent_qos nevents");
251*0f4c859eSApple OSS Distributions T_QUIET; T_ASSERT_EQ(remote->sequence, (uint64_t)0x6666666666666666, "kevent_qos remote->sequence");
252*0f4c859eSApple OSS Distributions
253*0f4c859eSApple OSS Distributions int ret = 0;
254*0f4c859eSApple OSS Distributions struct kevent_qos_s del_event = {
255*0f4c859eSApple OSS Distributions .ident = sync_port,
256*0f4c859eSApple OSS Distributions .filter = EVFILT_MACHPORT,
257*0f4c859eSApple OSS Distributions .flags = EV_DELETE,
258*0f4c859eSApple OSS Distributions .qos = 0xA00,
259*0f4c859eSApple OSS Distributions .udata = 0x00,
260*0f4c859eSApple OSS Distributions .fflags = MACH_RCV_MSG,
261*0f4c859eSApple OSS Distributions .xflags = 0x00,
262*0f4c859eSApple OSS Distributions .data = 0x00,
263*0f4c859eSApple OSS Distributions .ext = {0, 0, 0, 0},
264*0f4c859eSApple OSS Distributions };
265*0f4c859eSApple OSS Distributions
266*0f4c859eSApple OSS Distributions ret = kevent_qos(kq, &del_event, 1, NULL, 0, NULL, NULL, 0);
267*0f4c859eSApple OSS Distributions T_QUIET; T_ASSERT_EQ(ret, (int)0, "kevent_qos return");
268*0f4c859eSApple OSS Distributions
269*0f4c859eSApple OSS Distributions while (!context.initialized) {
270*0f4c859eSApple OSS Distributions }
271*0f4c859eSApple OSS Distributions
272*0f4c859eSApple OSS Distributions context.start = 1;
273*0f4c859eSApple OSS Distributions T_ASSERT_POSIX_ZERO(pthread_join(thknote, NULL), "pthread_join");
274*0f4c859eSApple OSS Distributions
275*0f4c859eSApple OSS Distributions kr = _kernelrpc_mach_port_insert_right_trap(task, sync_port, sync_port, MACH_MSG_TYPE_MOVE_RECEIVE);
276*0f4c859eSApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "_kernelrpc_mach_port_insert_right_trap");
277*0f4c859eSApple OSS Distributions }
278