1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2021 Facebook */
3 #include <test_progs.h>
4 #include <network_helpers.h>
5 #include "kfunc_call_fail.skel.h"
6 #include "kfunc_call_test.skel.h"
7 #include "kfunc_call_test.lskel.h"
8 #include "kfunc_call_test_subprog.skel.h"
9 #include "kfunc_call_test_subprog.lskel.h"
10 #include "kfunc_call_destructive.skel.h"
11 
12 #include "cap_helpers.h"
13 
14 static size_t log_buf_sz = 1048576; /* 1 MB */
15 static char obj_log_buf[1048576];
16 
17 enum kfunc_test_type {
18 	tc_test = 0,
19 	syscall_test,
20 	syscall_null_ctx_test,
21 };
22 
23 struct kfunc_test_params {
24 	const char *prog_name;
25 	unsigned long lskel_prog_desc_offset;
26 	int retval;
27 	enum kfunc_test_type test_type;
28 	const char *expected_err_msg;
29 };
30 
31 #define __BPF_TEST_SUCCESS(name, __retval, type) \
32 	{ \
33 	  .prog_name = #name, \
34 	  .lskel_prog_desc_offset = offsetof(struct kfunc_call_test_lskel, progs.name), \
35 	  .retval = __retval, \
36 	  .test_type = type, \
37 	  .expected_err_msg = NULL, \
38 	}
39 
40 #define __BPF_TEST_FAIL(name, __retval, type, error_msg) \
41 	{ \
42 	  .prog_name = #name, \
43 	  .lskel_prog_desc_offset = 0 /* unused when test is failing */, \
44 	  .retval = __retval, \
45 	  .test_type = type, \
46 	  .expected_err_msg = error_msg, \
47 	}
48 
49 #define TC_TEST(name, retval) __BPF_TEST_SUCCESS(name, retval, tc_test)
50 #define SYSCALL_TEST(name, retval) __BPF_TEST_SUCCESS(name, retval, syscall_test)
51 #define SYSCALL_NULL_CTX_TEST(name, retval) __BPF_TEST_SUCCESS(name, retval, syscall_null_ctx_test)
52 
53 #define TC_FAIL(name, retval, error_msg) __BPF_TEST_FAIL(name, retval, tc_test, error_msg)
54 #define SYSCALL_NULL_CTX_FAIL(name, retval, error_msg) \
55 	__BPF_TEST_FAIL(name, retval, syscall_null_ctx_test, error_msg)
56 
57 static struct kfunc_test_params kfunc_tests[] = {
58 	/* failure cases:
59 	 * if retval is 0 -> the program will fail to load and the error message is an error
60 	 * if retval is not 0 -> the program can be loaded but running it will gives the
61 	 *                       provided return value. The error message is thus the one
62 	 *                       from a successful load
63 	 */
64 	SYSCALL_NULL_CTX_FAIL(kfunc_syscall_test_fail, -EINVAL, "processed 4 insns"),
65 	SYSCALL_NULL_CTX_FAIL(kfunc_syscall_test_null_fail, -EINVAL, "processed 4 insns"),
66 	TC_FAIL(kfunc_call_test_get_mem_fail_rdonly, 0, "R0 cannot write into rdonly_mem"),
67 	TC_FAIL(kfunc_call_test_get_mem_fail_use_after_free, 0, "invalid mem access 'scalar'"),
68 	TC_FAIL(kfunc_call_test_get_mem_fail_oob, 0, "min value is outside of the allowed memory range"),
69 	TC_FAIL(kfunc_call_test_get_mem_fail_not_const, 0, "is not a const"),
70 	TC_FAIL(kfunc_call_test_mem_acquire_fail, 0, "acquire kernel function does not return PTR_TO_BTF_ID"),
71 
72 	/* success cases */
73 	TC_TEST(kfunc_call_test1, 12),
74 	TC_TEST(kfunc_call_test2, 3),
75 	TC_TEST(kfunc_call_test_ref_btf_id, 0),
76 	TC_TEST(kfunc_call_test_get_mem, 42),
77 	SYSCALL_TEST(kfunc_syscall_test, 0),
78 	SYSCALL_NULL_CTX_TEST(kfunc_syscall_test_null, 0),
79 };
80 
81 struct syscall_test_args {
82 	__u8 data[16];
83 	size_t size;
84 };
85 
86 static void verify_success(struct kfunc_test_params *param)
87 {
88 	struct kfunc_call_test_lskel *lskel = NULL;
89 	LIBBPF_OPTS(bpf_test_run_opts, topts);
90 	struct bpf_prog_desc *lskel_prog;
91 	struct kfunc_call_test *skel;
92 	struct bpf_program *prog;
93 	int prog_fd, err;
94 	struct syscall_test_args args = {
95 		.size = 10,
96 	};
97 
98 	switch (param->test_type) {
99 	case syscall_test:
100 		topts.ctx_in = &args;
101 		topts.ctx_size_in = sizeof(args);
102 		/* fallthrough */
103 	case syscall_null_ctx_test:
104 		break;
105 	case tc_test:
106 		topts.data_in = &pkt_v4;
107 		topts.data_size_in = sizeof(pkt_v4);
108 		topts.repeat = 1;
109 		break;
110 	}
111 
112 	/* first test with normal libbpf */
113 	skel = kfunc_call_test__open_and_load();
114 	if (!ASSERT_OK_PTR(skel, "skel"))
115 		return;
116 
117 	prog = bpf_object__find_program_by_name(skel->obj, param->prog_name);
118 	if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name"))
119 		goto cleanup;
120 
121 	prog_fd = bpf_program__fd(prog);
122 	err = bpf_prog_test_run_opts(prog_fd, &topts);
123 	if (!ASSERT_OK(err, param->prog_name))
124 		goto cleanup;
125 
126 	if (!ASSERT_EQ(topts.retval, param->retval, "retval"))
127 		goto cleanup;
128 
129 	/* second test with light skeletons */
130 	lskel = kfunc_call_test_lskel__open_and_load();
131 	if (!ASSERT_OK_PTR(lskel, "lskel"))
132 		goto cleanup;
133 
134 	lskel_prog = (struct bpf_prog_desc *)((char *)lskel + param->lskel_prog_desc_offset);
135 
136 	prog_fd = lskel_prog->prog_fd;
137 	err = bpf_prog_test_run_opts(prog_fd, &topts);
138 	if (!ASSERT_OK(err, param->prog_name))
139 		goto cleanup;
140 
141 	ASSERT_EQ(topts.retval, param->retval, "retval");
142 
143 cleanup:
144 	kfunc_call_test__destroy(skel);
145 	if (lskel)
146 		kfunc_call_test_lskel__destroy(lskel);
147 }
148 
149 static void verify_fail(struct kfunc_test_params *param)
150 {
151 	LIBBPF_OPTS(bpf_object_open_opts, opts);
152 	LIBBPF_OPTS(bpf_test_run_opts, topts);
153 	struct bpf_program *prog;
154 	struct kfunc_call_fail *skel;
155 	int prog_fd, err;
156 	struct syscall_test_args args = {
157 		.size = 10,
158 	};
159 
160 	opts.kernel_log_buf = obj_log_buf;
161 	opts.kernel_log_size = log_buf_sz;
162 	opts.kernel_log_level = 1;
163 
164 	switch (param->test_type) {
165 	case syscall_test:
166 		topts.ctx_in = &args;
167 		topts.ctx_size_in = sizeof(args);
168 		/* fallthrough */
169 	case syscall_null_ctx_test:
170 		break;
171 	case tc_test:
172 		topts.data_in = &pkt_v4;
173 		topts.data_size_in = sizeof(pkt_v4);
174 		break;
175 		topts.repeat = 1;
176 	}
177 
178 	skel = kfunc_call_fail__open_opts(&opts);
179 	if (!ASSERT_OK_PTR(skel, "kfunc_call_fail__open_opts"))
180 		goto cleanup;
181 
182 	prog = bpf_object__find_program_by_name(skel->obj, param->prog_name);
183 	if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name"))
184 		goto cleanup;
185 
186 	bpf_program__set_autoload(prog, true);
187 
188 	err = kfunc_call_fail__load(skel);
189 	if (!param->retval) {
190 		/* the verifier is supposed to complain and refuses to load */
191 		if (!ASSERT_ERR(err, "unexpected load success"))
192 			goto out_err;
193 
194 	} else {
195 		/* the program is loaded but must dynamically fail */
196 		if (!ASSERT_OK(err, "unexpected load error"))
197 			goto out_err;
198 
199 		prog_fd = bpf_program__fd(prog);
200 		err = bpf_prog_test_run_opts(prog_fd, &topts);
201 		if (!ASSERT_EQ(err, param->retval, param->prog_name))
202 			goto out_err;
203 	}
204 
205 out_err:
206 	if (!ASSERT_OK_PTR(strstr(obj_log_buf, param->expected_err_msg), "expected_err_msg")) {
207 		fprintf(stderr, "Expected err_msg: %s\n", param->expected_err_msg);
208 		fprintf(stderr, "Verifier output: %s\n", obj_log_buf);
209 	}
210 
211 cleanup:
212 	kfunc_call_fail__destroy(skel);
213 }
214 
215 static void test_main(void)
216 {
217 	int i;
218 
219 	for (i = 0; i < ARRAY_SIZE(kfunc_tests); i++) {
220 		if (!test__start_subtest(kfunc_tests[i].prog_name))
221 			continue;
222 
223 		if (!kfunc_tests[i].expected_err_msg)
224 			verify_success(&kfunc_tests[i]);
225 		else
226 			verify_fail(&kfunc_tests[i]);
227 	}
228 }
229 
230 static void test_subprog(void)
231 {
232 	struct kfunc_call_test_subprog *skel;
233 	int prog_fd, err;
234 	LIBBPF_OPTS(bpf_test_run_opts, topts,
235 		.data_in = &pkt_v4,
236 		.data_size_in = sizeof(pkt_v4),
237 		.repeat = 1,
238 	);
239 
240 	skel = kfunc_call_test_subprog__open_and_load();
241 	if (!ASSERT_OK_PTR(skel, "skel"))
242 		return;
243 
244 	prog_fd = bpf_program__fd(skel->progs.kfunc_call_test1);
245 	err = bpf_prog_test_run_opts(prog_fd, &topts);
246 	ASSERT_OK(err, "bpf_prog_test_run(test1)");
247 	ASSERT_EQ(topts.retval, 10, "test1-retval");
248 	ASSERT_NEQ(skel->data->active_res, -1, "active_res");
249 	ASSERT_EQ(skel->data->sk_state_res, BPF_TCP_CLOSE, "sk_state_res");
250 
251 	kfunc_call_test_subprog__destroy(skel);
252 }
253 
254 static void test_subprog_lskel(void)
255 {
256 	struct kfunc_call_test_subprog_lskel *skel;
257 	int prog_fd, err;
258 	LIBBPF_OPTS(bpf_test_run_opts, topts,
259 		.data_in = &pkt_v4,
260 		.data_size_in = sizeof(pkt_v4),
261 		.repeat = 1,
262 	);
263 
264 	skel = kfunc_call_test_subprog_lskel__open_and_load();
265 	if (!ASSERT_OK_PTR(skel, "skel"))
266 		return;
267 
268 	prog_fd = skel->progs.kfunc_call_test1.prog_fd;
269 	err = bpf_prog_test_run_opts(prog_fd, &topts);
270 	ASSERT_OK(err, "bpf_prog_test_run(test1)");
271 	ASSERT_EQ(topts.retval, 10, "test1-retval");
272 	ASSERT_NEQ(skel->data->active_res, -1, "active_res");
273 	ASSERT_EQ(skel->data->sk_state_res, BPF_TCP_CLOSE, "sk_state_res");
274 
275 	kfunc_call_test_subprog_lskel__destroy(skel);
276 }
277 
278 static int test_destructive_open_and_load(void)
279 {
280 	struct kfunc_call_destructive *skel;
281 	int err;
282 
283 	skel = kfunc_call_destructive__open();
284 	if (!ASSERT_OK_PTR(skel, "prog_open"))
285 		return -1;
286 
287 	err = kfunc_call_destructive__load(skel);
288 
289 	kfunc_call_destructive__destroy(skel);
290 
291 	return err;
292 }
293 
294 static void test_destructive(void)
295 {
296 	__u64 save_caps = 0;
297 
298 	ASSERT_OK(test_destructive_open_and_load(), "successful_load");
299 
300 	if (!ASSERT_OK(cap_disable_effective(1ULL << CAP_SYS_BOOT, &save_caps), "drop_caps"))
301 		return;
302 
303 	ASSERT_EQ(test_destructive_open_and_load(), -13, "no_caps_failure");
304 
305 	cap_enable_effective(save_caps, NULL);
306 }
307 
308 void test_kfunc_call(void)
309 {
310 	test_main();
311 
312 	if (test__start_subtest("subprog"))
313 		test_subprog();
314 
315 	if (test__start_subtest("subprog_lskel"))
316 		test_subprog_lskel();
317 
318 	if (test__start_subtest("destructive"))
319 		test_destructive();
320 }
321