On Wed, 24 Aug 2022 at 15:41, Benjamin Tissoires benjamin.tissoires@redhat.com wrote:
We need to also export the kfunc set to the syscall program type, and then add a couple of eBPF programs that are testing those calls.
The first one checks for valid access, and the second one is OK from a static analysis point of view but fails at run time because we are trying to access outside of the allocated memory.
Signed-off-by: Benjamin Tissoires benjamin.tissoires@redhat.com
no changes in v9
no changes in v8
changes in v7:
- add 1 more case to ensure we can read the entire sizeof(ctx)
- add a test case for when the context is NULL
new in v6
net/bpf/test_run.c | 1 + .../selftests/bpf/prog_tests/kfunc_call.c | 28 +++++++++++++++ .../selftests/bpf/progs/kfunc_call_test.c | 36 +++++++++++++++++++ 3 files changed, 65 insertions(+)
diff --git a/net/bpf/test_run.c b/net/bpf/test_run.c index 25d8ecf105aa..f16baf977a21 100644 --- a/net/bpf/test_run.c +++ b/net/bpf/test_run.c @@ -1634,6 +1634,7 @@ static int __init bpf_prog_test_run_init(void)
ret = register_btf_kfunc_id_set(BPF_PROG_TYPE_SCHED_CLS, &bpf_prog_test_kfunc_set); ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_TRACING, &bpf_prog_test_kfunc_set);
ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SYSCALL, &bpf_prog_test_kfunc_set); return ret ?: register_btf_id_dtor_kfuncs(bpf_prog_test_dtor_kfunc, ARRAY_SIZE(bpf_prog_test_dtor_kfunc), THIS_MODULE);
diff --git a/tools/testing/selftests/bpf/prog_tests/kfunc_call.c b/tools/testing/selftests/bpf/prog_tests/kfunc_call.c index eede7c304f86..1edad012fe01 100644 --- a/tools/testing/selftests/bpf/prog_tests/kfunc_call.c +++ b/tools/testing/selftests/bpf/prog_tests/kfunc_call.c @@ -9,10 +9,22 @@
#include "cap_helpers.h"
+struct syscall_test_args {
__u8 data[16];
size_t size;
+};
static void test_main(void) { struct kfunc_call_test_lskel *skel; int prog_fd, err;
struct syscall_test_args args = {
.size = 10,
};
DECLARE_LIBBPF_OPTS(bpf_test_run_opts, syscall_topts,
.ctx_in = &args,
.ctx_size_in = sizeof(args),
); LIBBPF_OPTS(bpf_test_run_opts, topts, .data_in = &pkt_v4, .data_size_in = sizeof(pkt_v4),
@@ -38,6 +50,22 @@ static void test_main(void) ASSERT_OK(err, "bpf_prog_test_run(test_ref_btf_id)"); ASSERT_EQ(topts.retval, 0, "test_ref_btf_id-retval");
prog_fd = skel->progs.kfunc_syscall_test.prog_fd;
err = bpf_prog_test_run_opts(prog_fd, &syscall_topts);
ASSERT_OK(err, "bpf_prog_test_run(syscall_test)");
prog_fd = skel->progs.kfunc_syscall_test_fail.prog_fd;
err = bpf_prog_test_run_opts(prog_fd, &syscall_topts);
ASSERT_ERR(err, "bpf_prog_test_run(syscall_test_fail)");
It would be better to assert on the verifier error string, to make sure we continue actually testing the error we care about and not something else.
syscall_topts.ctx_in = NULL;
syscall_topts.ctx_size_in = 0;
prog_fd = skel->progs.kfunc_syscall_test_null.prog_fd;
err = bpf_prog_test_run_opts(prog_fd, &syscall_topts);
ASSERT_OK(err, "bpf_prog_test_run(syscall_test_null)");
ASSERT_EQ(syscall_topts.retval, 0, "syscall_test_null-retval");
kfunc_call_test_lskel__destroy(skel);
}
diff --git a/tools/testing/selftests/bpf/progs/kfunc_call_test.c b/tools/testing/selftests/bpf/progs/kfunc_call_test.c index 5aecbb9fdc68..da7ae0ef9100 100644 --- a/tools/testing/selftests/bpf/progs/kfunc_call_test.c +++ b/tools/testing/selftests/bpf/progs/kfunc_call_test.c @@ -92,4 +92,40 @@ int kfunc_call_test_pass(struct __sk_buff *skb) return 0; }
+struct syscall_test_args {
__u8 data[16];
size_t size;
+};
+SEC("syscall") +int kfunc_syscall_test(struct syscall_test_args *args) +{
const int size = args->size;
if (size > sizeof(args->data))
return -7; /* -E2BIG */
bpf_kfunc_call_test_mem_len_pass1(&args->data, sizeof(args->data));
bpf_kfunc_call_test_mem_len_pass1(&args->data, sizeof(*args));
bpf_kfunc_call_test_mem_len_pass1(&args->data, size);
return 0;
+}
+SEC("syscall") +int kfunc_syscall_test_null(struct syscall_test_args *args) +{
bpf_kfunc_call_test_mem_len_pass1(args, 0);
Where is it testing 'NULL'? It is testing zero_size_allowed.
return 0;
+}
+SEC("syscall") +int kfunc_syscall_test_fail(struct syscall_test_args *args) +{
bpf_kfunc_call_test_mem_len_pass1(&args->data, sizeof(*args) + 1);
return 0;
+}
char _license[] SEC("license") = "GPL";
2.36.1