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