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