1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2022 Meta Platforms, Inc. and affiliates.*/
3 
4 #define _GNU_SOURCE
5 #include <unistd.h>
6 #include <sys/syscall.h>
7 #include <sys/types.h>
8 #include <test_progs.h>
9 #include "cgrp_ls_tp_btf.skel.h"
10 #include "cgrp_ls_recursion.skel.h"
11 #include "cgrp_ls_attach_cgroup.skel.h"
12 #include "cgrp_ls_negative.skel.h"
13 #include "network_helpers.h"
14 
15 struct socket_cookie {
16 	__u64 cookie_key;
17 	__u32 cookie_value;
18 };
19 
20 static void test_tp_btf(int cgroup_fd)
21 {
22 	struct cgrp_ls_tp_btf *skel;
23 	long val1 = 1, val2 = 0;
24 	int err;
25 
26 	skel = cgrp_ls_tp_btf__open_and_load();
27 	if (!ASSERT_OK_PTR(skel, "skel_open_and_load"))
28 		return;
29 
30 	/* populate a value in map_b */
31 	err = bpf_map_update_elem(bpf_map__fd(skel->maps.map_b), &cgroup_fd, &val1, BPF_ANY);
32 	if (!ASSERT_OK(err, "map_update_elem"))
33 		goto out;
34 
35 	/* check value */
36 	err = bpf_map_lookup_elem(bpf_map__fd(skel->maps.map_b), &cgroup_fd, &val2);
37 	if (!ASSERT_OK(err, "map_lookup_elem"))
38 		goto out;
39 	if (!ASSERT_EQ(val2, 1, "map_lookup_elem, invalid val"))
40 		goto out;
41 
42 	/* delete value */
43 	err = bpf_map_delete_elem(bpf_map__fd(skel->maps.map_b), &cgroup_fd);
44 	if (!ASSERT_OK(err, "map_delete_elem"))
45 		goto out;
46 
47 	skel->bss->target_pid = syscall(SYS_gettid);
48 
49 	err = cgrp_ls_tp_btf__attach(skel);
50 	if (!ASSERT_OK(err, "skel_attach"))
51 		goto out;
52 
53 	syscall(SYS_gettid);
54 	syscall(SYS_gettid);
55 
56 	skel->bss->target_pid = 0;
57 
58 	/* 3x syscalls: 1x attach and 2x gettid */
59 	ASSERT_EQ(skel->bss->enter_cnt, 3, "enter_cnt");
60 	ASSERT_EQ(skel->bss->exit_cnt, 3, "exit_cnt");
61 	ASSERT_EQ(skel->bss->mismatch_cnt, 0, "mismatch_cnt");
62 out:
63 	cgrp_ls_tp_btf__destroy(skel);
64 }
65 
66 static void test_attach_cgroup(int cgroup_fd)
67 {
68 	int server_fd = 0, client_fd = 0, err = 0;
69 	socklen_t addr_len = sizeof(struct sockaddr_in6);
70 	struct cgrp_ls_attach_cgroup *skel;
71 	__u32 cookie_expected_value;
72 	struct sockaddr_in6 addr;
73 	struct socket_cookie val;
74 
75 	skel = cgrp_ls_attach_cgroup__open_and_load();
76 	if (!ASSERT_OK_PTR(skel, "skel_open"))
77 		return;
78 
79 	skel->links.set_cookie = bpf_program__attach_cgroup(
80 		skel->progs.set_cookie, cgroup_fd);
81 	if (!ASSERT_OK_PTR(skel->links.set_cookie, "prog_attach"))
82 		goto out;
83 
84 	skel->links.update_cookie_sockops = bpf_program__attach_cgroup(
85 		skel->progs.update_cookie_sockops, cgroup_fd);
86 	if (!ASSERT_OK_PTR(skel->links.update_cookie_sockops, "prog_attach"))
87 		goto out;
88 
89 	skel->links.update_cookie_tracing = bpf_program__attach(
90 		skel->progs.update_cookie_tracing);
91 	if (!ASSERT_OK_PTR(skel->links.update_cookie_tracing, "prog_attach"))
92 		goto out;
93 
94 	server_fd = start_server(AF_INET6, SOCK_STREAM, "::1", 0, 0);
95 	if (!ASSERT_GE(server_fd, 0, "start_server"))
96 		goto out;
97 
98 	client_fd = connect_to_fd(server_fd, 0);
99 	if (!ASSERT_GE(client_fd, 0, "connect_to_fd"))
100 		goto close_server_fd;
101 
102 	err = bpf_map_lookup_elem(bpf_map__fd(skel->maps.socket_cookies),
103 				  &cgroup_fd, &val);
104 	if (!ASSERT_OK(err, "map_lookup(socket_cookies)"))
105 		goto close_client_fd;
106 
107 	err = getsockname(client_fd, (struct sockaddr *)&addr, &addr_len);
108 	if (!ASSERT_OK(err, "getsockname"))
109 		goto close_client_fd;
110 
111 	cookie_expected_value = (ntohs(addr.sin6_port) << 8) | 0xFF;
112 	ASSERT_EQ(val.cookie_value, cookie_expected_value, "cookie_value");
113 
114 close_client_fd:
115 	close(client_fd);
116 close_server_fd:
117 	close(server_fd);
118 out:
119 	cgrp_ls_attach_cgroup__destroy(skel);
120 }
121 
122 static void test_recursion(int cgroup_fd)
123 {
124 	struct cgrp_ls_recursion *skel;
125 	int err;
126 
127 	skel = cgrp_ls_recursion__open_and_load();
128 	if (!ASSERT_OK_PTR(skel, "skel_open_and_load"))
129 		return;
130 
131 	err = cgrp_ls_recursion__attach(skel);
132 	if (!ASSERT_OK(err, "skel_attach"))
133 		goto out;
134 
135 	/* trigger sys_enter, make sure it does not cause deadlock */
136 	syscall(SYS_gettid);
137 
138 out:
139 	cgrp_ls_recursion__destroy(skel);
140 }
141 
142 static void test_negative(void)
143 {
144 	struct cgrp_ls_negative *skel;
145 
146 	skel = cgrp_ls_negative__open_and_load();
147 	if (!ASSERT_ERR_PTR(skel, "skel_open_and_load")) {
148 		cgrp_ls_negative__destroy(skel);
149 		return;
150 	}
151 }
152 
153 void test_cgrp_local_storage(void)
154 {
155 	int cgroup_fd;
156 
157 	cgroup_fd = test__join_cgroup("/cgrp_local_storage");
158 	if (!ASSERT_GE(cgroup_fd, 0, "join_cgroup /cgrp_local_storage"))
159 		return;
160 
161 	if (test__start_subtest("tp_btf"))
162 		test_tp_btf(cgroup_fd);
163 	if (test__start_subtest("attach_cgroup"))
164 		test_attach_cgroup(cgroup_fd);
165 	if (test__start_subtest("recursion"))
166 		test_recursion(cgroup_fd);
167 	if (test__start_subtest("negative"))
168 		test_negative();
169 
170 	close(cgroup_fd);
171 }
172