Message ID | 20230515133756.1658301-9-jolsa@kernel.org (mailing list archive) |
---|---|
State | Accepted |
Commit | f26ebdd3e4e4e1f5f08522b087ab9ec7216e9a3b |
Delegated to: | BPF |
Headers | show |
Series | bpf: Move kernel test kfuncs into bpf_testmod | expand |
On Mon, May 15, 2023 at 6:39 AM Jiri Olsa <jolsa@kernel.org> wrote: > > Currently the test_verifier allows test to specify kfunc symbol > and search for it in the kernel BTF. > > Adding the possibility to search for kfunc also in bpf_testmod > module when it's not found in kernel BTF. > > To find bpf_testmod btf we need to get back SYS_ADMIN cap. > > Acked-by: David Vernet <void@manifault.com> > Signed-off-by: Jiri Olsa <jolsa@kernel.org> > --- > tools/testing/selftests/bpf/test_verifier.c | 161 +++++++++++++++++--- > 1 file changed, 139 insertions(+), 22 deletions(-) > Eduard is working on migrating most (if not all) test_verifier tests into test_progs where we can use libbpf declarative functionality for things like this. Eduard, can you please review this part? Would it make sense to just wait for the migration? If not, will there be anything involved to support something like this for the future migration? > diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c > index 285ea4aba194..71704a38cac3 100644 > --- a/tools/testing/selftests/bpf/test_verifier.c > +++ b/tools/testing/selftests/bpf/test_verifier.c > @@ -874,8 +874,140 @@ static int create_map_kptr(void) > return fd; > } > [...]
On Tue, May 16, 2023 at 2:45 PM Andrii Nakryiko <andrii.nakryiko@gmail.com> wrote: > > On Mon, May 15, 2023 at 6:39 AM Jiri Olsa <jolsa@kernel.org> wrote: > > > > Currently the test_verifier allows test to specify kfunc symbol > > and search for it in the kernel BTF. > > > > Adding the possibility to search for kfunc also in bpf_testmod > > module when it's not found in kernel BTF. > > > > To find bpf_testmod btf we need to get back SYS_ADMIN cap. > > > > Acked-by: David Vernet <void@manifault.com> > > Signed-off-by: Jiri Olsa <jolsa@kernel.org> > > --- > > tools/testing/selftests/bpf/test_verifier.c | 161 +++++++++++++++++--- > > 1 file changed, 139 insertions(+), 22 deletions(-) > > > > Eduard is working on migrating most (if not all) test_verifier tests > into test_progs where we can use libbpf declarative functionality for > things like this. > > Eduard, can you please review this part? Would it make sense to just > wait for the migration? No. Migration might never complete. It's already at the point of diminishing returns. This patch set is a great clean up on its own. Hence I've decided to apply it. If in the future this particular patch for test_verifier won't be necessary we can easily revert it.
On Tue, 2023-05-16 at 14:45 -0700, Andrii Nakryiko wrote: > On Mon, May 15, 2023 at 6:39 AM Jiri Olsa <jolsa@kernel.org> wrote: > > > > Currently the test_verifier allows test to specify kfunc symbol > > and search for it in the kernel BTF. > > > > Adding the possibility to search for kfunc also in bpf_testmod > > module when it's not found in kernel BTF. > > > > To find bpf_testmod btf we need to get back SYS_ADMIN cap. > > > > Acked-by: David Vernet <void@manifault.com> > > Signed-off-by: Jiri Olsa <jolsa@kernel.org> > > --- > > tools/testing/selftests/bpf/test_verifier.c | 161 +++++++++++++++++--- > > 1 file changed, 139 insertions(+), 22 deletions(-) > > > > Eduard is working on migrating most (if not all) test_verifier tests > into test_progs where we can use libbpf declarative functionality for > things like this. > > Eduard, can you please review this part? Would it make sense to just > wait for the migration? If not, will there be anything involved to > support something like this for the future migration? Hi Andrii, I'm not working on migrating remaining test_verifier tests to test_progs/inline assembly at the moment. Regarding this specific change, as far as I understand it is necessary for the following tests: - verifier/calls.c - verifier/map_kptr.c Both files can't be migrated at the moment. I spent some time today debugging, but the reasons are obscure and require further investigation. As to this particular patch itself, I tested it locally and it seems to work fine. None of the changes prohibit future migration to inline assembly, should such migration happen. Thanks, Eduard > > > > diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c > > index 285ea4aba194..71704a38cac3 100644 > > --- a/tools/testing/selftests/bpf/test_verifier.c > > +++ b/tools/testing/selftests/bpf/test_verifier.c > > @@ -874,8 +874,140 @@ static int create_map_kptr(void) > > return fd; > > } > > > > [...]
On Wed, May 17, 2023 at 7:27 AM Eduard Zingerman <eddyz87@gmail.com> wrote: > > On Tue, 2023-05-16 at 14:45 -0700, Andrii Nakryiko wrote: > > On Mon, May 15, 2023 at 6:39 AM Jiri Olsa <jolsa@kernel.org> wrote: > > > > > > Currently the test_verifier allows test to specify kfunc symbol > > > and search for it in the kernel BTF. > > > > > > Adding the possibility to search for kfunc also in bpf_testmod > > > module when it's not found in kernel BTF. > > > > > > To find bpf_testmod btf we need to get back SYS_ADMIN cap. > > > > > > Acked-by: David Vernet <void@manifault.com> > > > Signed-off-by: Jiri Olsa <jolsa@kernel.org> > > > --- > > > tools/testing/selftests/bpf/test_verifier.c | 161 +++++++++++++++++--- > > > 1 file changed, 139 insertions(+), 22 deletions(-) > > > > > > > Eduard is working on migrating most (if not all) test_verifier tests > > into test_progs where we can use libbpf declarative functionality for > > things like this. > > > > Eduard, can you please review this part? Would it make sense to just > > wait for the migration? If not, will there be anything involved to > > support something like this for the future migration? > > Hi Andrii, > > I'm not working on migrating remaining test_verifier tests > to test_progs/inline assembly at the moment. > > Regarding this specific change, as far as I understand it is > necessary for the following tests: > - verifier/calls.c > - verifier/map_kptr.c > Both files can't be migrated at the moment. > I spent some time today debugging, but the reasons are > obscure and require further investigation. > > As to this particular patch itself, I tested it locally and > it seems to work fine. None of the changes prohibit future > migration to inline assembly, should such migration happen. > Great, thanks for checking! > Thanks, > Eduard > > > > > > > > diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c > > > index 285ea4aba194..71704a38cac3 100644 > > > --- a/tools/testing/selftests/bpf/test_verifier.c > > > +++ b/tools/testing/selftests/bpf/test_verifier.c > > > @@ -874,8 +874,140 @@ static int create_map_kptr(void) > > > return fd; > > > } > > > > > > > [...] >
diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 285ea4aba194..71704a38cac3 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -874,8 +874,140 @@ static int create_map_kptr(void) return fd; } +static void set_root(bool set) +{ + __u64 caps; + + if (set) { + if (cap_enable_effective(1ULL << CAP_SYS_ADMIN, &caps)) + perror("cap_disable_effective(CAP_SYS_ADMIN)"); + } else { + if (cap_disable_effective(1ULL << CAP_SYS_ADMIN, &caps)) + perror("cap_disable_effective(CAP_SYS_ADMIN)"); + } +} + +static __u64 ptr_to_u64(const void *ptr) +{ + return (uintptr_t) ptr; +} + +static struct btf *btf__load_testmod_btf(struct btf *vmlinux) +{ + struct bpf_btf_info info; + __u32 len = sizeof(info); + struct btf *btf = NULL; + char name[64]; + __u32 id = 0; + int err, fd; + + /* Iterate all loaded BTF objects and find bpf_testmod, + * we need SYS_ADMIN cap for that. + */ + set_root(true); + + while (true) { + err = bpf_btf_get_next_id(id, &id); + if (err) { + if (errno == ENOENT) + break; + perror("bpf_btf_get_next_id failed"); + break; + } + + fd = bpf_btf_get_fd_by_id(id); + if (fd < 0) { + if (errno == ENOENT) + continue; + perror("bpf_btf_get_fd_by_id failed"); + break; + } + + memset(&info, 0, sizeof(info)); + info.name_len = sizeof(name); + info.name = ptr_to_u64(name); + len = sizeof(info); + + err = bpf_obj_get_info_by_fd(fd, &info, &len); + if (err) { + close(fd); + perror("bpf_obj_get_info_by_fd failed"); + break; + } + + if (strcmp("bpf_testmod", name)) { + close(fd); + continue; + } + + btf = btf__load_from_kernel_by_id_split(id, vmlinux); + if (!btf) { + close(fd); + break; + } + + /* We need the fd to stay open so it can be used in fd_array. + * The final cleanup call to btf__free will free btf object + * and close the file descriptor. + */ + btf__set_fd(btf, fd); + break; + } + + set_root(false); + return btf; +} + +static struct btf *testmod_btf; +static struct btf *vmlinux_btf; + +static void kfuncs_cleanup(void) +{ + btf__free(testmod_btf); + btf__free(vmlinux_btf); +} + +static void fixup_prog_kfuncs(struct bpf_insn *prog, int *fd_array, + struct kfunc_btf_id_pair *fixup_kfunc_btf_id) +{ + /* Patch in kfunc BTF IDs */ + while (fixup_kfunc_btf_id->kfunc) { + int btf_id = 0; + + /* try to find kfunc in kernel BTF */ + vmlinux_btf = vmlinux_btf ?: btf__load_vmlinux_btf(); + if (vmlinux_btf) { + btf_id = btf__find_by_name_kind(vmlinux_btf, + fixup_kfunc_btf_id->kfunc, + BTF_KIND_FUNC); + btf_id = btf_id < 0 ? 0 : btf_id; + } + + /* kfunc not found in kernel BTF, try bpf_testmod BTF */ + if (!btf_id) { + testmod_btf = testmod_btf ?: btf__load_testmod_btf(vmlinux_btf); + if (testmod_btf) { + btf_id = btf__find_by_name_kind(testmod_btf, + fixup_kfunc_btf_id->kfunc, + BTF_KIND_FUNC); + btf_id = btf_id < 0 ? 0 : btf_id; + if (btf_id) { + /* We put bpf_testmod module fd into fd_array + * and its index 1 into instruction 'off'. + */ + *fd_array = btf__fd(testmod_btf); + prog[fixup_kfunc_btf_id->insn_idx].off = 1; + } + } + } + + prog[fixup_kfunc_btf_id->insn_idx].imm = btf_id; + fixup_kfunc_btf_id++; + } +} + static void do_test_fixup(struct bpf_test *test, enum bpf_prog_type prog_type, - struct bpf_insn *prog, int *map_fds) + struct bpf_insn *prog, int *map_fds, int *fd_array) { int *fixup_map_hash_8b = test->fixup_map_hash_8b; int *fixup_map_hash_48b = test->fixup_map_hash_48b; @@ -900,7 +1032,6 @@ static void do_test_fixup(struct bpf_test *test, enum bpf_prog_type prog_type, int *fixup_map_ringbuf = test->fixup_map_ringbuf; int *fixup_map_timer = test->fixup_map_timer; int *fixup_map_kptr = test->fixup_map_kptr; - struct kfunc_btf_id_pair *fixup_kfunc_btf_id = test->fixup_kfunc_btf_id; if (test->fill_helper) { test->fill_insns = calloc(MAX_TEST_INSNS, sizeof(struct bpf_insn)); @@ -1101,25 +1232,7 @@ static void do_test_fixup(struct bpf_test *test, enum bpf_prog_type prog_type, } while (*fixup_map_kptr); } - /* Patch in kfunc BTF IDs */ - if (fixup_kfunc_btf_id->kfunc) { - struct btf *btf; - int btf_id; - - do { - btf_id = 0; - btf = btf__load_vmlinux_btf(); - if (btf) { - btf_id = btf__find_by_name_kind(btf, - fixup_kfunc_btf_id->kfunc, - BTF_KIND_FUNC); - btf_id = btf_id < 0 ? 0 : btf_id; - } - btf__free(btf); - prog[fixup_kfunc_btf_id->insn_idx].imm = btf_id; - fixup_kfunc_btf_id++; - } while (fixup_kfunc_btf_id->kfunc); - } + fixup_prog_kfuncs(prog, fd_array, test->fixup_kfunc_btf_id); } struct libcap { @@ -1446,6 +1559,7 @@ static void do_test_single(struct bpf_test *test, bool unpriv, int run_errs, run_successes; int map_fds[MAX_NR_MAPS]; const char *expected_err; + int fd_array[2] = { -1, -1 }; int saved_errno; int fixup_skips; __u32 pflags; @@ -1459,7 +1573,7 @@ static void do_test_single(struct bpf_test *test, bool unpriv, if (!prog_type) prog_type = BPF_PROG_TYPE_SOCKET_FILTER; fixup_skips = skips; - do_test_fixup(test, prog_type, prog, map_fds); + do_test_fixup(test, prog_type, prog, map_fds, &fd_array[1]); if (test->fill_insns) { prog = test->fill_insns; prog_len = test->prog_len; @@ -1493,6 +1607,8 @@ static void do_test_single(struct bpf_test *test, bool unpriv, else opts.log_level = DEFAULT_LIBBPF_LOG_LEVEL; opts.prog_flags = pflags; + if (fd_array[1] != -1) + opts.fd_array = &fd_array[0]; if ((prog_type == BPF_PROG_TYPE_TRACING || prog_type == BPF_PROG_TYPE_LSM) && test->kfunc) { @@ -1719,6 +1835,7 @@ static int do_test(bool unpriv, unsigned int from, unsigned int to) } unload_bpf_testmod(verbose); + kfuncs_cleanup(); printf("Summary: %d PASSED, %d SKIPPED, %d FAILED\n", passes, skips, errors);