xref: /xnu-8792.41.9/tests/netagent_race_infodisc_56244905.c (revision 5c2921b07a2480ab43ec66f5b9e41cb872bc554f) !
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(&reg_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(&reg_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