xref: /xnu-11417.140.69/tests/netagent_race_infodisc_56244905.c (revision 43a90889846e00bfb5cf1d255cdc0a701a1e05a4)
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(&reg_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(&reg_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