xref: /linux/tools/testing/selftests/bpf/prog_tests/task_kfunc.c (revision c16ce856e422e73a54c41131e0332de1afe09b8b)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
3 
4 #define _GNU_SOURCE
5 #include <sys/wait.h>
6 #include <test_progs.h>
7 #include <unistd.h>
8 
9 #include "task_kfunc_failure.skel.h"
10 #include "task_kfunc_success.skel.h"
11 
12 static struct task_kfunc_success *open_load_task_kfunc_skel(void)
13 {
14 	struct task_kfunc_success *skel;
15 	int err;
16 
17 	skel = task_kfunc_success__open();
18 	if (!ASSERT_OK_PTR(skel, "skel_open"))
19 		return NULL;
20 
21 	skel->bss->pid = getpid();
22 
23 	err = task_kfunc_success__load(skel);
24 	if (!ASSERT_OK(err, "skel_load"))
25 		goto cleanup;
26 
27 	return skel;
28 
29 cleanup:
30 	task_kfunc_success__destroy(skel);
31 	return NULL;
32 }
33 
34 static void run_success_test(const char *prog_name)
35 {
36 	struct task_kfunc_success *skel;
37 	int status;
38 	pid_t child_pid;
39 	struct bpf_program *prog;
40 	struct bpf_link *link = NULL;
41 
42 	skel = open_load_task_kfunc_skel();
43 	if (!ASSERT_OK_PTR(skel, "open_load_skel"))
44 		return;
45 
46 	if (!ASSERT_OK(skel->bss->err, "pre_spawn_err"))
47 		goto cleanup;
48 
49 	prog = bpf_object__find_program_by_name(skel->obj, prog_name);
50 	if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name"))
51 		goto cleanup;
52 
53 	link = bpf_program__attach(prog);
54 	if (!ASSERT_OK_PTR(link, "attached_link"))
55 		goto cleanup;
56 
57 	child_pid = fork();
58 	if (!ASSERT_GT(child_pid, -1, "child_pid"))
59 		goto cleanup;
60 	if (child_pid == 0)
61 		_exit(0);
62 	waitpid(child_pid, &status, 0);
63 
64 	ASSERT_OK(skel->bss->err, "post_wait_err");
65 
66 cleanup:
67 	bpf_link__destroy(link);
68 	task_kfunc_success__destroy(skel);
69 }
70 
71 static void run_syscall_success_test(const char *prog_name)
72 {
73 	LIBBPF_OPTS(bpf_test_run_opts, opts);
74 	struct task_kfunc_success *skel;
75 	struct bpf_program *prog;
76 	int err;
77 
78 	skel = open_load_task_kfunc_skel();
79 	if (!ASSERT_OK_PTR(skel, "open_load_skel"))
80 		return;
81 
82 	if (!ASSERT_OK(skel->bss->err, "pre_run_err"))
83 		goto cleanup;
84 
85 	prog = bpf_object__find_program_by_name(skel->obj, prog_name);
86 	if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name"))
87 		goto cleanup;
88 
89 	err = bpf_prog_test_run_opts(bpf_program__fd(prog), &opts);
90 	if (!ASSERT_OK(err, "bpf_prog_test_run_opts"))
91 		goto cleanup;
92 	if (!ASSERT_EQ(opts.retval, 0, "retval"))
93 		goto cleanup;
94 
95 	ASSERT_OK(skel->bss->err, "post_run_err");
96 
97 cleanup:
98 	task_kfunc_success__destroy(skel);
99 }
100 
101 static int run_vpid_test(void *prog_name)
102 {
103 	struct task_kfunc_success *skel;
104 	struct bpf_program *prog;
105 	int prog_fd, err = 0;
106 
107 	if (getpid() != 1)
108 		return 1;
109 
110 	skel = open_load_task_kfunc_skel();
111 	if (!skel)
112 		return 2;
113 
114 	if (skel->bss->err) {
115 		err = 3;
116 		goto cleanup;
117 	}
118 
119 	prog = bpf_object__find_program_by_name(skel->obj, prog_name);
120 	if (!prog) {
121 		err = 4;
122 		goto cleanup;
123 	}
124 
125 	prog_fd = bpf_program__fd(prog);
126 	if (prog_fd < 0) {
127 		err = 5;
128 		goto cleanup;
129 	}
130 
131 	if (bpf_prog_test_run_opts(prog_fd, NULL)) {
132 		err = 6;
133 		goto cleanup;
134 	}
135 
136 	if (skel->bss->err)
137 		err = 7 + skel->bss->err;
138 cleanup:
139 	task_kfunc_success__destroy(skel);
140 	return err;
141 }
142 
143 static void run_vpid_success_test(const char *prog_name)
144 {
145 	const int stack_size = 1024 * 1024;
146 	int child_pid, wstatus;
147 	char *stack;
148 
149 	stack = (char *)malloc(stack_size);
150 	if (!ASSERT_OK_PTR(stack, "clone_stack"))
151 		return;
152 
153 	child_pid = clone(run_vpid_test, stack + stack_size,
154 			  CLONE_NEWPID | SIGCHLD, (void *)prog_name);
155 	if (!ASSERT_GT(child_pid, -1, "child_pid"))
156 		goto cleanup;
157 
158 	if (!ASSERT_GT(waitpid(child_pid, &wstatus, 0), -1, "waitpid"))
159 		goto cleanup;
160 
161 	if (WEXITSTATUS(wstatus) > 7)
162 		ASSERT_OK(WEXITSTATUS(wstatus) - 7, "vpid_test_failure");
163 	else
164 		ASSERT_OK(WEXITSTATUS(wstatus), "run_vpid_test_err");
165 cleanup:
166 	free(stack);
167 }
168 
169 static const char * const success_tests[] = {
170 	"test_task_acquire_release_argument",
171 	"test_task_acquire_release_current",
172 	"test_task_acquire_leave_in_map",
173 	"test_task_map_acquire_release",
174 	"test_task_current_acquire_release",
175 	"test_task_from_pid_arg",
176 	"test_task_from_pid_current",
177 	"test_task_from_pid_invalid",
178 	"task_kfunc_acquire_trusted_walked",
179 	"test_task_kfunc_flavor_relo",
180 	"test_task_kfunc_flavor_relo_not_found",
181 };
182 
183 static const char * const syscall_success_tests[] = {
184 	"test_task_xchg_release",
185 };
186 
187 static const char * const vpid_success_tests[] = {
188 	"test_task_from_vpid_current",
189 	"test_task_from_vpid_invalid",
190 };
191 
192 void test_task_kfunc(void)
193 {
194 	int i;
195 
196 	for (i = 0; i < ARRAY_SIZE(success_tests); i++) {
197 		if (!test__start_subtest(success_tests[i]))
198 			continue;
199 
200 		run_success_test(success_tests[i]);
201 	}
202 
203 	for (i = 0; i < ARRAY_SIZE(syscall_success_tests); i++) {
204 		if (!test__start_subtest(syscall_success_tests[i]))
205 			continue;
206 
207 		run_syscall_success_test(syscall_success_tests[i]);
208 	}
209 
210 	for (i = 0; i < ARRAY_SIZE(vpid_success_tests); i++) {
211 		if (!test__start_subtest(vpid_success_tests[i]))
212 			continue;
213 
214 		run_vpid_success_test(vpid_success_tests[i]);
215 	}
216 
217 	RUN_TESTS(task_kfunc_failure);
218 }
219