1 #include <stdint.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <strings.h>
6
7 #include <fcntl.h>
8 #include <pthread.h>
9 #include <sys/kern_control.h>
10 #include <sys/kern_event.h>
11 #include <sys/ioctl.h>
12 #include <sys/socket.h>
13 #include <sys/sys_domain.h>
14 #include <unistd.h>
15 #include <uuid/uuid.h>
16
17 #include <darwintest.h>
18
19 static int finished = 0;
20
21 #ifndef KEV_NETAGENT_SUBCLASS
22 #define KEV_NETAGENT_SUBCLASS 9
23 #endif
24
25 #ifndef NETAGENT_MESSAGE_TYPE_REGISTER
26 #define NETAGENT_MESSAGE_TYPE_REGISTER 1
27 #endif
28
29 #ifndef NETAGENT_MESSAGE_TYPE_UNREGISTER
30 #define NETAGENT_MESSAGE_TYPE_UNREGISTER 2
31 #endif
32
33 struct netagent_message_header {
34 uint8_t message_type;
35 uint8_t message_flags;
36 uint32_t message_id;
37 uint32_t message_error;
38 uint32_t message_payload_length;
39 };
40
41 struct kev_msg {
42 uint32_t total_size;
43 uint32_t vendor_code;
44 uint32_t kev_class;
45 uint32_t kev_subclass;
46 uint32_t id;
47 uint32_t event_code;
48 };
49
50 struct kev_netagent_data {
51 uuid_t netagent_uuid;
52 };
53
54 struct netagent {
55 uuid_t netagent_uuid;
56 char netagent_domain[32];
57 char netagent_type[32];
58 char netagent_desc[128];
59 uint32_t netagent_flags;
60 uint32_t netagent_data_size;
61 /*uint8_t netagent_data[0];*/
62 };
63
64 static void *
register_sockopt_racer(void * data)65 register_sockopt_racer(void *data)
66 {
67 int s = *(int *)data;
68 struct {
69 struct netagent_message_header header;
70 struct netagent netagent;
71 } msg;
72
73 bzero(&msg, sizeof(msg));
74 msg.header.message_type = NETAGENT_MESSAGE_TYPE_REGISTER;
75 msg.header.message_payload_length = sizeof(struct netagent);
76
77 while (!finished) {
78 send(s, &msg, sizeof(msg), 0);
79 }
80
81 return NULL;
82 }
83
84 static void *
register_message_racer(void * data)85 register_message_racer(void *data)
86 {
87 int s = *(int *)data;
88 struct netagent netagent;
89
90 bzero(&netagent, sizeof(netagent));
91 while (!finished) {
92 setsockopt(s, SYSPROTO_CONTROL, NETAGENT_MESSAGE_TYPE_REGISTER, &netagent, sizeof(netagent));
93 }
94
95 return NULL;
96 }
97
98 #define SIZEOF_STRUCT_NETAGENT_WRAPPER 280
99
100 static void *
unregister_racer(void * data)101 unregister_racer(void *data)
102 {
103 int s = *(int *)data;
104 uint8_t spraybuf[SIZEOF_STRUCT_NETAGENT_WRAPPER];
105
106 memset(spraybuf, 0x41, sizeof(spraybuf));
107
108 while (!finished) {
109 setsockopt(s, SYSPROTO_CONTROL, NETAGENT_MESSAGE_TYPE_UNREGISTER, NULL, 0);
110 ioctl(-1, _IOW('x', 0, spraybuf), spraybuf);
111 }
112
113 return NULL;
114 }
115
116 #define NITERS 200000
117
118 static size_t
data_available(int sock)119 data_available(int sock)
120 {
121 int n = 0;
122 socklen_t nlen = sizeof(n);
123
124 getsockopt(sock, SOL_SOCKET, SO_NREAD, &n, &nlen);
125 return (size_t)n;
126 }
127
128 T_DECL(netagent_race_infodisc_56244905, "Netagent race between register and post event.")
129 {
130 int s;
131 int evsock;
132 pthread_t reg_th;
133 pthread_t unreg_th;
134 struct kev_request kev_req = {
135 .vendor_code = KEV_VENDOR_APPLE,
136 .kev_class = KEV_NETWORK_CLASS,
137 .kev_subclass = KEV_NETAGENT_SUBCLASS
138 };
139 struct ctl_info ci;
140 struct sockaddr_ctl sc;
141 struct {
142 struct kev_msg msg;
143 struct kev_netagent_data nd;
144 } ev;
145 int n;
146 int retry;
147 unsigned long leaked;
148
149 T_SETUPBEGIN;
150 /* set up the event socket so we can receive notifications: */
151 T_ASSERT_POSIX_SUCCESS(evsock = socket(AF_SYSTEM, SOCK_RAW, SYSPROTO_EVENT), NULL);
152 T_ASSERT_POSIX_SUCCESS(ioctl(evsock, SIOCSKEVFILT, &kev_req), NULL);
153
154 /* this is the socket we'll race on: */
155 T_ASSERT_POSIX_SUCCESS(s = socket(AF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL), NULL);
156
157 /* connect to netagent: */
158 bzero(&ci, sizeof(ci));
159 strcpy(ci.ctl_name, "com.apple.net.netagent");
160 T_ASSERT_POSIX_SUCCESS(ioctl(s, CTLIOCGINFO, &ci), NULL);
161
162 bzero(&sc, sizeof(sc));
163 sc.sc_id = ci.ctl_id;
164
165 T_ASSERT_POSIX_SUCCESS(connect(s, (const struct sockaddr *)&sc, sizeof(sc)), NULL);
166 T_SETUPEND;
167
168 /* variant 1: */
169 /* spin off the racer threads: */
170 T_ASSERT_POSIX_ZERO(pthread_create(®_th, NULL, register_message_racer, &s), NULL);
171 T_ASSERT_POSIX_ZERO(pthread_create(&unreg_th, NULL, unregister_racer, &s), NULL);
172
173 /* keep going until we're done: */
174 for (n = 0; n < NITERS; ++n) {
175 bzero(&ev, sizeof(ev));
176
177 for (retry = 0; retry < 20; ++retry) {
178 if (data_available(evsock) >= sizeof(ev) &&
179 sizeof(ev) == recv(evsock, &ev, sizeof(ev), 0)) {
180 goto check1;
181 }
182 }
183
184 continue;
185
186 check1:
187 if (ev.nd.netagent_uuid[0] != 0) {
188 finished = 1;
189 memcpy(&leaked, ev.nd.netagent_uuid, sizeof(leaked));
190 T_ASSERT_FAIL("netagent register event leaked data: 0x%08lx", leaked);
191 }
192
193 break;
194 }
195
196 finished = 1;
197
198 T_ASSERT_POSIX_ZERO(pthread_join(reg_th, NULL), NULL);
199 T_ASSERT_POSIX_ZERO(pthread_join(unreg_th, NULL), NULL);
200
201 finished = 0;
202
203 /* variant 2: */
204 /* spin off the racer threads: */
205 T_ASSERT_POSIX_ZERO(pthread_create(®_th, NULL, register_sockopt_racer, &s), NULL);
206 T_ASSERT_POSIX_ZERO(pthread_create(&unreg_th, NULL, unregister_racer, &s), NULL);
207
208 /* keep going until we're done: */
209 for (n = 0; n < NITERS; ++n) {
210 bzero(&ev, sizeof(ev));
211
212 for (retry = 0; retry < 20; ++retry) {
213 if (data_available(evsock) >= sizeof(ev) &&
214 sizeof(ev) == recv(evsock, &ev, sizeof(ev), 0)) {
215 goto check2;
216 }
217 }
218
219 continue;
220
221 check2:
222 if (ev.nd.netagent_uuid[0] != 0) {
223 finished = 1;
224 memcpy(&leaked, ev.nd.netagent_uuid, sizeof(leaked));
225 T_ASSERT_FAIL("netagent register event leaked data: 0x%08lx", leaked);
226 }
227
228 break;
229 }
230
231 finished = 1;
232
233 T_ASSERT_POSIX_ZERO(pthread_join(reg_th, NULL), NULL);
234 T_ASSERT_POSIX_ZERO(pthread_join(unreg_th, NULL), NULL);
235 }
236