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 ASSERT_EQ(skel->bss->invalid_cnt, 0, "invalid_cnt"); 197 pthread_mutex_unlock(&do_nothing_mutex); 198 for (int i = 0; i < thread_num; i++) 199 ASSERT_OK(pthread_join(thread_ids[i], &ret), "pthread_join"); 200 cleanup: 201 iters_task__destroy(skel); 202 } 203 204 extern int stack_mprotect(void); 205 206 static void subtest_css_task_iters(void) 207 { 208 struct iters_css_task *skel = NULL; 209 int err, cg_fd, cg_id; 210 const char *cgrp_path = "/cg1"; 211 212 err = setup_cgroup_environment(); 213 if (!ASSERT_OK(err, "setup_cgroup_environment")) 214 goto cleanup; 215 cg_fd = create_and_get_cgroup(cgrp_path); 216 if (!ASSERT_GE(cg_fd, 0, "create_and_get_cgroup")) 217 goto cleanup; 218 cg_id = get_cgroup_id(cgrp_path); 219 err = join_cgroup(cgrp_path); 220 if (!ASSERT_OK(err, "join_cgroup")) 221 goto cleanup; 222 223 skel = iters_css_task__open_and_load(); 224 if (!ASSERT_OK_PTR(skel, "open_and_load")) 225 goto cleanup; 226 227 skel->bss->target_pid = getpid(); 228 skel->bss->cg_id = cg_id; 229 err = iters_css_task__attach(skel); 230 if (!ASSERT_OK(err, "iters_task__attach")) 231 goto cleanup; 232 err = stack_mprotect(); 233 if (!ASSERT_EQ(err, -1, "stack_mprotect") || 234 !ASSERT_EQ(errno, EPERM, "stack_mprotect")) 235 goto cleanup; 236 iters_css_task__detach(skel); 237 ASSERT_EQ(skel->bss->css_task_cnt, 1, "css_task_cnt"); 238 239 cleanup: 240 cleanup_cgroup_environment(); 241 iters_css_task__destroy(skel); 242 } 243 244 static void subtest_css_iters(void) 245 { 246 struct iters_css *skel = NULL; 247 struct { 248 const char *path; 249 int fd; 250 } cgs[] = { 251 { "/cg1" }, 252 { "/cg1/cg2" }, 253 { "/cg1/cg2/cg3" }, 254 { "/cg1/cg2/cg3/cg4" }, 255 }; 256 int err, cg_nr = ARRAY_SIZE(cgs); 257 int i; 258 259 err = setup_cgroup_environment(); 260 if (!ASSERT_OK(err, "setup_cgroup_environment")) 261 goto cleanup; 262 for (i = 0; i < cg_nr; i++) { 263 cgs[i].fd = create_and_get_cgroup(cgs[i].path); 264 if (!ASSERT_GE(cgs[i].fd, 0, "create_and_get_cgroup")) 265 goto cleanup; 266 } 267 268 skel = iters_css__open_and_load(); 269 if (!ASSERT_OK_PTR(skel, "open_and_load")) 270 goto cleanup; 271 272 skel->bss->target_pid = getpid(); 273 skel->bss->root_cg_id = get_cgroup_id(cgs[0].path); 274 skel->bss->leaf_cg_id = get_cgroup_id(cgs[cg_nr - 1].path); 275 err = iters_css__attach(skel); 276 277 if (!ASSERT_OK(err, "iters_task__attach")) 278 goto cleanup; 279 280 syscall(SYS_getpgid); 281 ASSERT_EQ(skel->bss->pre_order_cnt, cg_nr, "pre_order_cnt"); 282 ASSERT_EQ(skel->bss->first_cg_id, get_cgroup_id(cgs[0].path), "first_cg_id"); 283 284 ASSERT_EQ(skel->bss->post_order_cnt, cg_nr, "post_order_cnt"); 285 ASSERT_EQ(skel->bss->last_cg_id, get_cgroup_id(cgs[0].path), "last_cg_id"); 286 ASSERT_EQ(skel->bss->tree_high, cg_nr - 1, "tree_high"); 287 iters_css__detach(skel); 288 cleanup: 289 cleanup_cgroup_environment(); 290 iters_css__destroy(skel); 291 } 292 293 void test_iters(void) 294 { 295 RUN_TESTS(iters_state_safety); 296 RUN_TESTS(iters_looping); 297 RUN_TESTS(iters); 298 RUN_TESTS(iters_css_task); 299 300 if (env.has_testmod) 301 RUN_TESTS(iters_testmod_seq); 302 303 if (test__start_subtest("num")) 304 subtest_num_iters(); 305 if (test__start_subtest("testmod_seq")) 306 subtest_testmod_seq_iters(); 307 if (test__start_subtest("task_vma")) 308 subtest_task_vma_iters(); 309 if (test__start_subtest("task")) 310 subtest_task_iters(); 311 if (test__start_subtest("css_task")) 312 subtest_css_task_iters(); 313 if (test__start_subtest("css")) 314 subtest_css_iters(); 315 RUN_TESTS(iters_task_failure); 316 } 317