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 "cgrp_ls_sleepable.skel.h" 14 #include "network_helpers.h" 15 #include "cgroup_helpers.h" 16 17 struct socket_cookie { 18 __u64 cookie_key; 19 __u64 cookie_value; 20 }; 21 22 static void test_tp_btf(int cgroup_fd) 23 { 24 struct cgrp_ls_tp_btf *skel; 25 long val1 = 1, val2 = 0; 26 int err; 27 28 skel = cgrp_ls_tp_btf__open_and_load(); 29 if (!ASSERT_OK_PTR(skel, "skel_open_and_load")) 30 return; 31 32 /* populate a value in map_b */ 33 err = bpf_map_update_elem(bpf_map__fd(skel->maps.map_b), &cgroup_fd, &val1, BPF_ANY); 34 if (!ASSERT_OK(err, "map_update_elem")) 35 goto out; 36 37 /* check value */ 38 err = bpf_map_lookup_elem(bpf_map__fd(skel->maps.map_b), &cgroup_fd, &val2); 39 if (!ASSERT_OK(err, "map_lookup_elem")) 40 goto out; 41 if (!ASSERT_EQ(val2, 1, "map_lookup_elem, invalid val")) 42 goto out; 43 44 /* delete value */ 45 err = bpf_map_delete_elem(bpf_map__fd(skel->maps.map_b), &cgroup_fd); 46 if (!ASSERT_OK(err, "map_delete_elem")) 47 goto out; 48 49 skel->bss->target_pid = syscall(SYS_gettid); 50 51 err = cgrp_ls_tp_btf__attach(skel); 52 if (!ASSERT_OK(err, "skel_attach")) 53 goto out; 54 55 syscall(SYS_gettid); 56 syscall(SYS_gettid); 57 58 skel->bss->target_pid = 0; 59 60 /* 3x syscalls: 1x attach and 2x gettid */ 61 ASSERT_EQ(skel->bss->enter_cnt, 3, "enter_cnt"); 62 ASSERT_EQ(skel->bss->exit_cnt, 3, "exit_cnt"); 63 ASSERT_EQ(skel->bss->mismatch_cnt, 0, "mismatch_cnt"); 64 out: 65 cgrp_ls_tp_btf__destroy(skel); 66 } 67 68 static void test_attach_cgroup(int cgroup_fd) 69 { 70 int server_fd = 0, client_fd = 0, err = 0; 71 socklen_t addr_len = sizeof(struct sockaddr_in6); 72 struct cgrp_ls_attach_cgroup *skel; 73 __u32 cookie_expected_value; 74 struct sockaddr_in6 addr; 75 struct socket_cookie val; 76 77 skel = cgrp_ls_attach_cgroup__open_and_load(); 78 if (!ASSERT_OK_PTR(skel, "skel_open")) 79 return; 80 81 skel->links.set_cookie = bpf_program__attach_cgroup( 82 skel->progs.set_cookie, cgroup_fd); 83 if (!ASSERT_OK_PTR(skel->links.set_cookie, "prog_attach")) 84 goto out; 85 86 skel->links.update_cookie_sockops = bpf_program__attach_cgroup( 87 skel->progs.update_cookie_sockops, cgroup_fd); 88 if (!ASSERT_OK_PTR(skel->links.update_cookie_sockops, "prog_attach")) 89 goto out; 90 91 skel->links.update_cookie_tracing = bpf_program__attach( 92 skel->progs.update_cookie_tracing); 93 if (!ASSERT_OK_PTR(skel->links.update_cookie_tracing, "prog_attach")) 94 goto out; 95 96 server_fd = start_server(AF_INET6, SOCK_STREAM, "::1", 0, 0); 97 if (!ASSERT_GE(server_fd, 0, "start_server")) 98 goto out; 99 100 client_fd = connect_to_fd(server_fd, 0); 101 if (!ASSERT_GE(client_fd, 0, "connect_to_fd")) 102 goto close_server_fd; 103 104 err = bpf_map_lookup_elem(bpf_map__fd(skel->maps.socket_cookies), 105 &cgroup_fd, &val); 106 if (!ASSERT_OK(err, "map_lookup(socket_cookies)")) 107 goto close_client_fd; 108 109 err = getsockname(client_fd, (struct sockaddr *)&addr, &addr_len); 110 if (!ASSERT_OK(err, "getsockname")) 111 goto close_client_fd; 112 113 cookie_expected_value = (ntohs(addr.sin6_port) << 8) | 0xFF; 114 ASSERT_EQ(val.cookie_value, cookie_expected_value, "cookie_value"); 115 116 close_client_fd: 117 close(client_fd); 118 close_server_fd: 119 close(server_fd); 120 out: 121 cgrp_ls_attach_cgroup__destroy(skel); 122 } 123 124 static void test_recursion(int cgroup_fd) 125 { 126 struct cgrp_ls_recursion *skel; 127 int err; 128 129 skel = cgrp_ls_recursion__open_and_load(); 130 if (!ASSERT_OK_PTR(skel, "skel_open_and_load")) 131 return; 132 133 err = cgrp_ls_recursion__attach(skel); 134 if (!ASSERT_OK(err, "skel_attach")) 135 goto out; 136 137 /* trigger sys_enter, make sure it does not cause deadlock */ 138 syscall(SYS_gettid); 139 140 out: 141 cgrp_ls_recursion__destroy(skel); 142 } 143 144 static void test_negative(void) 145 { 146 struct cgrp_ls_negative *skel; 147 148 skel = cgrp_ls_negative__open_and_load(); 149 if (!ASSERT_ERR_PTR(skel, "skel_open_and_load")) { 150 cgrp_ls_negative__destroy(skel); 151 return; 152 } 153 } 154 155 static void test_cgroup_iter_sleepable(int cgroup_fd, __u64 cgroup_id) 156 { 157 DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts); 158 union bpf_iter_link_info linfo; 159 struct cgrp_ls_sleepable *skel; 160 struct bpf_link *link; 161 int err, iter_fd; 162 char buf[16]; 163 164 skel = cgrp_ls_sleepable__open(); 165 if (!ASSERT_OK_PTR(skel, "skel_open")) 166 return; 167 168 bpf_program__set_autoload(skel->progs.cgroup_iter, true); 169 err = cgrp_ls_sleepable__load(skel); 170 if (!ASSERT_OK(err, "skel_load")) 171 goto out; 172 173 memset(&linfo, 0, sizeof(linfo)); 174 linfo.cgroup.cgroup_fd = cgroup_fd; 175 linfo.cgroup.order = BPF_CGROUP_ITER_SELF_ONLY; 176 opts.link_info = &linfo; 177 opts.link_info_len = sizeof(linfo); 178 link = bpf_program__attach_iter(skel->progs.cgroup_iter, &opts); 179 if (!ASSERT_OK_PTR(link, "attach_iter")) 180 goto out; 181 182 iter_fd = bpf_iter_create(bpf_link__fd(link)); 183 if (!ASSERT_GE(iter_fd, 0, "iter_create")) 184 goto out; 185 186 /* trigger the program run */ 187 (void)read(iter_fd, buf, sizeof(buf)); 188 189 ASSERT_EQ(skel->bss->cgroup_id, cgroup_id, "cgroup_id"); 190 191 close(iter_fd); 192 out: 193 cgrp_ls_sleepable__destroy(skel); 194 } 195 196 static void test_no_rcu_lock(__u64 cgroup_id) 197 { 198 struct cgrp_ls_sleepable *skel; 199 int err; 200 201 skel = cgrp_ls_sleepable__open(); 202 if (!ASSERT_OK_PTR(skel, "skel_open")) 203 return; 204 205 skel->bss->target_pid = syscall(SYS_gettid); 206 207 bpf_program__set_autoload(skel->progs.no_rcu_lock, true); 208 err = cgrp_ls_sleepable__load(skel); 209 if (!ASSERT_OK(err, "skel_load")) 210 goto out; 211 212 err = cgrp_ls_sleepable__attach(skel); 213 if (!ASSERT_OK(err, "skel_attach")) 214 goto out; 215 216 syscall(SYS_getpgid); 217 218 ASSERT_EQ(skel->bss->cgroup_id, cgroup_id, "cgroup_id"); 219 out: 220 cgrp_ls_sleepable__destroy(skel); 221 } 222 223 static void test_rcu_lock(void) 224 { 225 struct cgrp_ls_sleepable *skel; 226 int err; 227 228 skel = cgrp_ls_sleepable__open(); 229 if (!ASSERT_OK_PTR(skel, "skel_open")) 230 return; 231 232 bpf_program__set_autoload(skel->progs.yes_rcu_lock, true); 233 err = cgrp_ls_sleepable__load(skel); 234 ASSERT_ERR(err, "skel_load"); 235 236 cgrp_ls_sleepable__destroy(skel); 237 } 238 239 void test_cgrp_local_storage(void) 240 { 241 __u64 cgroup_id; 242 int cgroup_fd; 243 244 cgroup_fd = test__join_cgroup("/cgrp_local_storage"); 245 if (!ASSERT_GE(cgroup_fd, 0, "join_cgroup /cgrp_local_storage")) 246 return; 247 248 cgroup_id = get_cgroup_id("/cgrp_local_storage"); 249 if (test__start_subtest("tp_btf")) 250 test_tp_btf(cgroup_fd); 251 if (test__start_subtest("attach_cgroup")) 252 test_attach_cgroup(cgroup_fd); 253 if (test__start_subtest("recursion")) 254 test_recursion(cgroup_fd); 255 if (test__start_subtest("negative")) 256 test_negative(); 257 if (test__start_subtest("cgroup_iter_sleepable")) 258 test_cgroup_iter_sleepable(cgroup_fd, cgroup_id); 259 if (test__start_subtest("no_rcu_lock")) 260 test_no_rcu_lock(cgroup_id); 261 if (test__start_subtest("rcu_lock")) 262 test_rcu_lock(); 263 264 close(cgroup_fd); 265 } 266