xref: /xnu-8792.81.2/tests/kqueue_port_tests.c (revision 19c3b8c28c31cb8130e034cfb5df6bf9ba342d90)
1*19c3b8c2SApple OSS Distributions #include <unistd.h>
2*19c3b8c2SApple OSS Distributions #include <pthread.h>
3*19c3b8c2SApple OSS Distributions #include <errno.h>
4*19c3b8c2SApple OSS Distributions 
5*19c3b8c2SApple OSS Distributions #include <sys/event.h>
6*19c3b8c2SApple OSS Distributions #include <mach/mach.h>
7*19c3b8c2SApple OSS Distributions #include <mach/mach_port.h>
8*19c3b8c2SApple OSS Distributions 
9*19c3b8c2SApple OSS Distributions #include <Block.h>
10*19c3b8c2SApple OSS Distributions #include <darwintest.h>
11*19c3b8c2SApple OSS Distributions 
12*19c3b8c2SApple OSS Distributions T_GLOBAL_META(
13*19c3b8c2SApple OSS Distributions 	T_META_NAMESPACE("xnu.kevent"),
14*19c3b8c2SApple OSS Distributions 	T_META_RADAR_COMPONENT_NAME("xnu"),
15*19c3b8c2SApple OSS Distributions 	T_META_RADAR_COMPONENT_VERSION("kevent"),
16*19c3b8c2SApple OSS Distributions 	T_META_RUN_CONCURRENTLY(true)
17*19c3b8c2SApple OSS Distributions 	);
18*19c3b8c2SApple OSS Distributions 
19*19c3b8c2SApple OSS Distributions static void
send(mach_port_t send_port)20*19c3b8c2SApple OSS Distributions send(mach_port_t send_port)
21*19c3b8c2SApple OSS Distributions {
22*19c3b8c2SApple OSS Distributions 	kern_return_t kr = 0;
23*19c3b8c2SApple OSS Distributions 	mach_msg_base_t msg = {
24*19c3b8c2SApple OSS Distributions 		.header = {
25*19c3b8c2SApple OSS Distributions 			.msgh_remote_port = send_port,
26*19c3b8c2SApple OSS Distributions 			.msgh_bits        = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_COPY_SEND,
27*19c3b8c2SApple OSS Distributions 	    0, MACH_MSG_TYPE_MOVE_SEND, 0),
28*19c3b8c2SApple OSS Distributions 			.msgh_id          = 0x100,
29*19c3b8c2SApple OSS Distributions 			.msgh_size        = sizeof(msg),
30*19c3b8c2SApple OSS Distributions 		},
31*19c3b8c2SApple OSS Distributions 	};
32*19c3b8c2SApple OSS Distributions 
33*19c3b8c2SApple OSS Distributions 	kr = mach_msg(&msg.header, MACH_SEND_MSG | MACH_SEND_TIMEOUT,
34*19c3b8c2SApple OSS Distributions 	    msg.header.msgh_size, 0, MACH_PORT_NULL, 10000, 0);
35*19c3b8c2SApple OSS Distributions 
36*19c3b8c2SApple OSS Distributions 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "client mach_msg");
37*19c3b8c2SApple OSS Distributions }
38*19c3b8c2SApple OSS Distributions 
39*19c3b8c2SApple OSS Distributions static kern_return_t
receive(mach_port_t rcv_port)40*19c3b8c2SApple OSS Distributions receive(mach_port_t rcv_port)
41*19c3b8c2SApple OSS Distributions {
42*19c3b8c2SApple OSS Distributions 	mach_msg_base_t msg = {
43*19c3b8c2SApple OSS Distributions 		.header = {
44*19c3b8c2SApple OSS Distributions 			.msgh_remote_port = MACH_PORT_NULL,
45*19c3b8c2SApple OSS Distributions 			.msgh_local_port  = rcv_port,
46*19c3b8c2SApple OSS Distributions 			.msgh_size        = sizeof(msg),
47*19c3b8c2SApple OSS Distributions 		},
48*19c3b8c2SApple OSS Distributions 	};
49*19c3b8c2SApple OSS Distributions 
50*19c3b8c2SApple OSS Distributions 	return mach_msg(&msg.header, MACH_RCV_MSG | MACH_RCV_TIMEOUT,
51*19c3b8c2SApple OSS Distributions 	           0, msg.header.msgh_size, rcv_port, 5000, 0);
52*19c3b8c2SApple OSS Distributions }
53*19c3b8c2SApple OSS Distributions 
54*19c3b8c2SApple OSS Distributions static void
fill_kevent(struct kevent * ke,uint16_t action,mach_port_t mp)55*19c3b8c2SApple OSS Distributions fill_kevent(struct kevent *ke, uint16_t action, mach_port_t mp)
56*19c3b8c2SApple OSS Distributions {
57*19c3b8c2SApple OSS Distributions 	*ke = (struct kevent){
58*19c3b8c2SApple OSS Distributions 		.filter = EVFILT_MACHPORT,
59*19c3b8c2SApple OSS Distributions 		.flags  = action,
60*19c3b8c2SApple OSS Distributions 		.ident  = mp,
61*19c3b8c2SApple OSS Distributions 	};
62*19c3b8c2SApple OSS Distributions }
63*19c3b8c2SApple OSS Distributions 
64*19c3b8c2SApple OSS Distributions #define TS(s) (struct timespec){ .tv_sec = s }
65*19c3b8c2SApple OSS Distributions 
66*19c3b8c2SApple OSS Distributions static void *
pthread_async_do(void * arg)67*19c3b8c2SApple OSS Distributions pthread_async_do(void *arg)
68*19c3b8c2SApple OSS Distributions {
69*19c3b8c2SApple OSS Distributions 	void (^block)(void) = arg;
70*19c3b8c2SApple OSS Distributions 	block();
71*19c3b8c2SApple OSS Distributions 	Block_release(block);
72*19c3b8c2SApple OSS Distributions 	pthread_detach(pthread_self());
73*19c3b8c2SApple OSS Distributions 	return NULL;
74*19c3b8c2SApple OSS Distributions }
75*19c3b8c2SApple OSS Distributions 
76*19c3b8c2SApple OSS Distributions static void
77*19c3b8c2SApple OSS Distributions pthread_async(void (^block)(void))
78*19c3b8c2SApple OSS Distributions {
79*19c3b8c2SApple OSS Distributions 	pthread_t th;
80*19c3b8c2SApple OSS Distributions 	int rc;
81*19c3b8c2SApple OSS Distributions 
82*19c3b8c2SApple OSS Distributions 	rc = pthread_create(&th, NULL, pthread_async_do, Block_copy(block));
83*19c3b8c2SApple OSS Distributions 	T_QUIET; T_ASSERT_POSIX_SUCCESS(rc, "pthread_create");
84*19c3b8c2SApple OSS Distributions }
85*19c3b8c2SApple OSS Distributions 
86*19c3b8c2SApple OSS Distributions T_DECL(kqueue_machport, "basic EVFILT_MACHPORT tests")
87*19c3b8c2SApple OSS Distributions {
88*19c3b8c2SApple OSS Distributions 	mach_port_options_t opts = {
89*19c3b8c2SApple OSS Distributions 		.flags = MPO_INSERT_SEND_RIGHT,
90*19c3b8c2SApple OSS Distributions 	};
91*19c3b8c2SApple OSS Distributions 	mach_port_t mp, pset;
92*19c3b8c2SApple OSS Distributions 	kern_return_t kr;
93*19c3b8c2SApple OSS Distributions 	struct kevent ke[2];
94*19c3b8c2SApple OSS Distributions 	int kq, rc;
95*19c3b8c2SApple OSS Distributions 
96*19c3b8c2SApple OSS Distributions 	kr = mach_port_construct(mach_task_self(), &opts, 0, &mp);
97*19c3b8c2SApple OSS Distributions 	T_EXPECT_MACH_SUCCESS(kr, "mach_port_construct()");
98*19c3b8c2SApple OSS Distributions 
99*19c3b8c2SApple OSS Distributions 	kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_PORT_SET, &pset);
100*19c3b8c2SApple OSS Distributions 	T_EXPECT_MACH_SUCCESS(kr, "mach_port_allocate(PSET)");
101*19c3b8c2SApple OSS Distributions 
102*19c3b8c2SApple OSS Distributions 	kr = mach_port_move_member(mach_task_self(), mp, pset);
103*19c3b8c2SApple OSS Distributions 	T_EXPECT_MACH_SUCCESS(kr, "mach_port_move_member(PORT, PSET)");
104*19c3b8c2SApple OSS Distributions 
105*19c3b8c2SApple OSS Distributions 	kq = kqueue();
106*19c3b8c2SApple OSS Distributions 	T_EXPECT_POSIX_SUCCESS(kq, "kqueue()");
107*19c3b8c2SApple OSS Distributions 
108*19c3b8c2SApple OSS Distributions 	/*
109*19c3b8c2SApple OSS Distributions 	 * Fired when attached
110*19c3b8c2SApple OSS Distributions 	 */
111*19c3b8c2SApple OSS Distributions 	send(mp);
112*19c3b8c2SApple OSS Distributions 
113*19c3b8c2SApple OSS Distributions 	fill_kevent(&ke[0], EV_ADD, mp);
114*19c3b8c2SApple OSS Distributions 	fill_kevent(&ke[1], EV_ADD, pset);
115*19c3b8c2SApple OSS Distributions 	rc = kevent(kq, ke, 2, NULL, 0, &TS(5));
116*19c3b8c2SApple OSS Distributions 	T_EXPECT_POSIX_SUCCESS(rc, "kevent(registration)");
117*19c3b8c2SApple OSS Distributions 
118*19c3b8c2SApple OSS Distributions 	rc = kevent(kq, NULL, 0, ke, 2, &TS(5));
119*19c3b8c2SApple OSS Distributions 	T_EXPECT_EQ(rc, 2, "kevent(fired at attach time)");
120*19c3b8c2SApple OSS Distributions 
121*19c3b8c2SApple OSS Distributions 	receive(mp);
122*19c3b8c2SApple OSS Distributions 	rc = kevent(kq, NULL, 0, ke, 2, &TS(1));
123*19c3b8c2SApple OSS Distributions 	T_EXPECT_EQ(rc, 0, "no event");
124*19c3b8c2SApple OSS Distributions 
125*19c3b8c2SApple OSS Distributions 	/*
126*19c3b8c2SApple OSS Distributions 	 * Fired after being attached, before wait
127*19c3b8c2SApple OSS Distributions 	 */
128*19c3b8c2SApple OSS Distributions 	send(mp);
129*19c3b8c2SApple OSS Distributions 	rc = kevent(kq, NULL, 0, ke, 2, &TS(5));
130*19c3b8c2SApple OSS Distributions 	T_EXPECT_EQ(rc, 2, "kevent(fired after attach time, before wait)");
131*19c3b8c2SApple OSS Distributions 
132*19c3b8c2SApple OSS Distributions 	receive(mp);
133*19c3b8c2SApple OSS Distributions 	rc = kevent(kq, NULL, 0, ke, 2, &TS(1));
134*19c3b8c2SApple OSS Distributions 	T_EXPECT_EQ(rc, 0, "no event");
135*19c3b8c2SApple OSS Distributions 
136*19c3b8c2SApple OSS Distributions 	/*
137*19c3b8c2SApple OSS Distributions 	 * Fired after being attached, after wait
138*19c3b8c2SApple OSS Distributions 	 */
139*19c3b8c2SApple OSS Distributions 	pthread_async(^{
140*19c3b8c2SApple OSS Distributions 		sleep(1);
141*19c3b8c2SApple OSS Distributions 		send(mp);
142*19c3b8c2SApple OSS Distributions 	});
143*19c3b8c2SApple OSS Distributions 	rc = kevent(kq, NULL, 0, ke, 2, &TS(5));
144*19c3b8c2SApple OSS Distributions 	T_EXPECT_EQ(rc, 2, "kevent(fired after attach time, after wait)");
145*19c3b8c2SApple OSS Distributions 
146*19c3b8c2SApple OSS Distributions 	receive(mp);
147*19c3b8c2SApple OSS Distributions 	rc = kevent(kq, NULL, 0, ke, 2, &TS(1));
148*19c3b8c2SApple OSS Distributions 	T_EXPECT_EQ(rc, 0, "no event");
149*19c3b8c2SApple OSS Distributions 
150*19c3b8c2SApple OSS Distributions 	/* Make sure destroying ports wakes you up */
151*19c3b8c2SApple OSS Distributions 	pthread_async(^{
152*19c3b8c2SApple OSS Distributions 		sleep(1);
153*19c3b8c2SApple OSS Distributions 		T_EXPECT_MACH_SUCCESS(mach_port_destruct(mach_task_self(), mp, -1, 0),
154*19c3b8c2SApple OSS Distributions 		"mach_port_destruct");
155*19c3b8c2SApple OSS Distributions 	});
156*19c3b8c2SApple OSS Distributions 	rc = kevent(kq, NULL, 0, ke, 2, &TS(5));
157*19c3b8c2SApple OSS Distributions 	T_EXPECT_EQ(rc, 1, "kevent(port-destroyed)");
158*19c3b8c2SApple OSS Distributions 	T_EXPECT_EQ(ke[0].ident, (uintptr_t)mp, "event was for the port");
159*19c3b8c2SApple OSS Distributions 
160*19c3b8c2SApple OSS Distributions 	pthread_async(^{
161*19c3b8c2SApple OSS Distributions 		sleep(1);
162*19c3b8c2SApple OSS Distributions 		T_EXPECT_MACH_SUCCESS(mach_port_mod_refs(mach_task_self(), pset,
163*19c3b8c2SApple OSS Distributions 		MACH_PORT_RIGHT_PORT_SET, -1), "destroy pset");
164*19c3b8c2SApple OSS Distributions 	});
165*19c3b8c2SApple OSS Distributions 	rc = kevent(kq, NULL, 0, ke, 2, &TS(5));
166*19c3b8c2SApple OSS Distributions 	T_EXPECT_EQ(rc, 1, "kevent(port-destroyed)");
167*19c3b8c2SApple OSS Distributions 	T_EXPECT_EQ(ke[0].ident, (uintptr_t)pset, "event was for the pset");
168*19c3b8c2SApple OSS Distributions }
169*19c3b8c2SApple OSS Distributions 
170*19c3b8c2SApple OSS Distributions static int
kevent_attach_event(mach_port_t port,uint16_t flags,uint32_t fflags,int * error)171*19c3b8c2SApple OSS Distributions kevent_attach_event(mach_port_t port, uint16_t flags, uint32_t fflags, int *error)
172*19c3b8c2SApple OSS Distributions {
173*19c3b8c2SApple OSS Distributions 	int rc;
174*19c3b8c2SApple OSS Distributions 
175*19c3b8c2SApple OSS Distributions 	struct kevent_qos_s kev = {
176*19c3b8c2SApple OSS Distributions 		.ident = port,
177*19c3b8c2SApple OSS Distributions 		.filter = EVFILT_MACHPORT,
178*19c3b8c2SApple OSS Distributions 		.flags = flags,
179*19c3b8c2SApple OSS Distributions 		.qos = 0xA00,
180*19c3b8c2SApple OSS Distributions 		.udata = 0x6666666666666666,
181*19c3b8c2SApple OSS Distributions 		.fflags = fflags,
182*19c3b8c2SApple OSS Distributions 	};
183*19c3b8c2SApple OSS Distributions 
184*19c3b8c2SApple OSS Distributions 	struct kevent_qos_s kev_err = {};
185*19c3b8c2SApple OSS Distributions 
186*19c3b8c2SApple OSS Distributions 	rc = kevent_id(0x88888887, &kev, 1, &kev_err, 1, NULL, NULL,
187*19c3b8c2SApple OSS Distributions 	    KEVENT_FLAG_WORKLOOP  | KEVENT_FLAG_ERROR_EVENTS);
188*19c3b8c2SApple OSS Distributions 
189*19c3b8c2SApple OSS Distributions 	*error = (int)kev_err.data;
190*19c3b8c2SApple OSS Distributions 	return rc;
191*19c3b8c2SApple OSS Distributions }
192*19c3b8c2SApple OSS Distributions 
193*19c3b8c2SApple OSS Distributions /* rdar://95680295 (Turnstile Use-after-Free in XNU) */
194*19c3b8c2SApple OSS Distributions T_DECL(kqueue_machport_no_toggle_flags, "don't allow turnstile flags to be toggled for EVFILT_MACHPORT")
195*19c3b8c2SApple OSS Distributions {
196*19c3b8c2SApple OSS Distributions 	kern_return_t kr;
197*19c3b8c2SApple OSS Distributions 	int rc, error = 0;
198*19c3b8c2SApple OSS Distributions 	mach_port_t port = MACH_PORT_NULL;
199*19c3b8c2SApple OSS Distributions 
200*19c3b8c2SApple OSS Distributions 	kr = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port);
201*19c3b8c2SApple OSS Distributions 	T_EXPECT_MACH_SUCCESS(kr, "mach_port_allocate()");
202*19c3b8c2SApple OSS Distributions 
203*19c3b8c2SApple OSS Distributions 	rc = kevent_attach_event(port, EV_ADD | EV_ENABLE | EV_DISPATCH, 0, &error);
204*19c3b8c2SApple OSS Distributions 	T_EXPECT_EQ(rc, 0, "kevent attach event");
205*19c3b8c2SApple OSS Distributions 
206*19c3b8c2SApple OSS Distributions 	rc = kevent_attach_event(port, 0, MACH_RCV_MSG, &error);
207*19c3b8c2SApple OSS Distributions 	T_QUIET; T_EXPECT_EQ_INT(rc, 1, "registration failed");
208*19c3b8c2SApple OSS Distributions 	T_EXPECT_EQ_INT(error, EINVAL, "cannot modify filter flag MACH_RCV_MSG");
209*19c3b8c2SApple OSS Distributions 
210*19c3b8c2SApple OSS Distributions 	rc = kevent_attach_event(port, 0, MACH_RCV_SYNC_PEEK, &error);
211*19c3b8c2SApple OSS Distributions 	T_QUIET; T_EXPECT_EQ_INT(rc, 1, "registration failed");
212*19c3b8c2SApple OSS Distributions 	T_EXPECT_EQ_INT(error, EINVAL, "cannot modify filter flag MACH_RCV_SYNC_PEEK");
213*19c3b8c2SApple OSS Distributions }
214