17bd1590dSMartin KaFai Lau // SPDX-License-Identifier: GPL-2.0
27bd1590dSMartin KaFai Lau /* Copyright (c) 2021 Facebook */
37bd1590dSMartin KaFai Lau #include <test_progs.h>
47bd1590dSMartin KaFai Lau #include <network_helpers.h>
5fb66223aSBenjamin Tissoires #include "kfunc_call_fail.skel.h"
6012ba115SBenjamin Tissoires #include "kfunc_call_test.skel.h"
74d1b6298SAlexei Starovoitov #include "kfunc_call_test.lskel.h"
87bd1590dSMartin KaFai Lau #include "kfunc_call_test_subprog.skel.h"
9bc5f75daSAlexei Starovoitov #include "kfunc_call_test_subprog.lskel.h"
10e3389458SArtem Savkov #include "kfunc_call_destructive.skel.h"
11e3389458SArtem Savkov
12e3389458SArtem Savkov #include "cap_helpers.h"
137bd1590dSMartin KaFai Lau
14fb66223aSBenjamin Tissoires static size_t log_buf_sz = 1048576; /* 1 MB */
15fb66223aSBenjamin Tissoires static char obj_log_buf[1048576];
16fb66223aSBenjamin Tissoires
17fb66223aSBenjamin Tissoires enum kfunc_test_type {
18fb66223aSBenjamin Tissoires tc_test = 0,
19fb66223aSBenjamin Tissoires syscall_test,
20fb66223aSBenjamin Tissoires syscall_null_ctx_test,
21fb66223aSBenjamin Tissoires };
22fb66223aSBenjamin Tissoires
23012ba115SBenjamin Tissoires struct kfunc_test_params {
24012ba115SBenjamin Tissoires const char *prog_name;
25012ba115SBenjamin Tissoires unsigned long lskel_prog_desc_offset;
26012ba115SBenjamin Tissoires int retval;
27fb66223aSBenjamin Tissoires enum kfunc_test_type test_type;
28fb66223aSBenjamin Tissoires const char *expected_err_msg;
29012ba115SBenjamin Tissoires };
30012ba115SBenjamin Tissoires
31fb66223aSBenjamin Tissoires #define __BPF_TEST_SUCCESS(name, __retval, type) \
32012ba115SBenjamin Tissoires { \
33012ba115SBenjamin Tissoires .prog_name = #name, \
34012ba115SBenjamin Tissoires .lskel_prog_desc_offset = offsetof(struct kfunc_call_test_lskel, progs.name), \
35012ba115SBenjamin Tissoires .retval = __retval, \
36fb66223aSBenjamin Tissoires .test_type = type, \
37fb66223aSBenjamin Tissoires .expected_err_msg = NULL, \
38012ba115SBenjamin Tissoires }
39012ba115SBenjamin Tissoires
40fb66223aSBenjamin Tissoires #define __BPF_TEST_FAIL(name, __retval, type, error_msg) \
41fb66223aSBenjamin Tissoires { \
42fb66223aSBenjamin Tissoires .prog_name = #name, \
43fb66223aSBenjamin Tissoires .lskel_prog_desc_offset = 0 /* unused when test is failing */, \
44fb66223aSBenjamin Tissoires .retval = __retval, \
45fb66223aSBenjamin Tissoires .test_type = type, \
46fb66223aSBenjamin Tissoires .expected_err_msg = error_msg, \
47fb66223aSBenjamin Tissoires }
48fb66223aSBenjamin Tissoires
49fb66223aSBenjamin Tissoires #define TC_TEST(name, retval) __BPF_TEST_SUCCESS(name, retval, tc_test)
50fb66223aSBenjamin Tissoires #define SYSCALL_TEST(name, retval) __BPF_TEST_SUCCESS(name, retval, syscall_test)
51fb66223aSBenjamin Tissoires #define SYSCALL_NULL_CTX_TEST(name, retval) __BPF_TEST_SUCCESS(name, retval, syscall_null_ctx_test)
52fb66223aSBenjamin Tissoires
5322ed8d5aSBenjamin Tissoires #define TC_FAIL(name, retval, error_msg) __BPF_TEST_FAIL(name, retval, tc_test, error_msg)
54fb66223aSBenjamin Tissoires #define SYSCALL_NULL_CTX_FAIL(name, retval, error_msg) \
55fb66223aSBenjamin Tissoires __BPF_TEST_FAIL(name, retval, syscall_null_ctx_test, error_msg)
56fb66223aSBenjamin Tissoires
57012ba115SBenjamin Tissoires static struct kfunc_test_params kfunc_tests[] = {
58fb66223aSBenjamin Tissoires /* failure cases:
59fb66223aSBenjamin Tissoires * if retval is 0 -> the program will fail to load and the error message is an error
60fb66223aSBenjamin Tissoires * if retval is not 0 -> the program can be loaded but running it will gives the
61fb66223aSBenjamin Tissoires * provided return value. The error message is thus the one
62fb66223aSBenjamin Tissoires * from a successful load
63fb66223aSBenjamin Tissoires */
64fb66223aSBenjamin Tissoires SYSCALL_NULL_CTX_FAIL(kfunc_syscall_test_fail, -EINVAL, "processed 4 insns"),
65fb66223aSBenjamin Tissoires SYSCALL_NULL_CTX_FAIL(kfunc_syscall_test_null_fail, -EINVAL, "processed 4 insns"),
6622ed8d5aSBenjamin Tissoires TC_FAIL(kfunc_call_test_get_mem_fail_rdonly, 0, "R0 cannot write into rdonly_mem"),
6722ed8d5aSBenjamin Tissoires TC_FAIL(kfunc_call_test_get_mem_fail_use_after_free, 0, "invalid mem access 'scalar'"),
6822ed8d5aSBenjamin Tissoires TC_FAIL(kfunc_call_test_get_mem_fail_oob, 0, "min value is outside of the allowed memory range"),
6922ed8d5aSBenjamin Tissoires TC_FAIL(kfunc_call_test_get_mem_fail_not_const, 0, "is not a const"),
7022ed8d5aSBenjamin Tissoires TC_FAIL(kfunc_call_test_mem_acquire_fail, 0, "acquire kernel function does not return PTR_TO_BTF_ID"),
71fb66223aSBenjamin Tissoires
72fb66223aSBenjamin Tissoires /* success cases */
73012ba115SBenjamin Tissoires TC_TEST(kfunc_call_test1, 12),
74012ba115SBenjamin Tissoires TC_TEST(kfunc_call_test2, 3),
75be6b5c10SIlya Leoshkevich TC_TEST(kfunc_call_test4, -1234),
76012ba115SBenjamin Tissoires TC_TEST(kfunc_call_test_ref_btf_id, 0),
7722ed8d5aSBenjamin Tissoires TC_TEST(kfunc_call_test_get_mem, 42),
78fb66223aSBenjamin Tissoires SYSCALL_TEST(kfunc_syscall_test, 0),
79fb66223aSBenjamin Tissoires SYSCALL_NULL_CTX_TEST(kfunc_syscall_test_null, 0),
806aed15e3SDavid Vernet TC_TEST(kfunc_call_test_static_unused_arg, 0),
81fb66223aSBenjamin Tissoires };
82fb66223aSBenjamin Tissoires
83fb66223aSBenjamin Tissoires struct syscall_test_args {
84fb66223aSBenjamin Tissoires __u8 data[16];
85fb66223aSBenjamin Tissoires size_t size;
86012ba115SBenjamin Tissoires };
87012ba115SBenjamin Tissoires
verify_success(struct kfunc_test_params * param)88012ba115SBenjamin Tissoires static void verify_success(struct kfunc_test_params *param)
897bd1590dSMartin KaFai Lau {
90012ba115SBenjamin Tissoires struct kfunc_call_test_lskel *lskel = NULL;
91fb66223aSBenjamin Tissoires LIBBPF_OPTS(bpf_test_run_opts, topts);
92012ba115SBenjamin Tissoires struct bpf_prog_desc *lskel_prog;
93012ba115SBenjamin Tissoires struct kfunc_call_test *skel;
94012ba115SBenjamin Tissoires struct bpf_program *prog;
9504fcb5f9SDelyan Kratunov int prog_fd, err;
96fb66223aSBenjamin Tissoires struct syscall_test_args args = {
97fb66223aSBenjamin Tissoires .size = 10,
98fb66223aSBenjamin Tissoires };
99fb66223aSBenjamin Tissoires
100fb66223aSBenjamin Tissoires switch (param->test_type) {
101fb66223aSBenjamin Tissoires case syscall_test:
102fb66223aSBenjamin Tissoires topts.ctx_in = &args;
103fb66223aSBenjamin Tissoires topts.ctx_size_in = sizeof(args);
104fb66223aSBenjamin Tissoires /* fallthrough */
105fb66223aSBenjamin Tissoires case syscall_null_ctx_test:
106fb66223aSBenjamin Tissoires break;
107fb66223aSBenjamin Tissoires case tc_test:
108fb66223aSBenjamin Tissoires topts.data_in = &pkt_v4;
109fb66223aSBenjamin Tissoires topts.data_size_in = sizeof(pkt_v4);
110fb66223aSBenjamin Tissoires topts.repeat = 1;
111fb66223aSBenjamin Tissoires break;
112fb66223aSBenjamin Tissoires }
1137bd1590dSMartin KaFai Lau
114012ba115SBenjamin Tissoires /* first test with normal libbpf */
115012ba115SBenjamin Tissoires skel = kfunc_call_test__open_and_load();
1167bd1590dSMartin KaFai Lau if (!ASSERT_OK_PTR(skel, "skel"))
1177bd1590dSMartin KaFai Lau return;
1187bd1590dSMartin KaFai Lau
119012ba115SBenjamin Tissoires prog = bpf_object__find_program_by_name(skel->obj, param->prog_name);
120012ba115SBenjamin Tissoires if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name"))
121012ba115SBenjamin Tissoires goto cleanup;
1227bd1590dSMartin KaFai Lau
123012ba115SBenjamin Tissoires prog_fd = bpf_program__fd(prog);
12404fcb5f9SDelyan Kratunov err = bpf_prog_test_run_opts(prog_fd, &topts);
125012ba115SBenjamin Tissoires if (!ASSERT_OK(err, param->prog_name))
126012ba115SBenjamin Tissoires goto cleanup;
1277bd1590dSMartin KaFai Lau
128012ba115SBenjamin Tissoires if (!ASSERT_EQ(topts.retval, param->retval, "retval"))
129012ba115SBenjamin Tissoires goto cleanup;
130012ba115SBenjamin Tissoires
131012ba115SBenjamin Tissoires /* second test with light skeletons */
132012ba115SBenjamin Tissoires lskel = kfunc_call_test_lskel__open_and_load();
133012ba115SBenjamin Tissoires if (!ASSERT_OK_PTR(lskel, "lskel"))
134012ba115SBenjamin Tissoires goto cleanup;
135012ba115SBenjamin Tissoires
136012ba115SBenjamin Tissoires lskel_prog = (struct bpf_prog_desc *)((char *)lskel + param->lskel_prog_desc_offset);
137012ba115SBenjamin Tissoires
138012ba115SBenjamin Tissoires prog_fd = lskel_prog->prog_fd;
13904fcb5f9SDelyan Kratunov err = bpf_prog_test_run_opts(prog_fd, &topts);
140012ba115SBenjamin Tissoires if (!ASSERT_OK(err, param->prog_name))
141012ba115SBenjamin Tissoires goto cleanup;
142c1ff181fSKumar Kartikeya Dwivedi
143012ba115SBenjamin Tissoires ASSERT_EQ(topts.retval, param->retval, "retval");
144012ba115SBenjamin Tissoires
145012ba115SBenjamin Tissoires cleanup:
146012ba115SBenjamin Tissoires kfunc_call_test__destroy(skel);
147012ba115SBenjamin Tissoires if (lskel)
148012ba115SBenjamin Tissoires kfunc_call_test_lskel__destroy(lskel);
149012ba115SBenjamin Tissoires }
150012ba115SBenjamin Tissoires
verify_fail(struct kfunc_test_params * param)151fb66223aSBenjamin Tissoires static void verify_fail(struct kfunc_test_params *param)
152fb66223aSBenjamin Tissoires {
153fb66223aSBenjamin Tissoires LIBBPF_OPTS(bpf_object_open_opts, opts);
154fb66223aSBenjamin Tissoires LIBBPF_OPTS(bpf_test_run_opts, topts);
155fb66223aSBenjamin Tissoires struct bpf_program *prog;
156fb66223aSBenjamin Tissoires struct kfunc_call_fail *skel;
157fb66223aSBenjamin Tissoires int prog_fd, err;
158fb66223aSBenjamin Tissoires struct syscall_test_args args = {
159fb66223aSBenjamin Tissoires .size = 10,
160fb66223aSBenjamin Tissoires };
161fb66223aSBenjamin Tissoires
162fb66223aSBenjamin Tissoires opts.kernel_log_buf = obj_log_buf;
163fb66223aSBenjamin Tissoires opts.kernel_log_size = log_buf_sz;
164fb66223aSBenjamin Tissoires opts.kernel_log_level = 1;
165fb66223aSBenjamin Tissoires
166fb66223aSBenjamin Tissoires switch (param->test_type) {
167fb66223aSBenjamin Tissoires case syscall_test:
168fb66223aSBenjamin Tissoires topts.ctx_in = &args;
169fb66223aSBenjamin Tissoires topts.ctx_size_in = sizeof(args);
170fb66223aSBenjamin Tissoires /* fallthrough */
171fb66223aSBenjamin Tissoires case syscall_null_ctx_test:
172fb66223aSBenjamin Tissoires break;
173fb66223aSBenjamin Tissoires case tc_test:
174fb66223aSBenjamin Tissoires topts.data_in = &pkt_v4;
175fb66223aSBenjamin Tissoires topts.data_size_in = sizeof(pkt_v4);
176fb66223aSBenjamin Tissoires topts.repeat = 1;
177*811915dbSYipeng Zou break;
178fb66223aSBenjamin Tissoires }
179fb66223aSBenjamin Tissoires
180fb66223aSBenjamin Tissoires skel = kfunc_call_fail__open_opts(&opts);
181fb66223aSBenjamin Tissoires if (!ASSERT_OK_PTR(skel, "kfunc_call_fail__open_opts"))
182fb66223aSBenjamin Tissoires goto cleanup;
183fb66223aSBenjamin Tissoires
184fb66223aSBenjamin Tissoires prog = bpf_object__find_program_by_name(skel->obj, param->prog_name);
185fb66223aSBenjamin Tissoires if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name"))
186fb66223aSBenjamin Tissoires goto cleanup;
187fb66223aSBenjamin Tissoires
188fb66223aSBenjamin Tissoires bpf_program__set_autoload(prog, true);
189fb66223aSBenjamin Tissoires
190fb66223aSBenjamin Tissoires err = kfunc_call_fail__load(skel);
191fb66223aSBenjamin Tissoires if (!param->retval) {
192fb66223aSBenjamin Tissoires /* the verifier is supposed to complain and refuses to load */
193fb66223aSBenjamin Tissoires if (!ASSERT_ERR(err, "unexpected load success"))
194fb66223aSBenjamin Tissoires goto out_err;
195fb66223aSBenjamin Tissoires
196fb66223aSBenjamin Tissoires } else {
197fb66223aSBenjamin Tissoires /* the program is loaded but must dynamically fail */
198fb66223aSBenjamin Tissoires if (!ASSERT_OK(err, "unexpected load error"))
199fb66223aSBenjamin Tissoires goto out_err;
200fb66223aSBenjamin Tissoires
201fb66223aSBenjamin Tissoires prog_fd = bpf_program__fd(prog);
202fb66223aSBenjamin Tissoires err = bpf_prog_test_run_opts(prog_fd, &topts);
203fb66223aSBenjamin Tissoires if (!ASSERT_EQ(err, param->retval, param->prog_name))
204fb66223aSBenjamin Tissoires goto out_err;
205fb66223aSBenjamin Tissoires }
206fb66223aSBenjamin Tissoires
207fb66223aSBenjamin Tissoires out_err:
208fb66223aSBenjamin Tissoires if (!ASSERT_OK_PTR(strstr(obj_log_buf, param->expected_err_msg), "expected_err_msg")) {
209fb66223aSBenjamin Tissoires fprintf(stderr, "Expected err_msg: %s\n", param->expected_err_msg);
210fb66223aSBenjamin Tissoires fprintf(stderr, "Verifier output: %s\n", obj_log_buf);
211fb66223aSBenjamin Tissoires }
212fb66223aSBenjamin Tissoires
213fb66223aSBenjamin Tissoires cleanup:
214fb66223aSBenjamin Tissoires kfunc_call_fail__destroy(skel);
215fb66223aSBenjamin Tissoires }
216fb66223aSBenjamin Tissoires
test_main(void)217012ba115SBenjamin Tissoires static void test_main(void)
218012ba115SBenjamin Tissoires {
219012ba115SBenjamin Tissoires int i;
220012ba115SBenjamin Tissoires
221012ba115SBenjamin Tissoires for (i = 0; i < ARRAY_SIZE(kfunc_tests); i++) {
222012ba115SBenjamin Tissoires if (!test__start_subtest(kfunc_tests[i].prog_name))
223012ba115SBenjamin Tissoires continue;
224012ba115SBenjamin Tissoires
225fb66223aSBenjamin Tissoires if (!kfunc_tests[i].expected_err_msg)
226012ba115SBenjamin Tissoires verify_success(&kfunc_tests[i]);
227fb66223aSBenjamin Tissoires else
228fb66223aSBenjamin Tissoires verify_fail(&kfunc_tests[i]);
229012ba115SBenjamin Tissoires }
2307bd1590dSMartin KaFai Lau }
2317bd1590dSMartin KaFai Lau
test_subprog(void)2327bd1590dSMartin KaFai Lau static void test_subprog(void)
2337bd1590dSMartin KaFai Lau {
2347bd1590dSMartin KaFai Lau struct kfunc_call_test_subprog *skel;
23504fcb5f9SDelyan Kratunov int prog_fd, err;
23604fcb5f9SDelyan Kratunov LIBBPF_OPTS(bpf_test_run_opts, topts,
23704fcb5f9SDelyan Kratunov .data_in = &pkt_v4,
23804fcb5f9SDelyan Kratunov .data_size_in = sizeof(pkt_v4),
23904fcb5f9SDelyan Kratunov .repeat = 1,
24004fcb5f9SDelyan Kratunov );
2417bd1590dSMartin KaFai Lau
2427bd1590dSMartin KaFai Lau skel = kfunc_call_test_subprog__open_and_load();
2437bd1590dSMartin KaFai Lau if (!ASSERT_OK_PTR(skel, "skel"))
2447bd1590dSMartin KaFai Lau return;
2457bd1590dSMartin KaFai Lau
2467bd1590dSMartin KaFai Lau prog_fd = bpf_program__fd(skel->progs.kfunc_call_test1);
24704fcb5f9SDelyan Kratunov err = bpf_prog_test_run_opts(prog_fd, &topts);
2487bd1590dSMartin KaFai Lau ASSERT_OK(err, "bpf_prog_test_run(test1)");
24904fcb5f9SDelyan Kratunov ASSERT_EQ(topts.retval, 10, "test1-retval");
2507bd1590dSMartin KaFai Lau ASSERT_NEQ(skel->data->active_res, -1, "active_res");
251700dcf0fSMartin KaFai Lau ASSERT_EQ(skel->data->sk_state_res, BPF_TCP_CLOSE, "sk_state_res");
2527bd1590dSMartin KaFai Lau
2537bd1590dSMartin KaFai Lau kfunc_call_test_subprog__destroy(skel);
2547bd1590dSMartin KaFai Lau }
2557bd1590dSMartin KaFai Lau
test_subprog_lskel(void)256bc5f75daSAlexei Starovoitov static void test_subprog_lskel(void)
257bc5f75daSAlexei Starovoitov {
258bc5f75daSAlexei Starovoitov struct kfunc_call_test_subprog_lskel *skel;
25904fcb5f9SDelyan Kratunov int prog_fd, err;
26004fcb5f9SDelyan Kratunov LIBBPF_OPTS(bpf_test_run_opts, topts,
26104fcb5f9SDelyan Kratunov .data_in = &pkt_v4,
26204fcb5f9SDelyan Kratunov .data_size_in = sizeof(pkt_v4),
26304fcb5f9SDelyan Kratunov .repeat = 1,
26404fcb5f9SDelyan Kratunov );
265bc5f75daSAlexei Starovoitov
266bc5f75daSAlexei Starovoitov skel = kfunc_call_test_subprog_lskel__open_and_load();
267bc5f75daSAlexei Starovoitov if (!ASSERT_OK_PTR(skel, "skel"))
268bc5f75daSAlexei Starovoitov return;
269bc5f75daSAlexei Starovoitov
270bc5f75daSAlexei Starovoitov prog_fd = skel->progs.kfunc_call_test1.prog_fd;
27104fcb5f9SDelyan Kratunov err = bpf_prog_test_run_opts(prog_fd, &topts);
272bc5f75daSAlexei Starovoitov ASSERT_OK(err, "bpf_prog_test_run(test1)");
27304fcb5f9SDelyan Kratunov ASSERT_EQ(topts.retval, 10, "test1-retval");
274bc5f75daSAlexei Starovoitov ASSERT_NEQ(skel->data->active_res, -1, "active_res");
275bc5f75daSAlexei Starovoitov ASSERT_EQ(skel->data->sk_state_res, BPF_TCP_CLOSE, "sk_state_res");
276bc5f75daSAlexei Starovoitov
277bc5f75daSAlexei Starovoitov kfunc_call_test_subprog_lskel__destroy(skel);
278bc5f75daSAlexei Starovoitov }
279bc5f75daSAlexei Starovoitov
test_destructive_open_and_load(void)280e3389458SArtem Savkov static int test_destructive_open_and_load(void)
281e3389458SArtem Savkov {
282e3389458SArtem Savkov struct kfunc_call_destructive *skel;
283e3389458SArtem Savkov int err;
284e3389458SArtem Savkov
285e3389458SArtem Savkov skel = kfunc_call_destructive__open();
286e3389458SArtem Savkov if (!ASSERT_OK_PTR(skel, "prog_open"))
287e3389458SArtem Savkov return -1;
288e3389458SArtem Savkov
289e3389458SArtem Savkov err = kfunc_call_destructive__load(skel);
290e3389458SArtem Savkov
291e3389458SArtem Savkov kfunc_call_destructive__destroy(skel);
292e3389458SArtem Savkov
293e3389458SArtem Savkov return err;
294e3389458SArtem Savkov }
295e3389458SArtem Savkov
test_destructive(void)296e3389458SArtem Savkov static void test_destructive(void)
297e3389458SArtem Savkov {
298e3389458SArtem Savkov __u64 save_caps = 0;
299e3389458SArtem Savkov
300e918cd23SColin Ian King ASSERT_OK(test_destructive_open_and_load(), "successful_load");
301e3389458SArtem Savkov
302e3389458SArtem Savkov if (!ASSERT_OK(cap_disable_effective(1ULL << CAP_SYS_BOOT, &save_caps), "drop_caps"))
303e3389458SArtem Savkov return;
304e3389458SArtem Savkov
305e3389458SArtem Savkov ASSERT_EQ(test_destructive_open_and_load(), -13, "no_caps_failure");
306e3389458SArtem Savkov
307e3389458SArtem Savkov cap_enable_effective(save_caps, NULL);
308e3389458SArtem Savkov }
309e3389458SArtem Savkov
test_kfunc_call(void)3107bd1590dSMartin KaFai Lau void test_kfunc_call(void)
3117bd1590dSMartin KaFai Lau {
3127bd1590dSMartin KaFai Lau test_main();
3137bd1590dSMartin KaFai Lau
3147bd1590dSMartin KaFai Lau if (test__start_subtest("subprog"))
3157bd1590dSMartin KaFai Lau test_subprog();
316bc5f75daSAlexei Starovoitov
317bc5f75daSAlexei Starovoitov if (test__start_subtest("subprog_lskel"))
318bc5f75daSAlexei Starovoitov test_subprog_lskel();
319e3389458SArtem Savkov
320e3389458SArtem Savkov if (test__start_subtest("destructive"))
321e3389458SArtem Savkov test_destructive();
3227bd1590dSMartin KaFai Lau }
323