1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
3 #include <test_progs.h>
4 #include <bpf/btf.h>
5 
6 #include "test_log_fixup.skel.h"
7 
8 enum trunc_type {
9 	TRUNC_NONE,
10 	TRUNC_PARTIAL,
11 	TRUNC_FULL,
12 };
13 
14 static void bad_core_relo(size_t log_buf_size, enum trunc_type trunc_type)
15 {
16 	char log_buf[8 * 1024];
17 	struct test_log_fixup* skel;
18 	int err;
19 
20 	skel = test_log_fixup__open();
21 	if (!ASSERT_OK_PTR(skel, "skel_open"))
22 		return;
23 
24 	bpf_program__set_autoload(skel->progs.bad_relo, true);
25 	memset(log_buf, 0, sizeof(log_buf));
26 	bpf_program__set_log_buf(skel->progs.bad_relo, log_buf, log_buf_size ?: sizeof(log_buf));
27 	bpf_program__set_log_level(skel->progs.bad_relo, 1 | 8); /* BPF_LOG_FIXED to force truncation */
28 
29 	err = test_log_fixup__load(skel);
30 	if (!ASSERT_ERR(err, "load_fail"))
31 		goto cleanup;
32 
33 	ASSERT_HAS_SUBSTR(log_buf,
34 			  "0: <invalid CO-RE relocation>\n"
35 			  "failed to resolve CO-RE relocation <byte_sz> ",
36 			  "log_buf_part1");
37 
38 	switch (trunc_type) {
39 	case TRUNC_NONE:
40 		ASSERT_HAS_SUBSTR(log_buf,
41 				  "struct task_struct___bad.fake_field (0:1 @ offset 4)\n",
42 				  "log_buf_part2");
43 		ASSERT_HAS_SUBSTR(log_buf,
44 				  "max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0\n",
45 				  "log_buf_end");
46 		break;
47 	case TRUNC_PARTIAL:
48 		/* we should get full libbpf message patch */
49 		ASSERT_HAS_SUBSTR(log_buf,
50 				  "struct task_struct___bad.fake_field (0:1 @ offset 4)\n",
51 				  "log_buf_part2");
52 		/* we shouldn't get full end of BPF verifier log */
53 		ASSERT_NULL(strstr(log_buf, "max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0\n"),
54 			    "log_buf_end");
55 		break;
56 	case TRUNC_FULL:
57 		/* we shouldn't get second part of libbpf message patch */
58 		ASSERT_NULL(strstr(log_buf, "struct task_struct___bad.fake_field (0:1 @ offset 4)\n"),
59 			    "log_buf_part2");
60 		/* we shouldn't get full end of BPF verifier log */
61 		ASSERT_NULL(strstr(log_buf, "max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0\n"),
62 			    "log_buf_end");
63 		break;
64 	}
65 
66 	if (env.verbosity > VERBOSE_NONE)
67 		printf("LOG:   \n=================\n%s=================\n", log_buf);
68 cleanup:
69 	test_log_fixup__destroy(skel);
70 }
71 
72 static void bad_core_relo_subprog(void)
73 {
74 	char log_buf[8 * 1024];
75 	struct test_log_fixup* skel;
76 	int err;
77 
78 	skel = test_log_fixup__open();
79 	if (!ASSERT_OK_PTR(skel, "skel_open"))
80 		return;
81 
82 	bpf_program__set_autoload(skel->progs.bad_relo_subprog, true);
83 	bpf_program__set_log_buf(skel->progs.bad_relo_subprog, log_buf, sizeof(log_buf));
84 
85 	err = test_log_fixup__load(skel);
86 	if (!ASSERT_ERR(err, "load_fail"))
87 		goto cleanup;
88 
89 	ASSERT_HAS_SUBSTR(log_buf,
90 			  ": <invalid CO-RE relocation>\n"
91 			  "failed to resolve CO-RE relocation <byte_off> ",
92 			  "log_buf");
93 	ASSERT_HAS_SUBSTR(log_buf,
94 			  "struct task_struct___bad.fake_field_subprog (0:2 @ offset 8)\n",
95 			  "log_buf");
96 
97 	if (env.verbosity > VERBOSE_NONE)
98 		printf("LOG:   \n=================\n%s=================\n", log_buf);
99 
100 cleanup:
101 	test_log_fixup__destroy(skel);
102 }
103 
104 static void missing_map(void)
105 {
106 	char log_buf[8 * 1024];
107 	struct test_log_fixup* skel;
108 	int err;
109 
110 	skel = test_log_fixup__open();
111 	if (!ASSERT_OK_PTR(skel, "skel_open"))
112 		return;
113 
114 	bpf_map__set_autocreate(skel->maps.missing_map, false);
115 
116 	bpf_program__set_autoload(skel->progs.use_missing_map, true);
117 	bpf_program__set_log_buf(skel->progs.use_missing_map, log_buf, sizeof(log_buf));
118 
119 	err = test_log_fixup__load(skel);
120 	if (!ASSERT_ERR(err, "load_fail"))
121 		goto cleanup;
122 
123 	ASSERT_TRUE(bpf_map__autocreate(skel->maps.existing_map), "existing_map_autocreate");
124 	ASSERT_FALSE(bpf_map__autocreate(skel->maps.missing_map), "missing_map_autocreate");
125 
126 	ASSERT_HAS_SUBSTR(log_buf,
127 			  ": <invalid BPF map reference>\n"
128 			  "BPF map 'missing_map' is referenced but wasn't created\n",
129 			  "log_buf");
130 
131 	if (env.verbosity > VERBOSE_NONE)
132 		printf("LOG:   \n=================\n%s=================\n", log_buf);
133 
134 cleanup:
135 	test_log_fixup__destroy(skel);
136 }
137 
138 static void missing_kfunc(void)
139 {
140 	char log_buf[8 * 1024];
141 	struct test_log_fixup* skel;
142 	int err;
143 
144 	skel = test_log_fixup__open();
145 	if (!ASSERT_OK_PTR(skel, "skel_open"))
146 		return;
147 
148 	bpf_program__set_autoload(skel->progs.use_missing_kfunc, true);
149 	bpf_program__set_log_buf(skel->progs.use_missing_kfunc, log_buf, sizeof(log_buf));
150 
151 	err = test_log_fixup__load(skel);
152 	if (!ASSERT_ERR(err, "load_fail"))
153 		goto cleanup;
154 
155 	ASSERT_HAS_SUBSTR(log_buf,
156 			  "0: <invalid kfunc call>\n"
157 			  "kfunc 'bpf_nonexistent_kfunc' is referenced but wasn't resolved\n",
158 			  "log_buf");
159 
160 	if (env.verbosity > VERBOSE_NONE)
161 		printf("LOG:   \n=================\n%s=================\n", log_buf);
162 
163 cleanup:
164 	test_log_fixup__destroy(skel);
165 }
166 
167 void test_log_fixup(void)
168 {
169 	if (test__start_subtest("bad_core_relo_trunc_none"))
170 		bad_core_relo(0, TRUNC_NONE /* full buf */);
171 	if (test__start_subtest("bad_core_relo_trunc_partial"))
172 		bad_core_relo(300, TRUNC_PARTIAL /* truncate original log a bit */);
173 	if (test__start_subtest("bad_core_relo_trunc_full"))
174 		bad_core_relo(210, TRUNC_FULL  /* truncate also libbpf's message patch */);
175 	if (test__start_subtest("bad_core_relo_subprog"))
176 		bad_core_relo_subprog();
177 	if (test__start_subtest("missing_map"))
178 		missing_map();
179 	if (test__start_subtest("missing_kfunc"))
180 		missing_kfunc();
181 }
182