xref: /linux/tools/testing/selftests/bpf/prog_tests/iters.c (revision 335bbdf01d25517ae832ac1807fd8323c1f4f3b9)
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