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