xref: /linux/tools/testing/selftests/bpf/prog_tests/sock_destroy.c (revision 5fc5768c7ca92895ccd1de94dc521e5a55ae7896)
1 // SPDX-License-Identifier: GPL-2.0
2 #include <poll.h>
3 #include <test_progs.h>
4 #include <bpf/bpf_endian.h>
5 
6 #include "sock_destroy_prog.skel.h"
7 #include "sock_destroy_prog_fail.skel.h"
8 #include "network_helpers.h"
9 
10 #define TEST_NS "sock_destroy_netns"
11 
start_iter_sockets(struct bpf_program * prog)12 static void start_iter_sockets(struct bpf_program *prog)
13 {
14 	struct bpf_link *link;
15 	char buf[50] = {};
16 	int iter_fd, len;
17 
18 	link = bpf_program__attach_iter(prog, NULL);
19 	if (!ASSERT_OK_PTR(link, "attach_iter"))
20 		return;
21 
22 	iter_fd = bpf_iter_create(bpf_link__fd(link));
23 	if (!ASSERT_GE(iter_fd, 0, "create_iter"))
24 		goto free_link;
25 
26 	while ((len = read(iter_fd, buf, sizeof(buf))) > 0)
27 		;
28 	ASSERT_GE(len, 0, "read");
29 
30 	close(iter_fd);
31 
32 free_link:
33 	bpf_link__destroy(link);
34 }
35 
test_tcp_client(struct sock_destroy_prog * skel)36 static void test_tcp_client(struct sock_destroy_prog *skel)
37 {
38 	int serv = -1, clien = -1, accept_serv = -1, n;
39 
40 	serv = start_server(AF_INET6, SOCK_STREAM, NULL, 0, 0);
41 	if (!ASSERT_GE(serv, 0, "start_server"))
42 		goto cleanup;
43 
44 	clien = connect_to_fd(serv, 0);
45 	if (!ASSERT_GE(clien, 0, "connect_to_fd"))
46 		goto cleanup;
47 
48 	accept_serv = accept(serv, NULL, NULL);
49 	if (!ASSERT_GE(accept_serv, 0, "serv accept"))
50 		goto cleanup;
51 
52 	n = send(clien, "t", 1, 0);
53 	if (!ASSERT_EQ(n, 1, "client send"))
54 		goto cleanup;
55 
56 	/* Run iterator program that destroys connected client sockets. */
57 	start_iter_sockets(skel->progs.iter_tcp6_client);
58 
59 	n = send(clien, "t", 1, 0);
60 	if (!ASSERT_LT(n, 0, "client_send on destroyed socket"))
61 		goto cleanup;
62 	ASSERT_EQ(errno, ECONNABORTED, "error code on destroyed socket");
63 
64 cleanup:
65 	if (clien != -1)
66 		close(clien);
67 	if (accept_serv != -1)
68 		close(accept_serv);
69 	if (serv != -1)
70 		close(serv);
71 }
72 
test_tcp_server(struct sock_destroy_prog * skel)73 static void test_tcp_server(struct sock_destroy_prog *skel)
74 {
75 	int serv = -1, clien = -1, accept_serv = -1, n, serv_port;
76 
77 	serv = start_server(AF_INET6, SOCK_STREAM, NULL, 0, 0);
78 	if (!ASSERT_GE(serv, 0, "start_server"))
79 		goto cleanup;
80 	serv_port = get_socket_local_port(serv);
81 	if (!ASSERT_GE(serv_port, 0, "get_sock_local_port"))
82 		goto cleanup;
83 	skel->bss->serv_port = (__be16) serv_port;
84 
85 	clien = connect_to_fd(serv, 0);
86 	if (!ASSERT_GE(clien, 0, "connect_to_fd"))
87 		goto cleanup;
88 
89 	accept_serv = accept(serv, NULL, NULL);
90 	if (!ASSERT_GE(accept_serv, 0, "serv accept"))
91 		goto cleanup;
92 
93 	n = send(clien, "t", 1, 0);
94 	if (!ASSERT_EQ(n, 1, "client send"))
95 		goto cleanup;
96 
97 	/* Run iterator program that destroys server sockets. */
98 	start_iter_sockets(skel->progs.iter_tcp6_server);
99 
100 	n = send(clien, "t", 1, 0);
101 	if (!ASSERT_LT(n, 0, "client_send on destroyed socket"))
102 		goto cleanup;
103 	ASSERT_EQ(errno, ECONNRESET, "error code on destroyed socket");
104 
105 cleanup:
106 	if (clien != -1)
107 		close(clien);
108 	if (accept_serv != -1)
109 		close(accept_serv);
110 	if (serv != -1)
111 		close(serv);
112 }
113 
test_tcp_listen_pending(struct sock_destroy_prog * skel)114 static void test_tcp_listen_pending(struct sock_destroy_prog *skel)
115 {
116 	int serv = -1, clien = -1, accept_serv = -1, n, serv_port;
117 	struct pollfd pfd = { .events = POLLIN };
118 	char buf[1];
119 
120 	serv = start_server(AF_INET6, SOCK_STREAM, NULL, 0, 0);
121 	if (!ASSERT_GE(serv, 0, "start_server"))
122 		goto cleanup;
123 	serv_port = get_socket_local_port(serv);
124 	if (!ASSERT_GE(serv_port, 0, "get_sock_local_port"))
125 		goto cleanup;
126 	skel->bss->serv_port = (__be16)serv_port;
127 
128 	/*
129 	 * Connect but never accept, so the child sits in the accept queue
130 	 * of the listener. Wait until it's actually there.
131 	 */
132 	clien = connect_to_fd(serv, 0);
133 	if (!ASSERT_GE(clien, 0, "connect_to_fd"))
134 		goto cleanup;
135 	pfd.fd = serv;
136 	if (!ASSERT_EQ(poll(&pfd, 1, -1), 1, "poll listener"))
137 		goto cleanup;
138 
139 	/* Run iterator program that destroys server sockets. */
140 	start_iter_sockets(skel->progs.iter_tcp6_server);
141 
142 	accept_serv = accept(serv, NULL, NULL);
143 	if (!ASSERT_LT(accept_serv, 0, "accept on destroyed listener"))
144 		goto cleanup;
145 	ASSERT_EQ(errno, EINVAL, "error code on destroyed listener");
146 
147 	/* The unaccepted child was reset along with the listener. */
148 	n = recv(clien, buf, sizeof(buf), 0);
149 	if (!ASSERT_LT(n, 0, "client recv on reset child"))
150 		goto cleanup;
151 	ASSERT_EQ(errno, ECONNRESET, "error code on reset child");
152 
153 cleanup:
154 	if (clien != -1)
155 		close(clien);
156 	if (accept_serv != -1)
157 		close(accept_serv);
158 	if (serv != -1)
159 		close(serv);
160 }
161 
test_tcp_timewait(struct sock_destroy_prog * skel)162 static void test_tcp_timewait(struct sock_destroy_prog *skel)
163 {
164 	int serv = -1, clien = -1, accept_serv = -1, n;
165 	struct timeval tv = {};
166 	char buf[1];
167 
168 	serv = start_server(AF_INET6, SOCK_STREAM, NULL, 0, 0);
169 	if (!ASSERT_GE(serv, 0, "start_server"))
170 		goto cleanup;
171 
172 	clien = connect_to_fd(serv, 0);
173 	if (!ASSERT_GE(clien, 0, "connect_to_fd"))
174 		goto cleanup;
175 
176 	accept_serv = accept(serv, NULL, NULL);
177 	if (!ASSERT_GE(accept_serv, 0, "serv accept"))
178 		goto cleanup;
179 
180 	/*
181 	 * Active close from the client, then close the server side. Once
182 	 * recv() sees EOF the server FIN has been processed and the client
183 	 * sock is in TIME_WAIT. Block without timeout so a loaded CI box
184 	 * can't race us.
185 	 */
186 	if (!ASSERT_OK(setsockopt(clien, SOL_SOCKET, SO_RCVTIMEO, &tv,
187 				  sizeof(tv)), "clear rcvtimeo"))
188 		goto cleanup;
189 	if (!ASSERT_OK(shutdown(clien, SHUT_WR), "client shutdown"))
190 		goto cleanup;
191 
192 	/*
193 	 * Make sure the server has seen the client FIN before it closes,
194 	 * so the two FINs never cross.
195 	 */
196 	n = recv(accept_serv, buf, sizeof(buf), 0);
197 	if (!ASSERT_EQ(n, 0, "server recv EOF"))
198 		goto cleanup;
199 
200 	close(accept_serv);
201 	accept_serv = -1;
202 
203 	/* block until return EOF */
204 	n = recv(clien, buf, sizeof(buf), 0);
205 	if (!ASSERT_EQ(n, 0, "client recv EOF"))
206 		goto cleanup;
207 
208 	/* Run iterator program that destroys the timewait client sock. */
209 	skel->bss->tw_found = 0;
210 	start_iter_sockets(skel->progs.iter_tcp6_timewait);
211 	if (!ASSERT_EQ(skel->bss->tw_found, 1, "timewait sock found"))
212 		goto cleanup;
213 
214 	ASSERT_OK(skel->bss->tw_destroy_err, "destroy timewait sock");
215 
216 	/* The destroyed timewait sock must be gone. */
217 	skel->bss->tw_found = 0;
218 	start_iter_sockets(skel->progs.iter_tcp6_timewait);
219 	ASSERT_EQ(skel->bss->tw_found, 0, "timewait sock destroyed");
220 
221 cleanup:
222 	if (clien != -1)
223 		close(clien);
224 	if (accept_serv != -1)
225 		close(accept_serv);
226 	if (serv != -1)
227 		close(serv);
228 }
229 
test_udp_client(struct sock_destroy_prog * skel)230 static void test_udp_client(struct sock_destroy_prog *skel)
231 {
232 	int serv = -1, clien = -1, n = 0;
233 
234 	serv = start_server(AF_INET6, SOCK_DGRAM, NULL, 0, 0);
235 	if (!ASSERT_GE(serv, 0, "start_server"))
236 		goto cleanup;
237 
238 	clien = connect_to_fd(serv, 0);
239 	if (!ASSERT_GE(clien, 0, "connect_to_fd"))
240 		goto cleanup;
241 
242 	n = send(clien, "t", 1, 0);
243 	if (!ASSERT_EQ(n, 1, "client send"))
244 		goto cleanup;
245 
246 	/* Run iterator program that destroys sockets. */
247 	start_iter_sockets(skel->progs.iter_udp6_client);
248 
249 	n = send(clien, "t", 1, 0);
250 	if (!ASSERT_LT(n, 0, "client_send on destroyed socket"))
251 		goto cleanup;
252 	/* UDP sockets have an overriding error code after they are disconnected,
253 	 * so we don't check for ECONNABORTED error code.
254 	 */
255 
256 cleanup:
257 	if (clien != -1)
258 		close(clien);
259 	if (serv != -1)
260 		close(serv);
261 }
262 
test_udp_server(struct sock_destroy_prog * skel)263 static void test_udp_server(struct sock_destroy_prog *skel)
264 {
265 	int *listen_fds = NULL, n, i, serv_port;
266 	unsigned int num_listens = 5;
267 	char buf[1];
268 
269 	/* Start reuseport servers. */
270 	listen_fds = start_reuseport_server(AF_INET6, SOCK_DGRAM,
271 					    "::1", 0, 0, num_listens);
272 	if (!ASSERT_OK_PTR(listen_fds, "start_reuseport_server"))
273 		goto cleanup;
274 	serv_port = get_socket_local_port(listen_fds[0]);
275 	if (!ASSERT_GE(serv_port, 0, "get_sock_local_port"))
276 		goto cleanup;
277 	skel->bss->serv_port = (__be16) serv_port;
278 
279 	/* Run iterator program that destroys server sockets. */
280 	start_iter_sockets(skel->progs.iter_udp6_server);
281 
282 	for (i = 0; i < num_listens; ++i) {
283 		n = read(listen_fds[i], buf, sizeof(buf));
284 		if (!ASSERT_EQ(n, -1, "read") ||
285 		    !ASSERT_EQ(errno, ECONNABORTED, "error code on destroyed socket"))
286 			break;
287 	}
288 	ASSERT_EQ(i, num_listens, "server socket");
289 
290 cleanup:
291 	free_fds(listen_fds, num_listens);
292 }
293 
test_sock_destroy(void)294 void test_sock_destroy(void)
295 {
296 	struct sock_destroy_prog *skel;
297 	struct nstoken *nstoken = NULL;
298 	int cgroup_fd;
299 
300 	skel = sock_destroy_prog__open_and_load();
301 	if (!ASSERT_OK_PTR(skel, "skel_open"))
302 		return;
303 
304 	cgroup_fd = test__join_cgroup("/sock_destroy");
305 	if (!ASSERT_GE(cgroup_fd, 0, "join_cgroup"))
306 		goto cleanup;
307 
308 	skel->links.sock_connect = bpf_program__attach_cgroup(
309 		skel->progs.sock_connect, cgroup_fd);
310 	if (!ASSERT_OK_PTR(skel->links.sock_connect, "prog_attach"))
311 		goto cleanup;
312 
313 	SYS(cleanup, "ip netns add %s", TEST_NS);
314 	SYS(cleanup, "ip -net %s link set dev lo up", TEST_NS);
315 
316 	nstoken = open_netns(TEST_NS);
317 	if (!ASSERT_OK_PTR(nstoken, "open_netns"))
318 		goto cleanup;
319 
320 	if (test__start_subtest("tcp_client"))
321 		test_tcp_client(skel);
322 	if (test__start_subtest("tcp_server"))
323 		test_tcp_server(skel);
324 	if (test__start_subtest("tcp_listen_pending"))
325 		test_tcp_listen_pending(skel);
326 	if (test__start_subtest("tcp_timewait"))
327 		test_tcp_timewait(skel);
328 	if (test__start_subtest("udp_client"))
329 		test_udp_client(skel);
330 	if (test__start_subtest("udp_server"))
331 		test_udp_server(skel);
332 
333 	RUN_TESTS(sock_destroy_prog_fail);
334 
335 cleanup:
336 	if (nstoken)
337 		close_netns(nstoken);
338 	SYS_NOFAIL("ip netns del " TEST_NS);
339 	if (cgroup_fd >= 0)
340 		close(cgroup_fd);
341 	sock_destroy_prog__destroy(skel);
342 }
343