1 // SPDX-License-Identifier: GPL-2.0-only
2 /* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */
3 #include <stdlib.h>
4 #include <test_progs.h>
5 #include <bpf/btf.h>
6 
7 #define str_has_pfx(str, pfx) \
8 	(strncmp(str, pfx, __builtin_constant_p(pfx) ? sizeof(pfx) - 1 : strlen(pfx)) == 0)
9 
10 #define TEST_LOADER_LOG_BUF_SZ 1048576
11 
12 #define TEST_TAG_EXPECT_FAILURE "comment:test_expect_failure"
13 #define TEST_TAG_EXPECT_SUCCESS "comment:test_expect_success"
14 #define TEST_TAG_EXPECT_MSG_PFX "comment:test_expect_msg="
15 #define TEST_TAG_LOG_LEVEL_PFX "comment:test_log_level="
16 
17 struct test_spec {
18 	const char *name;
19 	bool expect_failure;
20 	const char *expect_msg;
21 	int log_level;
22 };
23 
24 static int tester_init(struct test_loader *tester)
25 {
26 	if (!tester->log_buf) {
27 		tester->log_buf_sz = TEST_LOADER_LOG_BUF_SZ;
28 		tester->log_buf = malloc(tester->log_buf_sz);
29 		if (!ASSERT_OK_PTR(tester->log_buf, "tester_log_buf"))
30 			return -ENOMEM;
31 	}
32 
33 	return 0;
34 }
35 
36 void test_loader_fini(struct test_loader *tester)
37 {
38 	if (!tester)
39 		return;
40 
41 	free(tester->log_buf);
42 }
43 
44 static int parse_test_spec(struct test_loader *tester,
45 			   struct bpf_object *obj,
46 			   struct bpf_program *prog,
47 			   struct test_spec *spec)
48 {
49 	struct btf *btf;
50 	int func_id, i;
51 
52 	memset(spec, 0, sizeof(*spec));
53 
54 	spec->name = bpf_program__name(prog);
55 
56 	btf = bpf_object__btf(obj);
57 	if (!btf) {
58 		ASSERT_FAIL("BPF object has no BTF");
59 		return -EINVAL;
60 	}
61 
62 	func_id = btf__find_by_name_kind(btf, spec->name, BTF_KIND_FUNC);
63 	if (func_id < 0) {
64 		ASSERT_FAIL("failed to find FUNC BTF type for '%s'", spec->name);
65 		return -EINVAL;
66 	}
67 
68 	for (i = 1; i < btf__type_cnt(btf); i++) {
69 		const struct btf_type *t;
70 		const char *s;
71 
72 		t = btf__type_by_id(btf, i);
73 		if (!btf_is_decl_tag(t))
74 			continue;
75 
76 		if (t->type != func_id || btf_decl_tag(t)->component_idx != -1)
77 			continue;
78 
79 		s = btf__str_by_offset(btf, t->name_off);
80 		if (strcmp(s, TEST_TAG_EXPECT_FAILURE) == 0) {
81 			spec->expect_failure = true;
82 		} else if (strcmp(s, TEST_TAG_EXPECT_SUCCESS) == 0) {
83 			spec->expect_failure = false;
84 		} else if (str_has_pfx(s, TEST_TAG_EXPECT_MSG_PFX)) {
85 			spec->expect_msg = s + sizeof(TEST_TAG_EXPECT_MSG_PFX) - 1;
86 		} else if (str_has_pfx(s, TEST_TAG_LOG_LEVEL_PFX)) {
87 			errno = 0;
88 			spec->log_level = strtol(s + sizeof(TEST_TAG_LOG_LEVEL_PFX) - 1, NULL, 0);
89 			if (errno) {
90 				ASSERT_FAIL("failed to parse test log level from '%s'", s);
91 				return -EINVAL;
92 			}
93 		}
94 	}
95 
96 	return 0;
97 }
98 
99 static void prepare_case(struct test_loader *tester,
100 			 struct test_spec *spec,
101 			 struct bpf_object *obj,
102 			 struct bpf_program *prog)
103 {
104 	int min_log_level = 0;
105 
106 	if (env.verbosity > VERBOSE_NONE)
107 		min_log_level = 1;
108 	if (env.verbosity > VERBOSE_VERY)
109 		min_log_level = 2;
110 
111 	bpf_program__set_log_buf(prog, tester->log_buf, tester->log_buf_sz);
112 
113 	/* Make sure we set at least minimal log level, unless test requirest
114 	 * even higher level already. Make sure to preserve independent log
115 	 * level 4 (verifier stats), though.
116 	 */
117 	if ((spec->log_level & 3) < min_log_level)
118 		bpf_program__set_log_level(prog, (spec->log_level & 4) | min_log_level);
119 	else
120 		bpf_program__set_log_level(prog, spec->log_level);
121 
122 	tester->log_buf[0] = '\0';
123 }
124 
125 static void emit_verifier_log(const char *log_buf, bool force)
126 {
127 	if (!force && env.verbosity == VERBOSE_NONE)
128 		return;
129 	fprintf(stdout, "VERIFIER LOG:\n=============\n%s=============\n", log_buf);
130 }
131 
132 static void validate_case(struct test_loader *tester,
133 			  struct test_spec *spec,
134 			  struct bpf_object *obj,
135 			  struct bpf_program *prog,
136 			  int load_err)
137 {
138 	if (spec->expect_msg) {
139 		char *match;
140 
141 		match = strstr(tester->log_buf, spec->expect_msg);
142 		if (!ASSERT_OK_PTR(match, "expect_msg")) {
143 			/* if we are in verbose mode, we've already emitted log */
144 			if (env.verbosity == VERBOSE_NONE)
145 				emit_verifier_log(tester->log_buf, true /*force*/);
146 			fprintf(stderr, "EXPECTED MSG: '%s'\n", spec->expect_msg);
147 			return;
148 		}
149 	}
150 }
151 
152 /* this function is forced noinline and has short generic name to look better
153  * in test_progs output (in case of a failure)
154  */
155 static noinline
156 void run_subtest(struct test_loader *tester,
157 		 const char *skel_name,
158 		 skel_elf_bytes_fn elf_bytes_factory)
159 {
160 	LIBBPF_OPTS(bpf_object_open_opts, open_opts, .object_name = skel_name);
161 	struct bpf_object *obj = NULL, *tobj;
162 	struct bpf_program *prog, *tprog;
163 	const void *obj_bytes;
164 	size_t obj_byte_cnt;
165 	int err;
166 
167 	if (tester_init(tester) < 0)
168 		return; /* failed to initialize tester */
169 
170 	obj_bytes = elf_bytes_factory(&obj_byte_cnt);
171 	obj = bpf_object__open_mem(obj_bytes, obj_byte_cnt, &open_opts);
172 	if (!ASSERT_OK_PTR(obj, "obj_open_mem"))
173 		return;
174 
175 	bpf_object__for_each_program(prog, obj) {
176 		const char *prog_name = bpf_program__name(prog);
177 		struct test_spec spec;
178 
179 		if (!test__start_subtest(prog_name))
180 			continue;
181 
182 		/* if we can't derive test specification, go to the next test */
183 		err = parse_test_spec(tester, obj, prog, &spec);
184 		if (!ASSERT_OK(err, "parse_test_spec"))
185 			continue;
186 
187 		tobj = bpf_object__open_mem(obj_bytes, obj_byte_cnt, &open_opts);
188 		if (!ASSERT_OK_PTR(tobj, "obj_open_mem")) /* shouldn't happen */
189 			continue;
190 
191 		bpf_object__for_each_program(tprog, tobj)
192 			bpf_program__set_autoload(tprog, false);
193 
194 		bpf_object__for_each_program(tprog, tobj) {
195 			/* only load specified program */
196 			if (strcmp(bpf_program__name(tprog), prog_name) == 0) {
197 				bpf_program__set_autoload(tprog, true);
198 				break;
199 			}
200 		}
201 
202 		prepare_case(tester, &spec, tobj, tprog);
203 
204 		err = bpf_object__load(tobj);
205 		if (spec.expect_failure) {
206 			if (!ASSERT_ERR(err, "unexpected_load_success")) {
207 				emit_verifier_log(tester->log_buf, false /*force*/);
208 				goto tobj_cleanup;
209 			}
210 		} else {
211 			if (!ASSERT_OK(err, "unexpected_load_failure")) {
212 				emit_verifier_log(tester->log_buf, true /*force*/);
213 				goto tobj_cleanup;
214 			}
215 		}
216 
217 		emit_verifier_log(tester->log_buf, false /*force*/);
218 		validate_case(tester, &spec, tobj, tprog, err);
219 
220 tobj_cleanup:
221 		bpf_object__close(tobj);
222 	}
223 
224 	bpf_object__close(obj);
225 }
226 
227 void test_loader__run_subtests(struct test_loader *tester,
228 			       const char *skel_name,
229 			       skel_elf_bytes_fn elf_bytes_factory)
230 {
231 	/* see comment in run_subtest() for why we do this function nesting */
232 	run_subtest(tester, skel_name, elf_bytes_factory);
233 }
234