Call bpf_snprintf_btf() with the type_id of a "const void" from the vmlinux BTF and check the rendered output is the "" placeholder. On an unfixed kernel this used to NULL-deref in btf_modifier_show(), so the test doubles as a reproducer: it oopses the task (and panics it under panic_on_oops). Signed-off-by: Jiayuan Chen --- .../selftests/bpf/prog_tests/btf_show_void.c | 57 +++++++++++++++++++ .../selftests/bpf/progs/btf_show_void.c | 22 +++++++ 2 files changed, 79 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/btf_show_void.c create mode 100644 tools/testing/selftests/bpf/progs/btf_show_void.c diff --git a/tools/testing/selftests/bpf/prog_tests/btf_show_void.c b/tools/testing/selftests/bpf/prog_tests/btf_show_void.c new file mode 100644 index 000000000000..546833199195 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/btf_show_void.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include "btf_show_void.skel.h" + +/* + * bpf_snprintf_btf() with the type_id of a "const void" (a modifier that + * resolves to void, present in the vmlinux BTF) used to NULL-deref in + * btf_modifier_show(). A fixed kernel prints the "" + * placeholder; on an unfixed kernel this oopses the task (and panics it under + * panic_on_oops), so it doubles as a reproducer. + */ +void test_btf_show_void(void) +{ + LIBBPF_OPTS(bpf_test_run_opts, topts); + const struct btf_type *t; + struct btf_show_void *skel; + int i, n, cv = 0, err; + char ctx[16] = {}; + struct btf *btf; + + btf = btf__parse("/sys/kernel/btf/vmlinux", NULL); + if (!ASSERT_OK_PTR(btf, "btf__parse vmlinux")) + return; + + n = btf__type_cnt(btf); + for (i = 1; i < n; i++) { + t = btf__type_by_id(btf, i); + if (btf_kind(t) == BTF_KIND_CONST && t->type == 0) { + cv = i; + break; + } + } + if (!ASSERT_GT(cv, 0, "find const void in vmlinux BTF")) + goto out_btf; + + skel = btf_show_void__open(); + if (!ASSERT_OK_PTR(skel, "skel_open")) + goto out_btf; + skel->rodata->const_void_id = cv; + if (!ASSERT_OK(btf_show_void__load(skel), "skel_load")) + goto out_skel; + + topts.ctx_in = ctx; + topts.ctx_size_in = sizeof(ctx); + err = bpf_prog_test_run_opts(bpf_program__fd(skel->progs.dump_const_void), + &topts); + if (!ASSERT_OK(err, "test_run")) + goto out_skel; + + ASSERT_EQ(skel->bss->ret, sizeof("") - 1, "ret"); + ASSERT_STREQ(skel->bss->out, "", "placeholder"); +out_skel: + btf_show_void__destroy(skel); +out_btf: + btf__free(btf); +} diff --git a/tools/testing/selftests/bpf/progs/btf_show_void.c b/tools/testing/selftests/bpf/progs/btf_show_void.c new file mode 100644 index 000000000000..9fabd7372f89 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/btf_show_void.c @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0 +#include "btf_ptr.h" +#include + +const volatile __u32 const_void_id; +char out[64]; +long ret; + +SEC("raw_tp/sys_enter") +int dump_const_void(void *ctx) +{ + struct btf_ptr ptr = { + .ptr = ctx, + .type_id = const_void_id, + .flags = 0, + }; + + ret = bpf_snprintf_btf(out, sizeof(out), &ptr, sizeof(ptr), 0); + return 0; +} + +char _license[] SEC("license") = "GPL"; -- 2.43.0