From: Anton Protopopov <a.s.protopopov@gmail.com>
To: Alexei Starovoitov <ast@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
Andrii Nakryiko <andrii@kernel.org>,
Eduard Zingerman <eddyz87@gmail.com>,
Kumar Kartikeya Dwivedi <memxor@gmail.com>,
Alan Maguire <almagui@kernel.org>,
John Fastabend <john.fastabend@gmail.com>,
Quentin Monnet <qmo@kernel.org>,
Christian Brauner <brauner@kernel.org>,
KP Singh <kpsingh@kernel.org>,
Yonghong Song <yonghong.song@linux.dev>,
Jiri Olsa <jolsa@kernel.org>,
Emil Tsalapatis <emil@etsalapatis.com>,
Ihor Solodrai <ihor.solodrai@linux.dev>,
Sasha Levin <sashal@kernel.org>,
bpf@vger.kernel.org, linux-kernel@vger.kernel.org
Cc: Anton Protopopov <a.s.protopopov@gmail.com>
Subject: [PATCH v1 bpf-next 06/18] selftests/bpf: Test fmod_ret BTF decl tags and attach permission
Date: Fri, 6 Nov 2026 21:02:55 +0000 [thread overview]
Message-ID: <20261106210314.1767267-6-a.s.protopopov@gmail.com> (raw)
In-Reply-To: 20261106205523.1765622-1-a.s.protopopov@gmail.com
Check that resolve_btfids tags the fmod_ret targets of vmlinux and of
bpf_testmod with "bpf_fmodret", that only bpf_fentry_test1 has the
"bpf_fmodret_sleepable" tag, and that a function which is not a target
has none.
Load minimal fmod_ret programs to check that the kernel builds its
target set from the tags: a target loads, a function which is not a
target does not, and sleepable programs load only for the sleepable
target.
Signed-off-by: Anton Protopopov <a.s.protopopov@gmail.com>
---
.../selftests/bpf/prog_tests/fmodret_tags.c | 155 ++++++++++++++++++
1 file changed, 155 insertions(+)
create mode 100644 tools/testing/selftests/bpf/prog_tests/fmodret_tags.c
diff --git a/tools/testing/selftests/bpf/prog_tests/fmodret_tags.c b/tools/testing/selftests/bpf/prog_tests/fmodret_tags.c
new file mode 100644
index 000000000000..62efe11af826
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/fmodret_tags.c
@@ -0,0 +1,155 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <test_progs.h>
+#include <linux/filter.h>
+#include <bpf/btf.h>
+
+#define TAG_FMODRET "bpf_fmodret"
+#define TAG_FMODRET_SLEEPABLE "bpf_fmodret_sleepable"
+
+static bool func_has_tag(const struct btf *btf, const char *func, const char *tag)
+{
+ int func_id, id, nr_types;
+
+ func_id = btf__find_by_name_kind(btf, func, BTF_KIND_FUNC);
+ if (func_id < 0)
+ return false;
+
+ nr_types = btf__type_cnt(btf);
+ for (id = 1; id < nr_types; id++) {
+ const struct btf_type *t = btf__type_by_id(btf, id);
+
+ if (!btf_is_decl_tag(t) || t->type != func_id ||
+ btf_decl_tag(t)->component_idx != -1)
+ continue;
+ if (!strcmp(btf__name_by_offset(btf, t->name_off), tag))
+ return true;
+ }
+
+ return false;
+}
+
+static void test_vmlinux_tags(void)
+{
+ struct btf *btf;
+
+ btf = btf__load_vmlinux_btf();
+ if (!ASSERT_OK_PTR(btf, "btf__load_vmlinux_btf"))
+ return;
+
+ ASSERT_TRUE(func_has_tag(btf, "bpf_modify_return_test", TAG_FMODRET), "modify_return_test");
+ ASSERT_TRUE(func_has_tag(btf, "bpf_modify_return_test2", TAG_FMODRET),
+ "modify_return_test2");
+ ASSERT_TRUE(func_has_tag(btf, "bpf_modify_return_test_tp", TAG_FMODRET),
+ "modify_return_test_tp");
+ ASSERT_TRUE(func_has_tag(btf, "bpf_fentry_test1", TAG_FMODRET), "fentry_test1");
+ ASSERT_TRUE(func_has_tag(btf, "update_socket_protocol", TAG_FMODRET),
+ "update_socket_protocol");
+
+ /* Only bpf_fentry_test1 is a sleepable target */
+ ASSERT_TRUE(func_has_tag(btf, "bpf_fentry_test1", TAG_FMODRET_SLEEPABLE),
+ "fentry_test1_sleepable");
+ ASSERT_FALSE(func_has_tag(btf, "bpf_modify_return_test", TAG_FMODRET_SLEEPABLE),
+ "modify_return_test_sleepable");
+ ASSERT_FALSE(func_has_tag(btf, "bpf_modify_return_test2", TAG_FMODRET_SLEEPABLE),
+ "modify_return_test2_sleepable");
+ ASSERT_FALSE(func_has_tag(btf, "bpf_modify_return_test_tp", TAG_FMODRET_SLEEPABLE),
+ "modify_return_test_tp_sleepable");
+ ASSERT_FALSE(func_has_tag(btf, "update_socket_protocol", TAG_FMODRET_SLEEPABLE),
+ "update_socket_protocol_sleepable");
+
+ /* A function which is not a target has no tag */
+ ASSERT_GT(btf__find_by_name_kind(btf, "bpf_fentry_test2", BTF_KIND_FUNC), 0,
+ "fentry_test2_exists");
+ ASSERT_FALSE(func_has_tag(btf, "bpf_fentry_test2", TAG_FMODRET), "fentry_test2");
+ ASSERT_FALSE(func_has_tag(btf, "bpf_fentry_test2", TAG_FMODRET_SLEEPABLE),
+ "fentry_test2_sleepable");
+
+ btf__free(btf);
+}
+
+static void test_module_tags(void)
+{
+ struct btf *vmlinux_btf, *module_btf;
+
+ if (!env.has_testmod) {
+ test__skip();
+ return;
+ }
+
+ vmlinux_btf = btf__load_vmlinux_btf();
+ if (!ASSERT_OK_PTR(vmlinux_btf, "btf__load_vmlinux_btf"))
+ return;
+ module_btf = btf__load_module_btf("bpf_testmod", vmlinux_btf);
+ if (!module_btf && errno == ENOENT) {
+ printf("%s:SKIP:bpf_testmod has no BTF\n", __func__);
+ test__skip();
+ goto out;
+ }
+ if (!ASSERT_OK_PTR(module_btf, "btf__load_module_btf"))
+ goto out;
+
+ ASSERT_TRUE(func_has_tag(module_btf, "bpf_testmod_trampoline_count_test", TAG_FMODRET),
+ "trampoline_count_test");
+ ASSERT_FALSE(func_has_tag(module_btf, "bpf_testmod_trampoline_count_test",
+ TAG_FMODRET_SLEEPABLE), "trampoline_count_test_sleepable");
+ ASSERT_FALSE(func_has_tag(module_btf, "bpf_testmod_fentry_test1", TAG_FMODRET),
+ "testmod_fentry_test1");
+
+ btf__free(module_btf);
+out:
+ btf__free(vmlinux_btf);
+}
+
+/* Load a minimal fmod_ret program which attaches to function BTF_ID */
+static int load_fmod_ret(int btf_id, __u32 prog_flags)
+{
+ struct bpf_insn insns[] = {
+ BPF_MOV64_IMM(BPF_REG_0, 0),
+ BPF_EXIT_INSN(),
+ };
+ LIBBPF_OPTS(bpf_prog_load_opts, opts,
+ .expected_attach_type = BPF_MODIFY_RETURN,
+ .prog_flags = prog_flags,
+ .attach_btf_id = btf_id,
+ );
+
+ return bpf_prog_load(BPF_PROG_TYPE_TRACING, NULL, "GPL", insns, ARRAY_SIZE(insns), &opts);
+}
+
+static void check_load(const char *func, __u32 prog_flags, bool allowed, const char *name)
+{
+ int btf_id, fd;
+
+ btf_id = libbpf_find_vmlinux_btf_id(func, BPF_MODIFY_RETURN);
+ if (!ASSERT_GT(btf_id, 0, func))
+ return;
+ fd = load_fmod_ret(btf_id, prog_flags);
+ if (allowed)
+ ASSERT_GE(fd, 0, name);
+ else
+ ASSERT_LT(fd, 0, name);
+ if (fd >= 0)
+ close(fd);
+}
+
+static void test_attach_permission(void)
+{
+ check_load("bpf_modify_return_test", 0, true, "target");
+ check_load("bpf_fentry_test1", 0, true, "sleepable_target");
+ check_load("bpf_fentry_test2", 0, false, "not_a_target");
+
+ check_load("bpf_fentry_test1", BPF_F_SLEEPABLE, true, "sleepable_prog_sleepable_target");
+ check_load("bpf_modify_return_test", BPF_F_SLEEPABLE, false,
+ "sleepable_prog_nonsleepable_target");
+}
+
+void test_fmodret_tags(void)
+{
+ if (test__start_subtest("vmlinux"))
+ test_vmlinux_tags();
+ if (test__start_subtest("module"))
+ test_module_tags();
+ if (test__start_subtest("attach_permission"))
+ test_attach_permission();
+}
--
2.43.0
next prev parent reply other threads:[~2026-11-06 20:52 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-06 21:02 [PATCH v1 bpf-next 01/18] bpf: Add BTF ID sets for fmod_ret targets Anton Protopopov
2026-11-06 21:02 ` [PATCH v1 bpf-next 02/18] bpf: Add a btf_id_set8_entry helper Anton Protopopov
2026-11-06 21:02 ` [PATCH v1 bpf-next 03/18] bpf: Build fmod_ret target sets from BTF decl tags Anton Protopopov
2026-11-06 21:02 ` [PATCH v1 bpf-next 04/18] selftests/bpf: Declare bpf_fentry_test1 in tracing tests Anton Protopopov
2026-11-06 21:02 ` [PATCH v1 bpf-next 05/18] bpf: Declare fmod_ret targets with BTF_FMODRET sets Anton Protopopov
2026-11-06 21:02 ` Anton Protopopov [this message]
2026-11-06 21:02 ` [PATCH v1 bpf-next 07/18] scripts: Add LLVM plugin infrastructure Anton Protopopov
2026-11-06 21:02 ` [PATCH v1 bpf-next 08/18] bpf: Add the bpf_scan_ir LLVM plugin Anton Protopopov
2026-11-06 21:02 ` [PATCH v1 bpf-next 09/18] bpf: Find fmod_ret candidates in bpf_scan_ir Anton Protopopov
2026-11-06 21:02 ` [PATCH v1 bpf-next 10/18] bpf: Allow writes to private stack objects " Anton Protopopov
2026-11-06 21:03 ` [PATCH v1 bpf-next 11/18] bpf: Follow PHIs " Anton Protopopov
2026-11-06 21:03 ` [PATCH v1 bpf-next 12/18] bpf: Follow integer casts " Anton Protopopov
2026-11-06 21:03 ` [PATCH v1 bpf-next 13/18] bpf: Check the return values of fmod_ret programs on found targets Anton Protopopov
2026-11-06 21:03 ` [PATCH v1 bpf-next 14/18] bpf: Require the JIT for fmod_ret programs on found 64-bit targets Anton Protopopov
2026-11-06 21:03 ` [PATCH v1 bpf-next 15/18] resolve_btfids: Tag fmod_ret candidates as targets Anton Protopopov
2026-11-06 21:50 ` bot+bpf-ci
2026-11-06 21:03 ` [PATCH v1 bpf-next 16/18] selftests/bpf: Test fmod_ret candidates found by bpf_scan_ir Anton Protopopov
2026-11-06 21:50 ` bot+bpf-ci
2026-11-06 21:03 ` [PATCH v1 bpf-next 17/18] selftests/bpf: Enable bpf_scan_ir in the config Anton Protopopov
2026-11-06 21:35 ` bot+bpf-ci
2026-11-06 21:03 ` [PATCH v1 bpf-next 18/18] bpftool: List and show fmod_ret targets Anton Protopopov
2026-11-06 21:35 ` bot+bpf-ci
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261106210314.1767267-6-a.s.protopopov@gmail.com \
--to=a.s.protopopov@gmail.com \
--cc=almagui@kernel.org \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=brauner@kernel.org \
--cc=daniel@iogearbox.net \
--cc=eddyz87@gmail.com \
--cc=emil@etsalapatis.com \
--cc=ihor.solodrai@linux.dev \
--cc=john.fastabend@gmail.com \
--cc=jolsa@kernel.org \
--cc=kpsingh@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=memxor@gmail.com \
--cc=qmo@kernel.org \
--cc=sashal@kernel.org \
--cc=yonghong.song@linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®