Message ID | 20230119235833.2948341-6-void@manifault.com (mailing list archive) |
---|---|
State | Superseded |
Delegated to: | BPF |
Headers | show |
Series | Enable cpumasks to be used as kptrs | expand |
On Thu, Jan 19, 2023 at 05:58:30PM -0600, David Vernet wrote: > Now that defining trusted fields in a struct is supported, we should add > selftests to verify the behavior. This patch adds a few such testcases. > > Signed-off-by: David Vernet <void@manifault.com> > --- > tools/testing/selftests/bpf/DENYLIST.s390x | 1 + > .../selftests/bpf/prog_tests/nested_trust.c | 64 +++++++++++++++++++ > .../selftests/bpf/progs/nested_trust_common.h | 12 ++++ > .../bpf/progs/nested_trust_failure.c | 33 ++++++++++ > .../bpf/progs/nested_trust_success.c | 29 +++++++++ > 5 files changed, 139 insertions(+) > create mode 100644 tools/testing/selftests/bpf/prog_tests/nested_trust.c > create mode 100644 tools/testing/selftests/bpf/progs/nested_trust_common.h > create mode 100644 tools/testing/selftests/bpf/progs/nested_trust_failure.c > create mode 100644 tools/testing/selftests/bpf/progs/nested_trust_success.c > > diff --git a/tools/testing/selftests/bpf/DENYLIST.s390x b/tools/testing/selftests/bpf/DENYLIST.s390x > index 96e8371f5c2a..1cf5b94cda30 100644 > --- a/tools/testing/selftests/bpf/DENYLIST.s390x > +++ b/tools/testing/selftests/bpf/DENYLIST.s390x > @@ -44,6 +44,7 @@ map_kptr # failed to open_and_load program: -524 > modify_return # modify_return attach failed: -524 (trampoline) > module_attach # skel_attach skeleton attach failed: -524 (trampoline) > mptcp > +nested_trust # JIT does not support calling kernel function > netcnt # failed to load BPF skeleton 'netcnt_prog': -7 (?) > probe_user # check_kprobe_res wrong kprobe res from probe read (?) > rcu_read_lock # failed to find kernel BTF type ID of '__x64_sys_getpgid': -3 (?) > diff --git a/tools/testing/selftests/bpf/prog_tests/nested_trust.c b/tools/testing/selftests/bpf/prog_tests/nested_trust.c > new file mode 100644 > index 000000000000..4d13612f5001 > --- /dev/null > +++ b/tools/testing/selftests/bpf/prog_tests/nested_trust.c > @@ -0,0 +1,64 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ > + > +#include <test_progs.h> > +#include "nested_trust_failure.skel.h" > +#include "nested_trust_success.skel.h" > + > +static const char * const nested_trust_success_testcases[] = { > + "test_read_cpumask", > +}; > + > +static void verify_success(const char *prog_name) > +{ > + struct nested_trust_success *skel; > + struct bpf_program *prog; > + struct bpf_link *link = NULL; > + int status; > + pid_t child_pid; > + > + skel = nested_trust_success__open(); > + if (!ASSERT_OK_PTR(skel, "nested_trust_success__open")) > + return; > + > + skel->bss->pid = getpid(); > + > + nested_trust_success__load(skel); > + if (!ASSERT_OK_PTR(skel, "nested_trust_success__load")) > + goto cleanup; > + > + prog = bpf_object__find_program_by_name(skel->obj, prog_name); > + if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name")) > + goto cleanup; > + > + link = bpf_program__attach(prog); > + if (!ASSERT_OK_PTR(link, "bpf_program__attach")) > + goto cleanup; > + > + child_pid = fork(); > + if (!ASSERT_GT(child_pid, -1, "child_pid")) > + goto cleanup; > + if (child_pid == 0) > + _exit(0); > + waitpid(child_pid, &status, 0); > + ASSERT_OK(skel->bss->err, "post_wait_err"); > + > + bpf_link__destroy(link); > + > +cleanup: > + nested_trust_success__destroy(skel); > +} > + > +void test_nested_trust(void) > +{ > + int i; > + > + for (i = 0; i < ARRAY_SIZE(nested_trust_success_testcases); i++) { > + if (!test__start_subtest(nested_trust_success_testcases[i])) > + continue; > + > + verify_success(nested_trust_success_testcases[i]); > + } > + > + RUN_TESTS(nested_trust_failure); > +} Hmm. I thought RUN_TESTS() works for successes too. Looking at test_loader.c:run_subtest() that should be the case. Could you please double check? verify_success() above shouldn't be needed.
On Thu, Jan 19, 2023 at 09:51:49PM -0800, Alexei Starovoitov wrote: > On Thu, Jan 19, 2023 at 05:58:30PM -0600, David Vernet wrote: > > Now that defining trusted fields in a struct is supported, we should add > > selftests to verify the behavior. This patch adds a few such testcases. > > > > Signed-off-by: David Vernet <void@manifault.com> > > --- > > tools/testing/selftests/bpf/DENYLIST.s390x | 1 + > > .../selftests/bpf/prog_tests/nested_trust.c | 64 +++++++++++++++++++ > > .../selftests/bpf/progs/nested_trust_common.h | 12 ++++ > > .../bpf/progs/nested_trust_failure.c | 33 ++++++++++ > > .../bpf/progs/nested_trust_success.c | 29 +++++++++ > > 5 files changed, 139 insertions(+) > > create mode 100644 tools/testing/selftests/bpf/prog_tests/nested_trust.c > > create mode 100644 tools/testing/selftests/bpf/progs/nested_trust_common.h > > create mode 100644 tools/testing/selftests/bpf/progs/nested_trust_failure.c > > create mode 100644 tools/testing/selftests/bpf/progs/nested_trust_success.c > > > > diff --git a/tools/testing/selftests/bpf/DENYLIST.s390x b/tools/testing/selftests/bpf/DENYLIST.s390x > > index 96e8371f5c2a..1cf5b94cda30 100644 > > --- a/tools/testing/selftests/bpf/DENYLIST.s390x > > +++ b/tools/testing/selftests/bpf/DENYLIST.s390x > > @@ -44,6 +44,7 @@ map_kptr # failed to open_and_load program: -524 > > modify_return # modify_return attach failed: -524 (trampoline) > > module_attach # skel_attach skeleton attach failed: -524 (trampoline) > > mptcp > > +nested_trust # JIT does not support calling kernel function > > netcnt # failed to load BPF skeleton 'netcnt_prog': -7 (?) > > probe_user # check_kprobe_res wrong kprobe res from probe read (?) > > rcu_read_lock # failed to find kernel BTF type ID of '__x64_sys_getpgid': -3 (?) > > diff --git a/tools/testing/selftests/bpf/prog_tests/nested_trust.c b/tools/testing/selftests/bpf/prog_tests/nested_trust.c > > new file mode 100644 > > index 000000000000..4d13612f5001 > > --- /dev/null > > +++ b/tools/testing/selftests/bpf/prog_tests/nested_trust.c > > @@ -0,0 +1,64 @@ > > +// SPDX-License-Identifier: GPL-2.0 > > +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ > > + > > +#include <test_progs.h> > > +#include "nested_trust_failure.skel.h" > > +#include "nested_trust_success.skel.h" > > + > > +static const char * const nested_trust_success_testcases[] = { > > + "test_read_cpumask", > > +}; > > + > > +static void verify_success(const char *prog_name) > > +{ > > + struct nested_trust_success *skel; > > + struct bpf_program *prog; > > + struct bpf_link *link = NULL; > > + int status; > > + pid_t child_pid; > > + > > + skel = nested_trust_success__open(); > > + if (!ASSERT_OK_PTR(skel, "nested_trust_success__open")) > > + return; > > + > > + skel->bss->pid = getpid(); > > + > > + nested_trust_success__load(skel); > > + if (!ASSERT_OK_PTR(skel, "nested_trust_success__load")) > > + goto cleanup; > > + > > + prog = bpf_object__find_program_by_name(skel->obj, prog_name); > > + if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name")) > > + goto cleanup; > > + > > + link = bpf_program__attach(prog); > > + if (!ASSERT_OK_PTR(link, "bpf_program__attach")) > > + goto cleanup; > > + > > + child_pid = fork(); > > + if (!ASSERT_GT(child_pid, -1, "child_pid")) > > + goto cleanup; > > + if (child_pid == 0) > > + _exit(0); > > + waitpid(child_pid, &status, 0); > > + ASSERT_OK(skel->bss->err, "post_wait_err"); > > + > > + bpf_link__destroy(link); > > + > > +cleanup: > > + nested_trust_success__destroy(skel); > > +} > > + > > +void test_nested_trust(void) > > +{ > > + int i; > > + > > + for (i = 0; i < ARRAY_SIZE(nested_trust_success_testcases); i++) { > > + if (!test__start_subtest(nested_trust_success_testcases[i])) > > + continue; > > + > > + verify_success(nested_trust_success_testcases[i]); > > + } > > + > > + RUN_TESTS(nested_trust_failure); > > +} > > Hmm. I thought RUN_TESTS() works for successes too. > Looking at test_loader.c:run_subtest() that should be the case. > Could you please double check? > verify_success() above shouldn't be needed. Yes, looks like RUN_TESTS() works for success cases too, it just isn't used anywhere yet. I expect it won't be super commonly used given that it only loads the program and tests the verifier rather than doing any runtime validation, but that's exactly what we want for this so I'll update that in v2. I'll plan on leaving the cpumask success cases as they are unless you object so that we can get runtime coverage as well.
diff --git a/tools/testing/selftests/bpf/DENYLIST.s390x b/tools/testing/selftests/bpf/DENYLIST.s390x index 96e8371f5c2a..1cf5b94cda30 100644 --- a/tools/testing/selftests/bpf/DENYLIST.s390x +++ b/tools/testing/selftests/bpf/DENYLIST.s390x @@ -44,6 +44,7 @@ map_kptr # failed to open_and_load program: -524 modify_return # modify_return attach failed: -524 (trampoline) module_attach # skel_attach skeleton attach failed: -524 (trampoline) mptcp +nested_trust # JIT does not support calling kernel function netcnt # failed to load BPF skeleton 'netcnt_prog': -7 (?) probe_user # check_kprobe_res wrong kprobe res from probe read (?) rcu_read_lock # failed to find kernel BTF type ID of '__x64_sys_getpgid': -3 (?) diff --git a/tools/testing/selftests/bpf/prog_tests/nested_trust.c b/tools/testing/selftests/bpf/prog_tests/nested_trust.c new file mode 100644 index 000000000000..4d13612f5001 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/nested_trust.c @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ + +#include <test_progs.h> +#include "nested_trust_failure.skel.h" +#include "nested_trust_success.skel.h" + +static const char * const nested_trust_success_testcases[] = { + "test_read_cpumask", +}; + +static void verify_success(const char *prog_name) +{ + struct nested_trust_success *skel; + struct bpf_program *prog; + struct bpf_link *link = NULL; + int status; + pid_t child_pid; + + skel = nested_trust_success__open(); + if (!ASSERT_OK_PTR(skel, "nested_trust_success__open")) + return; + + skel->bss->pid = getpid(); + + nested_trust_success__load(skel); + if (!ASSERT_OK_PTR(skel, "nested_trust_success__load")) + goto cleanup; + + prog = bpf_object__find_program_by_name(skel->obj, prog_name); + if (!ASSERT_OK_PTR(prog, "bpf_object__find_program_by_name")) + goto cleanup; + + link = bpf_program__attach(prog); + if (!ASSERT_OK_PTR(link, "bpf_program__attach")) + goto cleanup; + + child_pid = fork(); + if (!ASSERT_GT(child_pid, -1, "child_pid")) + goto cleanup; + if (child_pid == 0) + _exit(0); + waitpid(child_pid, &status, 0); + ASSERT_OK(skel->bss->err, "post_wait_err"); + + bpf_link__destroy(link); + +cleanup: + nested_trust_success__destroy(skel); +} + +void test_nested_trust(void) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(nested_trust_success_testcases); i++) { + if (!test__start_subtest(nested_trust_success_testcases[i])) + continue; + + verify_success(nested_trust_success_testcases[i]); + } + + RUN_TESTS(nested_trust_failure); +} diff --git a/tools/testing/selftests/bpf/progs/nested_trust_common.h b/tools/testing/selftests/bpf/progs/nested_trust_common.h new file mode 100644 index 000000000000..83d33931136e --- /dev/null +++ b/tools/testing/selftests/bpf/progs/nested_trust_common.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ + +#ifndef _NESTED_TRUST_COMMON_H +#define _NESTED_TRUST_COMMON_H + +#include <stdbool.h> + +bool bpf_cpumask_test_cpu(unsigned int cpu, const struct cpumask *cpumask) __ksym; +bool bpf_cpumask_first_zero(const struct cpumask *cpumask) __ksym; + +#endif /* _NESTED_TRUST_COMMON_H */ diff --git a/tools/testing/selftests/bpf/progs/nested_trust_failure.c b/tools/testing/selftests/bpf/progs/nested_trust_failure.c new file mode 100644 index 000000000000..14aff7676436 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/nested_trust_failure.c @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ + +#include <vmlinux.h> +#include <bpf/bpf_tracing.h> +#include <bpf/bpf_helpers.h> +#include "bpf_misc.h" + +#include "nested_trust_common.h" + +char _license[] SEC("license") = "GPL"; + +/* Prototype for all of the program trace events below: + * + * TRACE_EVENT(task_newtask, + * TP_PROTO(struct task_struct *p, u64 clone_flags) + */ + +SEC("tp_btf/task_newtask") +__failure __msg("R2 must be referenced or trusted") +int BPF_PROG(test_invalid_nested_user_cpus, struct task_struct *task, u64 clone_flags) +{ + bpf_cpumask_test_cpu(0, task->user_cpus_ptr); + return 0; +} + +SEC("tp_btf/task_newtask") +__failure __msg("R1 must have zero offset when passed to release func or trusted arg to kfunc") +int BPF_PROG(test_invalid_nested_offset, struct task_struct *task, u64 clone_flags) +{ + bpf_cpumask_first_zero(&task->cpus_mask); + return 0; +} diff --git a/tools/testing/selftests/bpf/progs/nested_trust_success.c b/tools/testing/selftests/bpf/progs/nested_trust_success.c new file mode 100644 index 000000000000..04079f120bea --- /dev/null +++ b/tools/testing/selftests/bpf/progs/nested_trust_success.c @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */ + +#include <vmlinux.h> +#include <bpf/bpf_tracing.h> +#include <bpf/bpf_helpers.h> + +#include "nested_trust_common.h" + +char _license[] SEC("license") = "GPL"; + +int pid, err; + +static bool is_test_task(void) +{ + int cur_pid = bpf_get_current_pid_tgid() >> 32; + + return pid == cur_pid; +} + +SEC("tp_btf/task_newtask") +int BPF_PROG(test_read_cpumask, struct task_struct *task, u64 clone_flags) +{ + if (!is_test_task()) + return 0; + + bpf_cpumask_test_cpu(0, task->cpus_ptr); + return 0; +}
Now that defining trusted fields in a struct is supported, we should add selftests to verify the behavior. This patch adds a few such testcases. Signed-off-by: David Vernet <void@manifault.com> --- tools/testing/selftests/bpf/DENYLIST.s390x | 1 + .../selftests/bpf/prog_tests/nested_trust.c | 64 +++++++++++++++++++ .../selftests/bpf/progs/nested_trust_common.h | 12 ++++ .../bpf/progs/nested_trust_failure.c | 33 ++++++++++ .../bpf/progs/nested_trust_success.c | 29 +++++++++ 5 files changed, 139 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/nested_trust.c create mode 100644 tools/testing/selftests/bpf/progs/nested_trust_common.h create mode 100644 tools/testing/selftests/bpf/progs/nested_trust_failure.c create mode 100644 tools/testing/selftests/bpf/progs/nested_trust_success.c