325 lines · c
1// SPDX-License-Identifier: GPL-2.02/* 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 14static size_t log_buf_sz = 1048576; /* 1 MB */15static char obj_log_buf[1048576];16 17enum kfunc_test_type {18 tc_test = 0,19 syscall_test,20 syscall_null_ctx_test,21};22 23struct 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 57static 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 error60 * if retval is not 0 -> the program can be loaded but running it will gives the61 * provided return value. The error message is thus the one62 * from a successful load63 */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 TC_FAIL(kfunc_call_test_pointer_arg_type_mismatch, 0, "arg#0 expected pointer to ctx, but got scalar"),72 73 /* success cases */74 TC_TEST(kfunc_call_test1, 12),75 TC_TEST(kfunc_call_test2, 3),76 TC_TEST(kfunc_call_test4, -1234),77 TC_TEST(kfunc_call_test_ref_btf_id, 0),78 TC_TEST(kfunc_call_test_get_mem, 42),79 SYSCALL_TEST(kfunc_syscall_test, 0),80 SYSCALL_NULL_CTX_TEST(kfunc_syscall_test_null, 0),81 TC_TEST(kfunc_call_test_static_unused_arg, 0),82 TC_TEST(kfunc_call_ctx, 0),83};84 85struct syscall_test_args {86 __u8 data[16];87 size_t size;88};89 90static void verify_success(struct kfunc_test_params *param)91{92 struct kfunc_call_test_lskel *lskel = NULL;93 LIBBPF_OPTS(bpf_test_run_opts, topts);94 struct bpf_prog_desc *lskel_prog;95 struct kfunc_call_test *skel;96 struct bpf_program *prog;97 int prog_fd, err;98 struct syscall_test_args args = {99 .size = 10,100 };101 102 switch (param->test_type) {103 case syscall_test:104 topts.ctx_in = &args;105 topts.ctx_size_in = sizeof(args);106 /* fallthrough */107 case syscall_null_ctx_test:108 break;109 case tc_test:110 topts.data_in = &pkt_v4;111 topts.data_size_in = sizeof(pkt_v4);112 topts.repeat = 1;113 break;114 }115 116 /* first test with normal libbpf */117 skel = kfunc_call_test__open_and_load();118 if (!ASSERT_OK_PTR(skel, "skel"))119 return;120 121 prog = bpf_object__find_program_by_name(skel->obj, param->prog_name);122 if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name"))123 goto cleanup;124 125 prog_fd = bpf_program__fd(prog);126 err = bpf_prog_test_run_opts(prog_fd, &topts);127 if (!ASSERT_OK(err, param->prog_name))128 goto cleanup;129 130 if (!ASSERT_EQ(topts.retval, param->retval, "retval"))131 goto cleanup;132 133 /* second test with light skeletons */134 lskel = kfunc_call_test_lskel__open_and_load();135 if (!ASSERT_OK_PTR(lskel, "lskel"))136 goto cleanup;137 138 lskel_prog = (struct bpf_prog_desc *)((char *)lskel + param->lskel_prog_desc_offset);139 140 prog_fd = lskel_prog->prog_fd;141 err = bpf_prog_test_run_opts(prog_fd, &topts);142 if (!ASSERT_OK(err, param->prog_name))143 goto cleanup;144 145 ASSERT_EQ(topts.retval, param->retval, "retval");146 147cleanup:148 kfunc_call_test__destroy(skel);149 if (lskel)150 kfunc_call_test_lskel__destroy(lskel);151}152 153static void verify_fail(struct kfunc_test_params *param)154{155 LIBBPF_OPTS(bpf_object_open_opts, opts);156 LIBBPF_OPTS(bpf_test_run_opts, topts);157 struct bpf_program *prog;158 struct kfunc_call_fail *skel;159 int prog_fd, err;160 struct syscall_test_args args = {161 .size = 10,162 };163 164 opts.kernel_log_buf = obj_log_buf;165 opts.kernel_log_size = log_buf_sz;166 opts.kernel_log_level = 1;167 168 switch (param->test_type) {169 case syscall_test:170 topts.ctx_in = &args;171 topts.ctx_size_in = sizeof(args);172 /* fallthrough */173 case syscall_null_ctx_test:174 break;175 case tc_test:176 topts.data_in = &pkt_v4;177 topts.data_size_in = sizeof(pkt_v4);178 topts.repeat = 1;179 break;180 }181 182 skel = kfunc_call_fail__open_opts(&opts);183 if (!ASSERT_OK_PTR(skel, "kfunc_call_fail__open_opts"))184 goto cleanup;185 186 prog = bpf_object__find_program_by_name(skel->obj, param->prog_name);187 if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name"))188 goto cleanup;189 190 bpf_program__set_autoload(prog, true);191 192 err = kfunc_call_fail__load(skel);193 if (!param->retval) {194 /* the verifier is supposed to complain and refuses to load */195 if (!ASSERT_ERR(err, "unexpected load success"))196 goto out_err;197 198 } else {199 /* the program is loaded but must dynamically fail */200 if (!ASSERT_OK(err, "unexpected load error"))201 goto out_err;202 203 prog_fd = bpf_program__fd(prog);204 err = bpf_prog_test_run_opts(prog_fd, &topts);205 if (!ASSERT_EQ(err, param->retval, param->prog_name))206 goto out_err;207 }208 209out_err:210 if (!ASSERT_OK_PTR(strstr(obj_log_buf, param->expected_err_msg), "expected_err_msg")) {211 fprintf(stderr, "Expected err_msg: %s\n", param->expected_err_msg);212 fprintf(stderr, "Verifier output: %s\n", obj_log_buf);213 }214 215cleanup:216 kfunc_call_fail__destroy(skel);217}218 219static void test_main(void)220{221 int i;222 223 for (i = 0; i < ARRAY_SIZE(kfunc_tests); i++) {224 if (!test__start_subtest(kfunc_tests[i].prog_name))225 continue;226 227 if (!kfunc_tests[i].expected_err_msg)228 verify_success(&kfunc_tests[i]);229 else230 verify_fail(&kfunc_tests[i]);231 }232}233 234static void test_subprog(void)235{236 struct kfunc_call_test_subprog *skel;237 int prog_fd, err;238 LIBBPF_OPTS(bpf_test_run_opts, topts,239 .data_in = &pkt_v4,240 .data_size_in = sizeof(pkt_v4),241 .repeat = 1,242 );243 244 skel = kfunc_call_test_subprog__open_and_load();245 if (!ASSERT_OK_PTR(skel, "skel"))246 return;247 248 prog_fd = bpf_program__fd(skel->progs.kfunc_call_test1);249 err = bpf_prog_test_run_opts(prog_fd, &topts);250 ASSERT_OK(err, "bpf_prog_test_run(test1)");251 ASSERT_EQ(topts.retval, 10, "test1-retval");252 ASSERT_NEQ(skel->data->active_res, -1, "active_res");253 ASSERT_EQ(skel->data->sk_state_res, BPF_TCP_CLOSE, "sk_state_res");254 255 kfunc_call_test_subprog__destroy(skel);256}257 258static void test_subprog_lskel(void)259{260 struct kfunc_call_test_subprog_lskel *skel;261 int prog_fd, err;262 LIBBPF_OPTS(bpf_test_run_opts, topts,263 .data_in = &pkt_v4,264 .data_size_in = sizeof(pkt_v4),265 .repeat = 1,266 );267 268 skel = kfunc_call_test_subprog_lskel__open_and_load();269 if (!ASSERT_OK_PTR(skel, "skel"))270 return;271 272 prog_fd = skel->progs.kfunc_call_test1.prog_fd;273 err = bpf_prog_test_run_opts(prog_fd, &topts);274 ASSERT_OK(err, "bpf_prog_test_run(test1)");275 ASSERT_EQ(topts.retval, 10, "test1-retval");276 ASSERT_NEQ(skel->data->active_res, -1, "active_res");277 ASSERT_EQ(skel->data->sk_state_res, BPF_TCP_CLOSE, "sk_state_res");278 279 kfunc_call_test_subprog_lskel__destroy(skel);280}281 282static int test_destructive_open_and_load(void)283{284 struct kfunc_call_destructive *skel;285 int err;286 287 skel = kfunc_call_destructive__open();288 if (!ASSERT_OK_PTR(skel, "prog_open"))289 return -1;290 291 err = kfunc_call_destructive__load(skel);292 293 kfunc_call_destructive__destroy(skel);294 295 return err;296}297 298static void test_destructive(void)299{300 __u64 save_caps = 0;301 302 ASSERT_OK(test_destructive_open_and_load(), "successful_load");303 304 if (!ASSERT_OK(cap_disable_effective(1ULL << CAP_SYS_BOOT, &save_caps), "drop_caps"))305 return;306 307 ASSERT_EQ(test_destructive_open_and_load(), -13, "no_caps_failure");308 309 cap_enable_effective(save_caps, NULL);310}311 312void test_kfunc_call(void)313{314 test_main();315 316 if (test__start_subtest("subprog"))317 test_subprog();318 319 if (test__start_subtest("subprog_lskel"))320 test_subprog_lskel();321 322 if (test__start_subtest("destructive"))323 test_destructive();324}325