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