// SPDX-License-Identifier: GPL-2.0 /* Copyright (c) 2020 Facebook */ #include #include #include "test_module_attach.skel.h" #include "testing_helpers.h" static const char * const read_tests[] = { "handle_raw_tp", "handle_tp_btf", "handle_fentry", "handle_fentry_explicit", "handle_fmod_ret", }; static const char * const detach_tests[] = { "handle_fentry", "handle_fexit", "kprobe_multi", }; static const int READ_SZ = 456; static const int WRITE_SZ = 457; static int trigger_module_test_writable(int *val) { int fd, err; char buf[65]; ssize_t rd; fd = open(BPF_TESTMOD_TEST_FILE, O_RDONLY); err = -errno; if (!ASSERT_GE(fd, 0, "testmode_file_open")) return err; rd = read(fd, buf, sizeof(buf) - 1); err = -errno; if (!ASSERT_GT(rd, 0, "testmod_file_rd_val")) { close(fd); return err; } buf[rd] = '\0'; *val = strtol(buf, NULL, 0); close(fd); return 0; } static void test_module_attach_prog(const char *prog_name, int sz, const char *attach_target, int ret) { struct test_module_attach *skel; struct bpf_program *prog; int err; skel = test_module_attach__open(); if (!ASSERT_OK_PTR(skel, "module_attach open")) return; prog = bpf_object__find_program_by_name(skel->obj, prog_name); if (!ASSERT_OK_PTR(prog, "module_attach find_program")) goto cleanup; bpf_program__set_autoload(prog, true); if (attach_target) { err = bpf_program__set_attach_target(prog, 0, attach_target); if (!ASSERT_OK(err, attach_target)) goto cleanup; } err = test_module_attach__load(skel); if (!ASSERT_OK(err, "module_attach load")) goto cleanup; err = test_module_attach__attach(skel); if (!ASSERT_OK(err, "module_attach attach")) goto cleanup; if (sz) { /* trigger both read and write though each test uses only one */ ASSERT_OK(trigger_module_test_read(sz), "trigger_read"); ASSERT_OK(trigger_module_test_write(sz), "trigger_write"); ASSERT_EQ(skel->bss->sz, sz, prog_name); } if (ret) ASSERT_EQ(skel->bss->retval, ret, "ret"); cleanup: test_module_attach__destroy(skel); } static void test_module_attach_writable(void) { struct test_module_attach__bss *bss; struct test_module_attach *skel; int writable_val = 0; int err; skel = test_module_attach__open(); if (!ASSERT_OK_PTR(skel, "module_attach open")) return; bpf_program__set_autoload(skel->progs.handle_raw_tp_writable_bare, true); err = test_module_attach__load(skel); if (!ASSERT_OK(err, "module_attach load")) goto cleanup; bss = skel->bss; err = test_module_attach__attach(skel); if (!ASSERT_OK(err, "module_attach attach")) goto cleanup; bss->raw_tp_writable_bare_early_ret = true; bss->raw_tp_writable_bare_out_val = 0xf1f2f3f4; ASSERT_OK(trigger_module_test_writable(&writable_val), "trigger_writable"); ASSERT_EQ(bss->raw_tp_writable_bare_in_val, 1024, "writable_test_in"); ASSERT_EQ(bss->raw_tp_writable_bare_out_val, writable_val, "writable_test_out"); cleanup: test_module_attach__destroy(skel); } static void test_module_attach_detach(const char *prog_name) { struct test_module_attach *skel; struct bpf_program *prog; struct bpf_link *link; int err; skel = test_module_attach__open(); if (!ASSERT_OK_PTR(skel, "module_attach open")) return; prog = bpf_object__find_program_by_name(skel->obj, prog_name); if (!ASSERT_OK_PTR(prog, "module_attach find_program")) goto cleanup; bpf_program__set_autoload(prog, true); err = test_module_attach__load(skel); if (!ASSERT_OK(err, "module_attach load")) goto cleanup; /* attach and make sure it gets module reference */ link = bpf_program__attach(prog); if (!ASSERT_OK_PTR(link, "module_attach attach")) goto cleanup; ASSERT_ERR(try_unload_module("bpf_testmod", 1, false), "try_unload_module"); bpf_link__destroy(link); cleanup: test_module_attach__destroy(skel); } void test_module_attach(void) { int i; for (i = 0; i < ARRAY_SIZE(read_tests); i++) { if (!test__start_subtest(read_tests[i])) continue; test_module_attach_prog(read_tests[i], READ_SZ, NULL, 0); } if (test__start_subtest("handle_raw_tp_bare")) test_module_attach_prog("handle_raw_tp_bare", WRITE_SZ, NULL, 0); if (test__start_subtest("handle_raw_tp_writable_bare")) test_module_attach_writable(); if (test__start_subtest("handle_fentry_manual")) { test_module_attach_prog("handle_fentry_manual", READ_SZ, "bpf_testmod_test_read", 0); } if (test__start_subtest("handle_fentry_explicit_manual")) { test_module_attach_prog("handle_fentry_explicit_manual", READ_SZ, "bpf_testmod:bpf_testmod_test_read", 0); } if (test__start_subtest("handle_fexit")) test_module_attach_prog("handle_fexit", READ_SZ, NULL, -EIO); if (test__start_subtest("handle_fexit_ret")) test_module_attach_prog("handle_fexit_ret", 0, NULL, 0); for (i = 0; i < ARRAY_SIZE(detach_tests); i++) { char test_name[50]; snprintf(test_name, sizeof(test_name), "%s_detach", detach_tests[i]); if (!test__start_subtest(test_name)) continue; test_module_attach_detach(detach_tests[i]); } }