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