Call bpf_snprintf_btf() with the type_id of a "const void" from the
vmlinux BTF and check the rendered output is the "<unsupported kind:0>"
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 <[email protected]>
---
 .../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 <test_progs.h>
+#include <bpf/btf.h>
+#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 "<unsupported kind:0>"
+ * 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("<unsupported kind:0>") - 1, "ret");
+       ASSERT_STREQ(skel->bss->out, "<unsupported kind:0>", "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 <bpf/bpf_helpers.h>
+
+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


Reply via email to