1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ 3 4 #include <sys/syscall.h> 5 #include <sys/mman.h> 6 #include <sys/wait.h> 7 #include <unistd.h> 8 #include <malloc.h> 9 #include <stdlib.h> 10 #include <test_progs.h> 11 #include "cgroup_helpers.h" 12 13 #include "iters.skel.h" 14 #include "iters_state_safety.skel.h" 15 #include "iters_looping.skel.h" 16 #include "iters_num.skel.h" 17 #include "iters_testmod.skel.h" 18 #include "iters_testmod_seq.skel.h" 19 #include "iters_task_vma.skel.h" 20 #include "iters_task.skel.h" 21 #include "iters_css_task.skel.h" 22 #include "iters_css.skel.h" 23 #include "iters_task_failure.skel.h" 24 25 static void subtest_num_iters(void) 26 { 27 struct iters_num *skel; 28 int err; 29 30 skel = iters_num__open_and_load(); 31 if (!ASSERT_OK_PTR(skel, "skel_open_and_load")) 32 return; 33 34 err = iters_num__attach(skel); 35 if (!ASSERT_OK(err, "skel_attach")) 36 goto cleanup; 37 38 usleep(1); 39 iters_num__detach(skel); 40 41 #define VALIDATE_CASE(case_name) \ 42 ASSERT_EQ(skel->bss->res_##case_name, \ 43 skel->rodata->exp_##case_name, \ 44 #case_name) 45 46 VALIDATE_CASE(empty_zero); 47 VALIDATE_CASE(empty_int_min); 48 VALIDATE_CASE(empty_int_max); 49 VALIDATE_CASE(empty_minus_one); 50 51 VALIDATE_CASE(simple_sum); 52 VALIDATE_CASE(neg_sum); 53 VALIDATE_CASE(very_neg_sum); 54 VALIDATE_CASE(neg_pos_sum); 55 56 VALIDATE_CASE(invalid_range); 57 VALIDATE_CASE(max_range); 58 VALIDATE_CASE(e2big_range); 59 60 VALIDATE_CASE(succ_elem_cnt); 61 VALIDATE_CASE(overfetched_elem_cnt); 62 VALIDATE_CASE(fail_elem_cnt); 63 64 #undef VALIDATE_CASE 65 66 cleanup: 67 iters_num__destroy(skel); 68 } 69 70 static void subtest_testmod_seq_iters(void) 71 { 72 struct iters_testmod_seq *skel; 73 int err; 74 75 if (!env.has_testmod) { 76 test__skip(); 77 return; 78 } 79 80 skel = iters_testmod_seq__open_and_load(); 81 if (!ASSERT_OK_PTR(skel, "skel_open_and_load")) 82 return; 83 84 err = iters_testmod_seq__attach(skel); 85 if (!ASSERT_OK(err, "skel_attach")) 86 goto cleanup; 87 88 usleep(1); 89 iters_testmod_seq__detach(skel); 90 91 #define VALIDATE_CASE(case_name) \ 92 ASSERT_EQ(skel->bss->res_##case_name, \ 93 skel->rodata->exp_##case_name, \ 94 #case_name) 95 96 VALIDATE_CASE(empty); 97 VALIDATE_CASE(full); 98 VALIDATE_CASE(truncated); 99 100 #undef VALIDATE_CASE 101 102 cleanup: 103 iters_testmod_seq__destroy(skel); 104 } 105 106 static void subtest_task_vma_iters(void) 107 { 108 unsigned long start, end, bpf_iter_start, bpf_iter_end; 109 struct iters_task_vma *skel; 110 char rest_of_line[1000]; 111 unsigned int seen; 112 FILE *f = NULL; 113 int err; 114 115 skel = iters_task_vma__open_and_load(); 116 if (!ASSERT_OK_PTR(skel, "skel_open_and_load")) 117 return; 118 119 skel->bss->target_pid = getpid(); 120 121 err = iters_task_vma__attach(skel); 122 if (!ASSERT_OK(err, "skel_attach")) 123 goto cleanup; 124 125 getpgid(skel->bss->target_pid); 126 iters_task_vma__detach(skel); 127 128 if (!ASSERT_GT(skel->bss->vmas_seen, 0, "vmas_seen_gt_zero")) 129 goto cleanup; 130 131 f = fopen("/proc/self/maps", "r"); 132 if (!ASSERT_OK_PTR(f, "proc_maps_fopen")) 133 goto cleanup; 134 135 seen = 0; 136 while (fscanf(f, "%lx-%lx %[^\n]\n", &start, &end, rest_of_line) == 3) { 137 /* [vsyscall] vma isn't _really_ part of task->mm vmas. 138 * /proc/PID/maps returns it when out of vmas - see get_gate_vma 139 * calls in fs/proc/task_mmu.c 140 */ 141 if (strstr(rest_of_line, "[vsyscall]")) 142 continue; 143 144 bpf_iter_start = skel->bss->vm_ranges[seen].vm_start; 145 bpf_iter_end = skel->bss->vm_ranges[seen].vm_end; 146 147 ASSERT_EQ(bpf_iter_start, start, "vma->vm_start match"); 148 ASSERT_EQ(bpf_iter_end, end, "vma->vm_end match"); 149 seen++; 150 } 151 152 if (!ASSERT_EQ(skel->bss->vmas_seen, seen, "vmas_seen_eq")) 153 goto cleanup; 154 155 cleanup: 156 if (f) 157 fclose(f); 158 iters_task_vma__destroy(skel); 159 } 160 161 static pthread_mutex_t do_nothing_mutex; 162 163 static void *do_nothing_wait(void *arg) 164 { 165 pthread_mutex_lock(&do_nothing_mutex); 166 pthread_mutex_unlock(&do_nothing_mutex); 167 168 pthread_exit(arg); 169 } 170 171 #define thread_num 2 172 173 static void subtest_task_iters(void) 174 { 175 struct iters_task *skel = NULL; 176 pthread_t thread_ids[thread_num]; 177 void *ret; 178 int err; 179 180 skel = iters_task__open_and_load(); 181 if (!ASSERT_OK_PTR(skel, "open_and_load")) 182 goto cleanup; 183 skel->bss->target_pid = getpid(); 184 err = iters_task__attach(skel); 185 if (!ASSERT_OK(err, "iters_task__attach")) 186 goto cleanup; 187 pthread_mutex_lock(&do_nothing_mutex); 188 for (int i = 0; i < thread_num; i++) 189 ASSERT_OK(pthread_create(&thread_ids[i], NULL, &do_nothing_wait, NULL), 190 "pthread_create"); 191 192 syscall(SYS_getpgid); 193 iters_task__detach(skel); 194 ASSERT_EQ(skel->bss->procs_cnt, 1, "procs_cnt"); 195 ASSERT_EQ(skel->bss->threads_cnt, thread_num + 1, "threads_cnt"); 196 ASSERT_EQ(skel->bss->proc_threads_cnt, thread_num + 1, "proc_threads_cnt"); 197 ASSERT_EQ(skel->bss->invalid_cnt, 0, "invalid_cnt"); 198 pthread_mutex_unlock(&do_nothing_mutex); 199 for (int i = 0; i < thread_num; i++) 200 ASSERT_OK(pthread_join(thread_ids[i], &ret), "pthread_join"); 201 cleanup: 202 iters_task__destroy(skel); 203 } 204 205 extern int stack_mprotect(void); 206 207 static void subtest_css_task_iters(void) 208 { 209 struct iters_css_task *skel = NULL; 210 int err, cg_fd, cg_id; 211 const char *cgrp_path = "/cg1"; 212 213 err = setup_cgroup_environment(); 214 if (!ASSERT_OK(err, "setup_cgroup_environment")) 215 goto cleanup; 216 cg_fd = create_and_get_cgroup(cgrp_path); 217 if (!ASSERT_GE(cg_fd, 0, "create_and_get_cgroup")) 218 goto cleanup; 219 cg_id = get_cgroup_id(cgrp_path); 220 err = join_cgroup(cgrp_path); 221 if (!ASSERT_OK(err, "join_cgroup")) 222 goto cleanup; 223 224 skel = iters_css_task__open_and_load(); 225 if (!ASSERT_OK_PTR(skel, "open_and_load")) 226 goto cleanup; 227 228 skel->bss->target_pid = getpid(); 229 skel->bss->cg_id = cg_id; 230 err = iters_css_task__attach(skel); 231 if (!ASSERT_OK(err, "iters_task__attach")) 232 goto cleanup; 233 err = stack_mprotect(); 234 if (!ASSERT_EQ(err, -1, "stack_mprotect") || 235 !ASSERT_EQ(errno, EPERM, "stack_mprotect")) 236 goto cleanup; 237 iters_css_task__detach(skel); 238 ASSERT_EQ(skel->bss->css_task_cnt, 1, "css_task_cnt"); 239 240 cleanup: 241 cleanup_cgroup_environment(); 242 iters_css_task__destroy(skel); 243 } 244 245 static void subtest_css_iters(void) 246 { 247 struct iters_css *skel = NULL; 248 struct { 249 const char *path; 250 int fd; 251 } cgs[] = { 252 { "/cg1" }, 253 { "/cg1/cg2" }, 254 { "/cg1/cg2/cg3" }, 255 { "/cg1/cg2/cg3/cg4" }, 256 }; 257 int err, cg_nr = ARRAY_SIZE(cgs); 258 int i; 259 260 err = setup_cgroup_environment(); 261 if (!ASSERT_OK(err, "setup_cgroup_environment")) 262 goto cleanup; 263 for (i = 0; i < cg_nr; i++) { 264 cgs[i].fd = create_and_get_cgroup(cgs[i].path); 265 if (!ASSERT_GE(cgs[i].fd, 0, "create_and_get_cgroup")) 266 goto cleanup; 267 } 268 269 skel = iters_css__open_and_load(); 270 if (!ASSERT_OK_PTR(skel, "open_and_load")) 271 goto cleanup; 272 273 skel->bss->target_pid = getpid(); 274 skel->bss->root_cg_id = get_cgroup_id(cgs[0].path); 275 skel->bss->leaf_cg_id = get_cgroup_id(cgs[cg_nr - 1].path); 276 err = iters_css__attach(skel); 277 278 if (!ASSERT_OK(err, "iters_task__attach")) 279 goto cleanup; 280 281 syscall(SYS_getpgid); 282 ASSERT_EQ(skel->bss->pre_order_cnt, cg_nr, "pre_order_cnt"); 283 ASSERT_EQ(skel->bss->first_cg_id, get_cgroup_id(cgs[0].path), "first_cg_id"); 284 285 ASSERT_EQ(skel->bss->post_order_cnt, cg_nr, "post_order_cnt"); 286 ASSERT_EQ(skel->bss->last_cg_id, get_cgroup_id(cgs[0].path), "last_cg_id"); 287 ASSERT_EQ(skel->bss->tree_high, cg_nr - 1, "tree_high"); 288 iters_css__detach(skel); 289 cleanup: 290 cleanup_cgroup_environment(); 291 iters_css__destroy(skel); 292 } 293 294 void test_iters(void) 295 { 296 RUN_TESTS(iters_state_safety); 297 RUN_TESTS(iters_looping); 298 RUN_TESTS(iters); 299 RUN_TESTS(iters_css_task); 300 301 if (env.has_testmod) { 302 RUN_TESTS(iters_testmod); 303 RUN_TESTS(iters_testmod_seq); 304 } 305 306 if (test__start_subtest("num")) 307 subtest_num_iters(); 308 if (test__start_subtest("testmod_seq")) 309 subtest_testmod_seq_iters(); 310 if (test__start_subtest("task_vma")) 311 subtest_task_vma_iters(); 312 if (test__start_subtest("task")) 313 subtest_task_iters(); 314 if (test__start_subtest("css_task")) 315 subtest_css_task_iters(); 316 if (test__start_subtest("css")) 317 subtest_css_iters(); 318 RUN_TESTS(iters_task_failure); 319 } 320