xref: /linux/tools/testing/selftests/bpf/prog_tests/snprintf_btf.c (revision 14c5eb685cdefbd32e73d2723071ecbd8effbce9)
1 // SPDX-License-Identifier: GPL-2.0
2 #include <test_progs.h>
3 #include <linux/btf.h>
4 #include <bpf/btf.h>
5 #include "netif_receive_skb.skel.h"
6 #include "snprintf_btf_void.skel.h"
7 
8 /* Demonstrate that bpf_snprintf_btf succeeds and that various data types
9  * are formatted correctly.
10  */
11 void serial_test_snprintf_btf(void)
12 {
13 	struct netif_receive_skb *skel;
14 	struct netif_receive_skb__bss *bss;
15 	int err, duration = 0;
16 
17 	skel = netif_receive_skb__open();
18 	if (CHECK(!skel, "skel_open", "failed to open skeleton\n"))
19 		return;
20 
21 	err = netif_receive_skb__load(skel);
22 	if (CHECK(err, "skel_load", "failed to load skeleton: %d\n", err))
23 		goto cleanup;
24 
25 	bss = skel->bss;
26 
27 	err = netif_receive_skb__attach(skel);
28 	if (CHECK(err, "skel_attach", "skeleton attach failed: %d\n", err))
29 		goto cleanup;
30 
31 	/* generate receive event */
32 	err = system("ping -c 1 127.0.0.1 > /dev/null");
33 	if (CHECK(err, "system", "ping failed: %d\n", err))
34 		goto cleanup;
35 
36 	if (bss->skip) {
37 		printf("%s:SKIP:no __builtin_btf_type_id\n", __func__);
38 		test__skip();
39 		goto cleanup;
40 	}
41 
42 	/*
43 	 * Make sure netif_receive_skb program was triggered
44 	 * and it set expected return values from bpf_trace_printk()s
45 	 * and all tests ran.
46 	 */
47 	if (!ASSERT_GT(bss->ret, 0, "bpf_snprintf_ret"))
48 		goto cleanup;
49 
50 	if (CHECK(bss->ran_subtests == 0, "check if subtests ran",
51 		  "no subtests ran, did BPF program run?"))
52 		goto cleanup;
53 
54 	if (CHECK(bss->num_subtests != bss->ran_subtests,
55 		  "check all subtests ran",
56 		  "only ran %d of %d tests\n", bss->num_subtests,
57 		  bss->ran_subtests))
58 		goto cleanup;
59 
60 cleanup:
61 	netif_receive_skb__destroy(skel);
62 }
63 
64 /*
65  * bpf_snprintf_btf() renders a type_id taken straight from the vmlinux BTF.
66  * Two such type_ids used to NULL-deref in the BTF show path:
67  *   - a "const void" (a modifier resolving to void) in btf_modifier_show()
68  *   - a BTF_KIND_VAR in btf_var_show() (base BTF has no resolved_ids)
69  * A fixed kernel renders both without crashing.
70  */
71 static long run(struct snprintf_btf_void *skel, __u32 type_id)
72 {
73 	LIBBPF_OPTS(bpf_test_run_opts, topts);
74 	char ctx[8] = {};
75 
76 	skel->bss->type_id = type_id;
77 	topts.ctx_in = ctx;
78 	topts.ctx_size_in = sizeof(ctx);
79 	if (!ASSERT_OK(bpf_prog_test_run_opts(bpf_program__fd(skel->progs.dump_type),
80 					      &topts), "test_run"))
81 		return -1;
82 	return skel->bss->ret;
83 }
84 
85 void test_snprintf_btf_void(void)
86 {
87 	const struct btf_type *t;
88 	struct snprintf_btf_void *skel;
89 	int i, n, cv = 0, var = 0;
90 	struct btf *btf;
91 
92 	btf = btf__parse("/sys/kernel/btf/vmlinux", NULL);
93 	if (!btf) {
94 		test__skip();
95 		return;
96 	}
97 
98 	skel = snprintf_btf_void__open_and_load();
99 	if (!ASSERT_OK_PTR(skel, "skel_open_and_load"))
100 		goto out_btf;
101 
102 	n = btf__type_cnt(btf);
103 	for (i = 1; i < n && !(cv && var); i++) {
104 		t = btf__type_by_id(btf, i);
105 		if (!cv && btf_kind(t) == BTF_KIND_CONST && t->type == 0)
106 			cv = i;
107 		/* Pick a VAR small enough to render from the program's buffer. */
108 		if (!var && btf_kind(t) == BTF_KIND_VAR) {
109 			long sz = btf__resolve_size(btf, t->type);
110 
111 			if (sz > 0 && sz <= (long)sizeof(skel->bss->obj))
112 				var = i;
113 		}
114 	}
115 
116 	/* "const void" renders the "<unsupported kind:0>" placeholder. */
117 	if (test__start_subtest("const_void")) {
118 		if (cv) {
119 			ASSERT_EQ(run(skel, cv),
120 				  sizeof("<unsupported kind:0>") - 1, "ret");
121 			ASSERT_STREQ(skel->bss->out, "<unsupported kind:0>",
122 				     "placeholder");
123 		} else {
124 			test__skip();
125 		}
126 	}
127 
128 	/* A BTF_KIND_VAR must resolve and render without error. */
129 	if (test__start_subtest("var")) {
130 		if (var)
131 			ASSERT_GT(run(skel, var), 0, "ret");
132 		else
133 			test__skip();
134 	}
135 
136 	snprintf_btf_void__destroy(skel);
137 out_btf:
138 	btf__free(btf);
139 }
140