Added a selftest where the argument is a pointer with __user tag. Directly accessing its field without helper will result verification failure. $ ./test_progs -v -n 21/3 ... Successfully loaded bpf_testmod.ko. test_btf_type_tag_user:PASS:btf_type_tag_user 0 nsec libbpf: load bpf program failed: Permission denied libbpf: -- BEGIN DUMP LOG --- libbpf: R1 type=ctx expected=fp ; int BPF_PROG(sub, struct bpf_testmod_btf_type_tag *arg) 0: (79) r1 = *(u64 *)(r1 +0) func 'bpf_testmod_test_btf_type_tag_user' arg0 accesses user memory invalid bpf_context access off=0 size=8 processed 1 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0 ... test_btf_type_tag_user:PASS:btf_type_tag_user 0 nsec #21/3 btf_tag/btf_type_tag_user:OK #21 btf_tag:OK Summary: 1/1 PASSED, 0 SKIPPED, 0 FAILED Successfully unloaded bpf_testmod.ko. Signed-off-by: Yonghong Song <yhs@xxxxxx> --- kernel/bpf/verifier.c | 1 + .../selftests/bpf/bpf_testmod/bpf_testmod.c | 9 +++++++ .../selftests/bpf/prog_tests/btf_tag.c | 23 ++++++++++++++++++ .../selftests/bpf/progs/btf_type_tag_user.c | 24 +++++++++++++++++++ 4 files changed, 57 insertions(+) create mode 100644 tools/testing/selftests/bpf/progs/btf_type_tag_user.c diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index 07ba7c8f6aa3..71fd66b53026 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -4372,6 +4372,7 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn enum bpf_reg_type reg_type = SCALAR_VALUE; struct btf *btf = NULL; u32 btf_id = 0; + bool is_user; if (t == BPF_WRITE && value_regno >= 0 && is_pointer_value(env, value_regno)) { diff --git a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c index 5d52ea2768df..5377dd2959bb 100644 --- a/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c +++ b/tools/testing/selftests/bpf/bpf_testmod/bpf_testmod.c @@ -21,6 +21,15 @@ bpf_testmod_test_mod_kfunc(int i) *(int *)this_cpu_ptr(&bpf_testmod_ksym_percpu) = i; } +struct bpf_testmod_btf_type_tag { + int a; +}; + +noinline int +bpf_testmod_test_btf_type_tag_user(struct bpf_testmod_btf_type_tag __user *arg) { + return arg->a; +} + noinline int bpf_testmod_loop_test(int n) { int i, sum = 0; diff --git a/tools/testing/selftests/bpf/prog_tests/btf_tag.c b/tools/testing/selftests/bpf/prog_tests/btf_tag.c index 88d63e23e35f..1e4003fa7cd0 100644 --- a/tools/testing/selftests/bpf/prog_tests/btf_tag.c +++ b/tools/testing/selftests/bpf/prog_tests/btf_tag.c @@ -8,6 +8,7 @@ struct btf_type_tag_test { int **p; }; #include "btf_type_tag.skel.h" +#include "btf_type_tag_user.skel.h" static void test_btf_decl_tag(void) { @@ -41,10 +42,32 @@ static void test_btf_type_tag(void) btf_type_tag__destroy(skel); } +static void test_btf_type_tag_user(void) +{ + struct btf_type_tag_user *skel; + int err; + + skel = btf_type_tag_user__open(); + if (!ASSERT_OK_PTR(skel, "btf_type_tag_user")) + return; + + if (skel->rodata->skip_tests) { + printf("%s:SKIP: btf_type_tag attribute not supported", __func__); + test__skip(); + } else { + err = btf_type_tag_user__load(skel); + ASSERT_ERR(err, "btf_type_tag_user"); + } + + btf_type_tag_user__destroy(skel); +} + void test_btf_tag(void) { if (test__start_subtest("btf_decl_tag")) test_btf_decl_tag(); if (test__start_subtest("btf_type_tag")) test_btf_type_tag(); + if (test__start_subtest("btf_type_tag_user")) + test_btf_type_tag_user(); } diff --git a/tools/testing/selftests/bpf/progs/btf_type_tag_user.c b/tools/testing/selftests/bpf/progs/btf_type_tag_user.c new file mode 100644 index 000000000000..41ab1ddd2cf5 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/btf_type_tag_user.c @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2021 Facebook */ +#include "vmlinux.h" +#include <bpf/bpf_helpers.h> +#include <bpf/bpf_tracing.h> + +#if __has_attribute(btf_type_tag) +volatile const bool skip_tests = false; +#else +volatile const bool skip_tests = true; +#endif + +struct bpf_testmod_btf_type_tag { + int a; +}; + +int g; + +SEC("fentry/bpf_testmod_test_btf_type_tag_user") +int BPF_PROG(sub, struct bpf_testmod_btf_type_tag *arg) +{ + g = arg->a; + return 0; +} -- 2.30.2