mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-20 09:34:44 +08:00
selftests/bpf: Allow to use kfunc from testmod.ko in test_verifier
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> Link: https://lore.kernel.org/r/20230515133756.1658301-9-jolsa@kernel.org Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
parent
b23b385fa1
commit
f26ebdd3e4
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user