Apparently, no existing selftest covers it. Add a new one where we load cgroup/bind4 program and attach fentry to it. Calling bpf_obj_get_info_by_fd on the fentry program should return non-zero btf_id/btf_obj_id instead of crashing the kernel. Signed-off-by: Stanislav Fomichev <sdf@xxxxxxxxxx> --- .../selftests/bpf/prog_tests/attach_to_bpf.c | 109 ++++++++++++++++++ .../selftests/bpf/progs/attach_to_bpf.c | 12 ++ 2 files changed, 121 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/attach_to_bpf.c create mode 100644 tools/testing/selftests/bpf/progs/attach_to_bpf.c diff --git a/tools/testing/selftests/bpf/prog_tests/attach_to_bpf.c b/tools/testing/selftests/bpf/prog_tests/attach_to_bpf.c new file mode 100644 index 000000000000..fcf726c5ff0f --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/attach_to_bpf.c @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: GPL-2.0 +#define _GNU_SOURCE +#include <stdlib.h> +#include <bpf/btf.h> +#include <test_progs.h> +#include <network_helpers.h> +#include "attach_to_bpf.skel.h" + +char bpf_log_buf[BPF_LOG_BUF_SIZE]; + +static int find_prog_btf_id(const char *name, __u32 attach_prog_fd) +{ + struct bpf_prog_info info = {}; + __u32 info_len = sizeof(info); + struct btf *btf; + int err; + + err = bpf_obj_get_info_by_fd(attach_prog_fd, &info, &info_len); + if (err) + return err; + + if (!info.btf_id) + return -EINVAL; + + btf = btf__load_from_kernel_by_id(info.btf_id); + err = libbpf_get_error(btf); + if (err) + return err; + + err = btf__find_by_name_kind(btf, name, BTF_KIND_FUNC); + btf__free(btf); + if (err <= 0) + return err; + + return err; +} + +int load_fentry(int attach_prog_fd, int attach_btf_id) +{ + LIBBPF_OPTS(bpf_prog_load_opts, opts, + .expected_attach_type = BPF_TRACE_FENTRY, + .attach_prog_fd = attach_prog_fd, + .attach_btf_id = attach_btf_id, + .log_buf = bpf_log_buf, + .log_size = sizeof(bpf_log_buf), + ); + struct bpf_insn insns[] = { + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }; + int ret; + + ret = bpf_prog_load(BPF_PROG_TYPE_TRACING, + "bind4_fentry", + "GPL", + insns, + ARRAY_SIZE(insns), + &opts); + if (ret) + printf("verifier log: %s\n", bpf_log_buf); + return ret; +} + +void test_attach_to_bpf(void) +{ + struct attach_to_bpf *skel = NULL; + struct bpf_prog_info info = {}; + __u32 info_len = sizeof(info); + int cgroup_fd = -1; + int fentry_fd = -1; + int btf_id; + + cgroup_fd = test__join_cgroup("/attach_to_bpf"); + if (!ASSERT_GE(cgroup_fd, 0, "cgroup_fd")) + return; + + skel = attach_to_bpf__open_and_load(); + if (!ASSERT_OK_PTR(skel, "skel")) + goto cleanup; + + skel->links.bind4 = bpf_program__attach_cgroup(skel->progs.bind4, cgroup_fd); + if (!ASSERT_OK_PTR(skel, "bpf_program__attach_cgroup")) + goto cleanup; + + btf_id = find_prog_btf_id("bind4", bpf_program__fd(skel->progs.bind4)); + if (!ASSERT_GE(btf_id, 0, "find_prog_btf_id")) + goto cleanup; + + fentry_fd = load_fentry(bpf_program__fd(skel->progs.bind4), btf_id); + if (!ASSERT_GE(fentry_fd, 0, "load_fentry")) + goto cleanup; + + /* Make sure bpf_obj_get_info_by_fd works correctly when attaching + * to another BPF program. + */ + + if (!ASSERT_OK(bpf_obj_get_info_by_fd(fentry_fd, &info, &info_len), + "bpf_obj_get_info_by_fd")) + goto cleanup; + + ASSERT_EQ(info.btf_id, 0, "info.btf_id"); + ASSERT_GT(info.attach_btf_id, 0, "info.attach_btf_id"); + ASSERT_GT(info.attach_btf_obj_id, 0, "info.attach_btf_obj_id"); + +cleanup: + close(cgroup_fd); + close(fentry_fd); + attach_to_bpf__destroy(skel); +} diff --git a/tools/testing/selftests/bpf/progs/attach_to_bpf.c b/tools/testing/selftests/bpf/progs/attach_to_bpf.c new file mode 100644 index 000000000000..3f111fe96f8f --- /dev/null +++ b/tools/testing/selftests/bpf/progs/attach_to_bpf.c @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/bpf.h> +#include <bpf/bpf_helpers.h> + +SEC("cgroup/bind4") +int bind4(struct bpf_sock_addr *ctx) +{ + return 1; +} + +char _license[] SEC("license") = "GPL"; -- 2.37.1.455.g008518b4e5-goog