forked from starfive-tech/linux
-
Notifications
You must be signed in to change notification settings - Fork 8
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
selftests/bpf: Add tests for dynamic pointers parameters in kfuncs
Add tests to ensure that only supported dynamic pointer types are accepted, that the passed argument is actually a dynamic pointer, that the passed argument is a pointer to the stack, and that bpf_verify_pkcs7_signature() correctly handles dynamic pointers with data set to NULL. The tests are currently in the deny list for s390x (JIT does not support calling kernel function). Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com> Acked-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> Link: https://lore.kernel.org/r/20220920075951.929132-14-roberto.sassu@huaweicloud.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
- Loading branch information
1 parent
fc97590
commit b94fa9f
Showing
3 changed files
with
259 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
164 changes: 164 additions & 0 deletions
164
tools/testing/selftests/bpf/prog_tests/kfunc_dynptr_param.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
|
||
/* | ||
* Copyright (c) 2022 Facebook | ||
* Copyright (C) 2022 Huawei Technologies Duesseldorf GmbH | ||
* | ||
* Author: Roberto Sassu <roberto.sassu@huawei.com> | ||
*/ | ||
|
||
#include <test_progs.h> | ||
#include "test_kfunc_dynptr_param.skel.h" | ||
|
||
static size_t log_buf_sz = 1048576; /* 1 MB */ | ||
static char obj_log_buf[1048576]; | ||
|
||
static struct { | ||
const char *prog_name; | ||
const char *expected_verifier_err_msg; | ||
int expected_runtime_err; | ||
} kfunc_dynptr_tests[] = { | ||
{"dynptr_type_not_supp", | ||
"arg#0 pointer type STRUCT bpf_dynptr_kern points to unsupported dynamic pointer type", 0}, | ||
{"not_valid_dynptr", | ||
"arg#0 pointer type STRUCT bpf_dynptr_kern must be valid and initialized", 0}, | ||
{"not_ptr_to_stack", "arg#0 pointer type STRUCT bpf_dynptr_kern not to stack", 0}, | ||
{"dynptr_data_null", NULL, -EBADMSG}, | ||
}; | ||
|
||
static bool kfunc_not_supported; | ||
|
||
static int libbpf_print_cb(enum libbpf_print_level level, const char *fmt, | ||
va_list args) | ||
{ | ||
if (strcmp(fmt, "libbpf: extern (func ksym) '%s': not found in kernel or module BTFs\n")) | ||
return 0; | ||
|
||
if (strcmp(va_arg(args, char *), "bpf_verify_pkcs7_signature")) | ||
return 0; | ||
|
||
kfunc_not_supported = true; | ||
return 0; | ||
} | ||
|
||
static void verify_fail(const char *prog_name, const char *expected_err_msg) | ||
{ | ||
struct test_kfunc_dynptr_param *skel; | ||
LIBBPF_OPTS(bpf_object_open_opts, opts); | ||
libbpf_print_fn_t old_print_cb; | ||
struct bpf_program *prog; | ||
int err; | ||
|
||
opts.kernel_log_buf = obj_log_buf; | ||
opts.kernel_log_size = log_buf_sz; | ||
opts.kernel_log_level = 1; | ||
|
||
skel = test_kfunc_dynptr_param__open_opts(&opts); | ||
if (!ASSERT_OK_PTR(skel, "test_kfunc_dynptr_param__open_opts")) | ||
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; | ||
|
||
bpf_program__set_autoload(prog, true); | ||
|
||
bpf_map__set_max_entries(skel->maps.ringbuf, getpagesize()); | ||
|
||
kfunc_not_supported = false; | ||
|
||
old_print_cb = libbpf_set_print(libbpf_print_cb); | ||
err = test_kfunc_dynptr_param__load(skel); | ||
libbpf_set_print(old_print_cb); | ||
|
||
if (err < 0 && kfunc_not_supported) { | ||
fprintf(stderr, | ||
"%s:SKIP:bpf_verify_pkcs7_signature() kfunc not supported\n", | ||
__func__); | ||
test__skip(); | ||
goto cleanup; | ||
} | ||
|
||
if (!ASSERT_ERR(err, "unexpected load success")) | ||
goto cleanup; | ||
|
||
if (!ASSERT_OK_PTR(strstr(obj_log_buf, expected_err_msg), "expected_err_msg")) { | ||
fprintf(stderr, "Expected err_msg: %s\n", expected_err_msg); | ||
fprintf(stderr, "Verifier output: %s\n", obj_log_buf); | ||
} | ||
|
||
cleanup: | ||
test_kfunc_dynptr_param__destroy(skel); | ||
} | ||
|
||
static void verify_success(const char *prog_name, int expected_runtime_err) | ||
{ | ||
struct test_kfunc_dynptr_param *skel; | ||
libbpf_print_fn_t old_print_cb; | ||
struct bpf_program *prog; | ||
struct bpf_link *link; | ||
__u32 next_id; | ||
int err; | ||
|
||
skel = test_kfunc_dynptr_param__open(); | ||
if (!ASSERT_OK_PTR(skel, "test_kfunc_dynptr_param__open")) | ||
return; | ||
|
||
skel->bss->pid = getpid(); | ||
|
||
bpf_map__set_max_entries(skel->maps.ringbuf, getpagesize()); | ||
|
||
kfunc_not_supported = false; | ||
|
||
old_print_cb = libbpf_set_print(libbpf_print_cb); | ||
err = test_kfunc_dynptr_param__load(skel); | ||
libbpf_set_print(old_print_cb); | ||
|
||
if (err < 0 && kfunc_not_supported) { | ||
fprintf(stderr, | ||
"%s:SKIP:bpf_verify_pkcs7_signature() kfunc not supported\n", | ||
__func__); | ||
test__skip(); | ||
goto cleanup; | ||
} | ||
|
||
if (!ASSERT_OK(err, "test_kfunc_dynptr_param__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; | ||
|
||
err = bpf_prog_get_next_id(0, &next_id); | ||
|
||
bpf_link__destroy(link); | ||
|
||
if (!ASSERT_OK(err, "bpf_prog_get_next_id")) | ||
goto cleanup; | ||
|
||
ASSERT_EQ(skel->bss->err, expected_runtime_err, "err"); | ||
|
||
cleanup: | ||
test_kfunc_dynptr_param__destroy(skel); | ||
} | ||
|
||
void test_kfunc_dynptr_param(void) | ||
{ | ||
int i; | ||
|
||
for (i = 0; i < ARRAY_SIZE(kfunc_dynptr_tests); i++) { | ||
if (!test__start_subtest(kfunc_dynptr_tests[i].prog_name)) | ||
continue; | ||
|
||
if (kfunc_dynptr_tests[i].expected_verifier_err_msg) | ||
verify_fail(kfunc_dynptr_tests[i].prog_name, | ||
kfunc_dynptr_tests[i].expected_verifier_err_msg); | ||
else | ||
verify_success(kfunc_dynptr_tests[i].prog_name, | ||
kfunc_dynptr_tests[i].expected_runtime_err); | ||
} | ||
} |
94 changes: 94 additions & 0 deletions
94
tools/testing/selftests/bpf/progs/test_kfunc_dynptr_param.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
|
||
/* | ||
* Copyright (C) 2022 Huawei Technologies Duesseldorf GmbH | ||
* | ||
* Author: Roberto Sassu <roberto.sassu@huawei.com> | ||
*/ | ||
|
||
#include "vmlinux.h" | ||
#include <errno.h> | ||
#include <bpf/bpf_helpers.h> | ||
#include <bpf/bpf_tracing.h> | ||
|
||
extern struct bpf_key *bpf_lookup_system_key(__u64 id) __ksym; | ||
extern void bpf_key_put(struct bpf_key *key) __ksym; | ||
extern int bpf_verify_pkcs7_signature(struct bpf_dynptr *data_ptr, | ||
struct bpf_dynptr *sig_ptr, | ||
struct bpf_key *trusted_keyring) __ksym; | ||
|
||
struct { | ||
__uint(type, BPF_MAP_TYPE_RINGBUF); | ||
} ringbuf SEC(".maps"); | ||
|
||
struct { | ||
__uint(type, BPF_MAP_TYPE_ARRAY); | ||
__uint(max_entries, 1); | ||
__type(key, __u32); | ||
__type(value, __u32); | ||
} array_map SEC(".maps"); | ||
|
||
int err, pid; | ||
|
||
char _license[] SEC("license") = "GPL"; | ||
|
||
SEC("?lsm.s/bpf") | ||
int BPF_PROG(dynptr_type_not_supp, int cmd, union bpf_attr *attr, | ||
unsigned int size) | ||
{ | ||
char write_data[64] = "hello there, world!!"; | ||
struct bpf_dynptr ptr; | ||
|
||
bpf_ringbuf_reserve_dynptr(&ringbuf, sizeof(write_data), 0, &ptr); | ||
|
||
return bpf_verify_pkcs7_signature(&ptr, &ptr, NULL); | ||
} | ||
|
||
SEC("?lsm.s/bpf") | ||
int BPF_PROG(not_valid_dynptr, int cmd, union bpf_attr *attr, unsigned int size) | ||
{ | ||
unsigned long val; | ||
|
||
return bpf_verify_pkcs7_signature((struct bpf_dynptr *)&val, | ||
(struct bpf_dynptr *)&val, NULL); | ||
} | ||
|
||
SEC("?lsm.s/bpf") | ||
int BPF_PROG(not_ptr_to_stack, int cmd, union bpf_attr *attr, unsigned int size) | ||
{ | ||
unsigned long val; | ||
|
||
return bpf_verify_pkcs7_signature((struct bpf_dynptr *)val, | ||
(struct bpf_dynptr *)val, NULL); | ||
} | ||
|
||
SEC("lsm.s/bpf") | ||
int BPF_PROG(dynptr_data_null, int cmd, union bpf_attr *attr, unsigned int size) | ||
{ | ||
struct bpf_key *trusted_keyring; | ||
struct bpf_dynptr ptr; | ||
__u32 *value; | ||
int ret, zero = 0; | ||
|
||
if (bpf_get_current_pid_tgid() >> 32 != pid) | ||
return 0; | ||
|
||
value = bpf_map_lookup_elem(&array_map, &zero); | ||
if (!value) | ||
return 0; | ||
|
||
/* Pass invalid flags. */ | ||
ret = bpf_dynptr_from_mem(value, sizeof(*value), ((__u64)~0ULL), &ptr); | ||
if (ret != -EINVAL) | ||
return 0; | ||
|
||
trusted_keyring = bpf_lookup_system_key(0); | ||
if (!trusted_keyring) | ||
return 0; | ||
|
||
err = bpf_verify_pkcs7_signature(&ptr, &ptr, trusted_keyring); | ||
|
||
bpf_key_put(trusted_keyring); | ||
|
||
return 0; | ||
} |