1 // SPDX-License-Identifier: GPL-2.0
2 #include <test_progs.h>
3 #include "progs/core_reloc_types.h"
4 #include "bpf_testmod/bpf_testmod.h"
5 #include <sys/mman.h>
6 #include <sys/syscall.h>
7 #include <bpf/btf.h>
8 
9 static int duration = 0;
10 
11 #define STRUCT_TO_CHAR_PTR(struct_name) (const char *)&(struct struct_name)
12 
13 #define MODULES_CASE(name, sec_name, tp_name) {				\
14 	.case_name = name,						\
15 	.bpf_obj_file = "test_core_reloc_module.o",			\
16 	.btf_src_file = NULL, /* find in kernel module BTFs */		\
17 	.input = "",							\
18 	.input_len = 0,							\
19 	.output = STRUCT_TO_CHAR_PTR(core_reloc_module_output) {	\
20 		.read_ctx_sz = sizeof(struct bpf_testmod_test_read_ctx),\
21 		.read_ctx_exists = true,				\
22 		.buf_exists = true,					\
23 		.len_exists = true,					\
24 		.off_exists = true,					\
25 		.len = 123,						\
26 		.off = 0,						\
27 		.comm = "test_progs",					\
28 		.comm_len = sizeof("test_progs"),			\
29 	},								\
30 	.output_len = sizeof(struct core_reloc_module_output),		\
31 	.prog_sec_name = sec_name,					\
32 	.raw_tp_name = tp_name,						\
33 	.trigger = trigger_module_test_read,				\
34 	.needs_testmod = true,						\
35 }
36 
37 #define FLAVORS_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) {	\
38 	.a = 42,							\
39 	.b = 0xc001,							\
40 	.c = 0xbeef,							\
41 }
42 
43 #define FLAVORS_CASE_COMMON(name)					\
44 	.case_name = #name,						\
45 	.bpf_obj_file = "test_core_reloc_flavors.o",			\
46 	.btf_src_file = "btf__core_reloc_" #name ".o"			\
47 
48 #define FLAVORS_CASE(name) {						\
49 	FLAVORS_CASE_COMMON(name),					\
50 	.input = FLAVORS_DATA(core_reloc_##name),			\
51 	.input_len = sizeof(struct core_reloc_##name),			\
52 	.output = FLAVORS_DATA(core_reloc_flavors),			\
53 	.output_len = sizeof(struct core_reloc_flavors),		\
54 }
55 
56 #define FLAVORS_ERR_CASE(name) {					\
57 	FLAVORS_CASE_COMMON(name),					\
58 	.fails = true,							\
59 }
60 
61 #define NESTING_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) {	\
62 	.a = { .a = { .a = 42 } },					\
63 	.b = { .b = { .b = 0xc001 } },					\
64 }
65 
66 #define NESTING_CASE_COMMON(name)					\
67 	.case_name = #name,						\
68 	.bpf_obj_file = "test_core_reloc_nesting.o",			\
69 	.btf_src_file = "btf__core_reloc_" #name ".o"
70 
71 #define NESTING_CASE(name) {						\
72 	NESTING_CASE_COMMON(name),					\
73 	.input = NESTING_DATA(core_reloc_##name),			\
74 	.input_len = sizeof(struct core_reloc_##name),			\
75 	.output = NESTING_DATA(core_reloc_nesting),			\
76 	.output_len = sizeof(struct core_reloc_nesting)			\
77 }
78 
79 #define NESTING_ERR_CASE(name) {					\
80 	NESTING_CASE_COMMON(name),					\
81 	.fails = true,							\
82 }
83 
84 #define ARRAYS_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) {	\
85 	.a = { [2] = 1 },						\
86 	.b = { [1] = { [2] = { [3] = 2 } } },				\
87 	.c = { [1] = { .c =  3 } },					\
88 	.d = { [0] = { [0] = { .d = 4 } } },				\
89 }
90 
91 #define ARRAYS_CASE_COMMON(name)					\
92 	.case_name = #name,						\
93 	.bpf_obj_file = "test_core_reloc_arrays.o",			\
94 	.btf_src_file = "btf__core_reloc_" #name ".o"
95 
96 #define ARRAYS_CASE(name) {						\
97 	ARRAYS_CASE_COMMON(name),					\
98 	.input = ARRAYS_DATA(core_reloc_##name),			\
99 	.input_len = sizeof(struct core_reloc_##name),			\
100 	.output = STRUCT_TO_CHAR_PTR(core_reloc_arrays_output) {	\
101 		.a2   = 1,						\
102 		.b123 = 2,						\
103 		.c1c  = 3,						\
104 		.d00d = 4,						\
105 		.f10c = 0,						\
106 	},								\
107 	.output_len = sizeof(struct core_reloc_arrays_output)		\
108 }
109 
110 #define ARRAYS_ERR_CASE(name) {						\
111 	ARRAYS_CASE_COMMON(name),					\
112 	.fails = true,							\
113 }
114 
115 #define PRIMITIVES_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) {	\
116 	.a = 1,								\
117 	.b = 2,								\
118 	.c = 3,								\
119 	.d = (void *)4,							\
120 	.f = (void *)5,							\
121 }
122 
123 #define PRIMITIVES_CASE_COMMON(name)					\
124 	.case_name = #name,						\
125 	.bpf_obj_file = "test_core_reloc_primitives.o",			\
126 	.btf_src_file = "btf__core_reloc_" #name ".o"
127 
128 #define PRIMITIVES_CASE(name) {						\
129 	PRIMITIVES_CASE_COMMON(name),					\
130 	.input = PRIMITIVES_DATA(core_reloc_##name),			\
131 	.input_len = sizeof(struct core_reloc_##name),			\
132 	.output = PRIMITIVES_DATA(core_reloc_primitives),		\
133 	.output_len = sizeof(struct core_reloc_primitives),		\
134 }
135 
136 #define PRIMITIVES_ERR_CASE(name) {					\
137 	PRIMITIVES_CASE_COMMON(name),					\
138 	.fails = true,							\
139 }
140 
141 #define MODS_CASE(name) {						\
142 	.case_name = #name,						\
143 	.bpf_obj_file = "test_core_reloc_mods.o",			\
144 	.btf_src_file = "btf__core_reloc_" #name ".o",			\
145 	.input = STRUCT_TO_CHAR_PTR(core_reloc_##name) {		\
146 		.a = 1,							\
147 		.b = 2,							\
148 		.c = (void *)3,						\
149 		.d = (void *)4,						\
150 		.e = { [2] = 5 },					\
151 		.f = { [1] = 6 },					\
152 		.g = { .x = 7 },					\
153 		.h = { .y = 8 },					\
154 	},								\
155 	.input_len = sizeof(struct core_reloc_##name),			\
156 	.output = STRUCT_TO_CHAR_PTR(core_reloc_mods_output) {		\
157 		.a = 1, .b = 2, .c = 3, .d = 4,				\
158 		.e = 5, .f = 6, .g = 7, .h = 8,				\
159 	},								\
160 	.output_len = sizeof(struct core_reloc_mods_output),		\
161 }
162 
163 #define PTR_AS_ARR_CASE(name) {						\
164 	.case_name = #name,						\
165 	.bpf_obj_file = "test_core_reloc_ptr_as_arr.o",			\
166 	.btf_src_file = "btf__core_reloc_" #name ".o",			\
167 	.input = (const char *)&(struct core_reloc_##name []){		\
168 		{ .a = 1 },						\
169 		{ .a = 2 },						\
170 		{ .a = 3 },						\
171 	},								\
172 	.input_len = 3 * sizeof(struct core_reloc_##name),		\
173 	.output = STRUCT_TO_CHAR_PTR(core_reloc_ptr_as_arr) {		\
174 		.a = 3,							\
175 	},								\
176 	.output_len = sizeof(struct core_reloc_ptr_as_arr),		\
177 }
178 
179 #define INTS_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) {	\
180 	.u8_field = 1,							\
181 	.s8_field = 2,							\
182 	.u16_field = 3,							\
183 	.s16_field = 4,							\
184 	.u32_field = 5,							\
185 	.s32_field = 6,							\
186 	.u64_field = 7,							\
187 	.s64_field = 8,							\
188 }
189 
190 #define INTS_CASE_COMMON(name)						\
191 	.case_name = #name,						\
192 	.bpf_obj_file = "test_core_reloc_ints.o",			\
193 	.btf_src_file = "btf__core_reloc_" #name ".o"
194 
195 #define INTS_CASE(name) {						\
196 	INTS_CASE_COMMON(name),						\
197 	.input = INTS_DATA(core_reloc_##name),				\
198 	.input_len = sizeof(struct core_reloc_##name),			\
199 	.output = INTS_DATA(core_reloc_ints),				\
200 	.output_len = sizeof(struct core_reloc_ints),			\
201 }
202 
203 #define INTS_ERR_CASE(name) {						\
204 	INTS_CASE_COMMON(name),						\
205 	.fails = true,							\
206 }
207 
208 #define FIELD_EXISTS_CASE_COMMON(name)					\
209 	.case_name = #name,						\
210 	.bpf_obj_file = "test_core_reloc_existence.o",			\
211 	.btf_src_file = "btf__core_reloc_" #name ".o"			\
212 
213 #define BITFIELDS_CASE_COMMON(objfile, test_name_prefix,  name)		\
214 	.case_name = test_name_prefix#name,				\
215 	.bpf_obj_file = objfile,					\
216 	.btf_src_file = "btf__core_reloc_" #name ".o"
217 
218 #define BITFIELDS_CASE(name, ...) {					\
219 	BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_probed.o",	\
220 			      "probed:", name),				\
221 	.input = STRUCT_TO_CHAR_PTR(core_reloc_##name) __VA_ARGS__,	\
222 	.input_len = sizeof(struct core_reloc_##name),			\
223 	.output = STRUCT_TO_CHAR_PTR(core_reloc_bitfields_output)	\
224 		__VA_ARGS__,						\
225 	.output_len = sizeof(struct core_reloc_bitfields_output),	\
226 }, {									\
227 	BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_direct.o",	\
228 			      "direct:", name),				\
229 	.input = STRUCT_TO_CHAR_PTR(core_reloc_##name) __VA_ARGS__,	\
230 	.input_len = sizeof(struct core_reloc_##name),			\
231 	.output = STRUCT_TO_CHAR_PTR(core_reloc_bitfields_output)	\
232 		__VA_ARGS__,						\
233 	.output_len = sizeof(struct core_reloc_bitfields_output),	\
234 	.prog_sec_name = "tp_btf/sys_enter",				\
235 }
236 
237 
238 #define BITFIELDS_ERR_CASE(name) {					\
239 	BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_probed.o",	\
240 			      "probed:", name),				\
241 	.fails = true,							\
242 }, {									\
243 	BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_direct.o",	\
244 			      "direct:", name),				\
245 	.prog_sec_name = "tp_btf/sys_enter",				\
246 	.fails = true,							\
247 }
248 
249 #define SIZE_CASE_COMMON(name)						\
250 	.case_name = #name,						\
251 	.bpf_obj_file = "test_core_reloc_size.o",			\
252 	.btf_src_file = "btf__core_reloc_" #name ".o",			\
253 	.relaxed_core_relocs = true
254 
255 #define SIZE_OUTPUT_DATA(type)						\
256 	STRUCT_TO_CHAR_PTR(core_reloc_size_output) {			\
257 		.int_sz = sizeof(((type *)0)->int_field),		\
258 		.struct_sz = sizeof(((type *)0)->struct_field),		\
259 		.union_sz = sizeof(((type *)0)->union_field),		\
260 		.arr_sz = sizeof(((type *)0)->arr_field),		\
261 		.arr_elem_sz = sizeof(((type *)0)->arr_field[0]),	\
262 		.ptr_sz = 8, /* always 8-byte pointer for BPF */	\
263 		.enum_sz = sizeof(((type *)0)->enum_field),		\
264 		.float_sz = sizeof(((type *)0)->float_field),		\
265 	}
266 
267 #define SIZE_CASE(name) {						\
268 	SIZE_CASE_COMMON(name),						\
269 	.input_len = 0,							\
270 	.output = SIZE_OUTPUT_DATA(struct core_reloc_##name),		\
271 	.output_len = sizeof(struct core_reloc_size_output),		\
272 }
273 
274 #define SIZE_ERR_CASE(name) {						\
275 	SIZE_CASE_COMMON(name),						\
276 	.fails = true,							\
277 }
278 
279 #define TYPE_BASED_CASE_COMMON(name)					\
280 	.case_name = #name,						\
281 	.bpf_obj_file = "test_core_reloc_type_based.o",		\
282 	.btf_src_file = "btf__core_reloc_" #name ".o"			\
283 
284 #define TYPE_BASED_CASE(name, ...) {					\
285 	TYPE_BASED_CASE_COMMON(name),					\
286 	.output = STRUCT_TO_CHAR_PTR(core_reloc_type_based_output)	\
287 			__VA_ARGS__,					\
288 	.output_len = sizeof(struct core_reloc_type_based_output),	\
289 }
290 
291 #define TYPE_BASED_ERR_CASE(name) {					\
292 	TYPE_BASED_CASE_COMMON(name),					\
293 	.fails = true,							\
294 }
295 
296 #define TYPE_ID_CASE_COMMON(name)					\
297 	.case_name = #name,						\
298 	.bpf_obj_file = "test_core_reloc_type_id.o",			\
299 	.btf_src_file = "btf__core_reloc_" #name ".o"			\
300 
301 #define TYPE_ID_CASE(name, setup_fn) {					\
302 	TYPE_ID_CASE_COMMON(name),					\
303 	.output = STRUCT_TO_CHAR_PTR(core_reloc_type_id_output) {},	\
304 	.output_len = sizeof(struct core_reloc_type_id_output),		\
305 	.setup = setup_fn,						\
306 }
307 
308 #define TYPE_ID_ERR_CASE(name) {					\
309 	TYPE_ID_CASE_COMMON(name),					\
310 	.fails = true,							\
311 }
312 
313 #define ENUMVAL_CASE_COMMON(name)					\
314 	.case_name = #name,						\
315 	.bpf_obj_file = "test_core_reloc_enumval.o",			\
316 	.btf_src_file = "btf__core_reloc_" #name ".o"			\
317 
318 #define ENUMVAL_CASE(name, ...) {					\
319 	ENUMVAL_CASE_COMMON(name),					\
320 	.output = STRUCT_TO_CHAR_PTR(core_reloc_enumval_output)		\
321 			__VA_ARGS__,					\
322 	.output_len = sizeof(struct core_reloc_enumval_output),		\
323 }
324 
325 #define ENUMVAL_ERR_CASE(name) {					\
326 	ENUMVAL_CASE_COMMON(name),					\
327 	.fails = true,							\
328 }
329 
330 struct core_reloc_test_case;
331 
332 typedef int (*setup_test_fn)(struct core_reloc_test_case *test);
333 typedef int (*trigger_test_fn)(const struct core_reloc_test_case *test);
334 
335 struct core_reloc_test_case {
336 	const char *case_name;
337 	const char *bpf_obj_file;
338 	const char *btf_src_file;
339 	const char *input;
340 	int input_len;
341 	const char *output;
342 	int output_len;
343 	bool fails;
344 	bool needs_testmod;
345 	bool relaxed_core_relocs;
346 	const char *prog_sec_name;
347 	const char *raw_tp_name;
348 	setup_test_fn setup;
349 	trigger_test_fn trigger;
350 };
351 
find_btf_type(const struct btf * btf,const char * name,__u32 kind)352 static int find_btf_type(const struct btf *btf, const char *name, __u32 kind)
353 {
354 	int id;
355 
356 	id = btf__find_by_name_kind(btf, name, kind);
357 	if (CHECK(id <= 0, "find_type_id", "failed to find '%s', kind %d: %d\n", name, kind, id))
358 		return -1;
359 
360 	return id;
361 }
362 
setup_type_id_case_local(struct core_reloc_test_case * test)363 static int setup_type_id_case_local(struct core_reloc_test_case *test)
364 {
365 	struct core_reloc_type_id_output *exp = (void *)test->output;
366 	struct btf *local_btf = btf__parse(test->bpf_obj_file, NULL);
367 	struct btf *targ_btf = btf__parse(test->btf_src_file, NULL);
368 	const struct btf_type *t;
369 	const char *name;
370 	int i;
371 
372 	if (CHECK(IS_ERR(local_btf), "local_btf", "failed: %ld\n", PTR_ERR(local_btf)) ||
373 	    CHECK(IS_ERR(targ_btf), "targ_btf", "failed: %ld\n", PTR_ERR(targ_btf))) {
374 		btf__free(local_btf);
375 		btf__free(targ_btf);
376 		return -EINVAL;
377 	}
378 
379 	exp->local_anon_struct = -1;
380 	exp->local_anon_union = -1;
381 	exp->local_anon_enum = -1;
382 	exp->local_anon_func_proto_ptr = -1;
383 	exp->local_anon_void_ptr = -1;
384 	exp->local_anon_arr = -1;
385 
386 	for (i = 1; i <= btf__get_nr_types(local_btf); i++)
387 	{
388 		t = btf__type_by_id(local_btf, i);
389 		/* we are interested only in anonymous types */
390 		if (t->name_off)
391 			continue;
392 
393 		if (btf_is_struct(t) && btf_vlen(t) &&
394 		    (name = btf__name_by_offset(local_btf, btf_members(t)[0].name_off)) &&
395 		    strcmp(name, "marker_field") == 0) {
396 			exp->local_anon_struct = i;
397 		} else if (btf_is_union(t) && btf_vlen(t) &&
398 			 (name = btf__name_by_offset(local_btf, btf_members(t)[0].name_off)) &&
399 			 strcmp(name, "marker_field") == 0) {
400 			exp->local_anon_union = i;
401 		} else if (btf_is_enum(t) && btf_vlen(t) &&
402 			 (name = btf__name_by_offset(local_btf, btf_enum(t)[0].name_off)) &&
403 			 strcmp(name, "MARKER_ENUM_VAL") == 0) {
404 			exp->local_anon_enum = i;
405 		} else if (btf_is_ptr(t) && (t = btf__type_by_id(local_btf, t->type))) {
406 			if (btf_is_func_proto(t) && (t = btf__type_by_id(local_btf, t->type)) &&
407 			    btf_is_int(t) && (name = btf__name_by_offset(local_btf, t->name_off)) &&
408 			    strcmp(name, "_Bool") == 0) {
409 				/* ptr -> func_proto -> _Bool */
410 				exp->local_anon_func_proto_ptr = i;
411 			} else if (btf_is_void(t)) {
412 				/* ptr -> void */
413 				exp->local_anon_void_ptr = i;
414 			}
415 		} else if (btf_is_array(t) && (t = btf__type_by_id(local_btf, btf_array(t)->type)) &&
416 			   btf_is_int(t) && (name = btf__name_by_offset(local_btf, t->name_off)) &&
417 			   strcmp(name, "_Bool") == 0) {
418 			/* _Bool[] */
419 			exp->local_anon_arr = i;
420 		}
421 	}
422 
423 	exp->local_struct = find_btf_type(local_btf, "a_struct", BTF_KIND_STRUCT);
424 	exp->local_union = find_btf_type(local_btf, "a_union", BTF_KIND_UNION);
425 	exp->local_enum = find_btf_type(local_btf, "an_enum", BTF_KIND_ENUM);
426 	exp->local_int = find_btf_type(local_btf, "int", BTF_KIND_INT);
427 	exp->local_struct_typedef = find_btf_type(local_btf, "named_struct_typedef", BTF_KIND_TYPEDEF);
428 	exp->local_func_proto_typedef = find_btf_type(local_btf, "func_proto_typedef", BTF_KIND_TYPEDEF);
429 	exp->local_arr_typedef = find_btf_type(local_btf, "arr_typedef", BTF_KIND_TYPEDEF);
430 
431 	btf__free(local_btf);
432 	btf__free(targ_btf);
433 	return 0;
434 }
435 
setup_type_id_case_success(struct core_reloc_test_case * test)436 static int setup_type_id_case_success(struct core_reloc_test_case *test) {
437 	struct core_reloc_type_id_output *exp = (void *)test->output;
438 	struct btf *targ_btf = btf__parse(test->btf_src_file, NULL);
439 	int err;
440 
441 	err = setup_type_id_case_local(test);
442 	if (err)
443 		return err;
444 
445 	targ_btf = btf__parse(test->btf_src_file, NULL);
446 
447 	exp->targ_struct = find_btf_type(targ_btf, "a_struct", BTF_KIND_STRUCT);
448 	exp->targ_union = find_btf_type(targ_btf, "a_union", BTF_KIND_UNION);
449 	exp->targ_enum = find_btf_type(targ_btf, "an_enum", BTF_KIND_ENUM);
450 	exp->targ_int = find_btf_type(targ_btf, "int", BTF_KIND_INT);
451 	exp->targ_struct_typedef = find_btf_type(targ_btf, "named_struct_typedef", BTF_KIND_TYPEDEF);
452 	exp->targ_func_proto_typedef = find_btf_type(targ_btf, "func_proto_typedef", BTF_KIND_TYPEDEF);
453 	exp->targ_arr_typedef = find_btf_type(targ_btf, "arr_typedef", BTF_KIND_TYPEDEF);
454 
455 	btf__free(targ_btf);
456 	return 0;
457 }
458 
setup_type_id_case_failure(struct core_reloc_test_case * test)459 static int setup_type_id_case_failure(struct core_reloc_test_case *test)
460 {
461 	struct core_reloc_type_id_output *exp = (void *)test->output;
462 	int err;
463 
464 	err = setup_type_id_case_local(test);
465 	if (err)
466 		return err;
467 
468 	exp->targ_struct = 0;
469 	exp->targ_union = 0;
470 	exp->targ_enum = 0;
471 	exp->targ_int = 0;
472 	exp->targ_struct_typedef = 0;
473 	exp->targ_func_proto_typedef = 0;
474 	exp->targ_arr_typedef = 0;
475 
476 	return 0;
477 }
478 
trigger_module_test_read(const struct core_reloc_test_case * test)479 static int trigger_module_test_read(const struct core_reloc_test_case *test)
480 {
481 	struct core_reloc_module_output *exp = (void *)test->output;
482 	int fd, err;
483 
484 	fd = open("/sys/kernel/bpf_testmod", O_RDONLY);
485 	err = -errno;
486 	if (CHECK(fd < 0, "testmod_file_open", "failed: %d\n", err))
487 		return err;
488 
489 	read(fd, NULL, exp->len); /* request expected number of bytes */
490 	close(fd);
491 
492 	return 0;
493 }
494 
495 
496 static struct core_reloc_test_case test_cases[] = {
497 	/* validate we can find kernel image and use its BTF for relocs */
498 	{
499 		.case_name = "kernel",
500 		.bpf_obj_file = "test_core_reloc_kernel.o",
501 		.btf_src_file = NULL, /* load from /lib/modules/$(uname -r) */
502 		.input = "",
503 		.input_len = 0,
504 		.output = STRUCT_TO_CHAR_PTR(core_reloc_kernel_output) {
505 			.valid = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, },
506 			.comm = "test_progs",
507 			.comm_len = sizeof("test_progs"),
508 		},
509 		.output_len = sizeof(struct core_reloc_kernel_output),
510 	},
511 
512 	/* validate we can find kernel module BTF types for relocs/attach */
513 	MODULES_CASE("module_probed", "raw_tp/bpf_testmod_test_read", "bpf_testmod_test_read"),
514 	MODULES_CASE("module_direct", "tp_btf/bpf_testmod_test_read", NULL),
515 
516 	/* validate BPF program can use multiple flavors to match against
517 	 * single target BTF type
518 	 */
519 	FLAVORS_CASE(flavors),
520 
521 	FLAVORS_ERR_CASE(flavors__err_wrong_name),
522 
523 	/* various struct/enum nesting and resolution scenarios */
524 	NESTING_CASE(nesting),
525 	NESTING_CASE(nesting___anon_embed),
526 	NESTING_CASE(nesting___struct_union_mixup),
527 	NESTING_CASE(nesting___extra_nesting),
528 	NESTING_CASE(nesting___dup_compat_types),
529 
530 	NESTING_ERR_CASE(nesting___err_missing_field),
531 	NESTING_ERR_CASE(nesting___err_array_field),
532 	NESTING_ERR_CASE(nesting___err_missing_container),
533 	NESTING_ERR_CASE(nesting___err_nonstruct_container),
534 	NESTING_ERR_CASE(nesting___err_array_container),
535 	NESTING_ERR_CASE(nesting___err_dup_incompat_types),
536 	NESTING_ERR_CASE(nesting___err_partial_match_dups),
537 	NESTING_ERR_CASE(nesting___err_too_deep),
538 
539 	/* various array access relocation scenarios */
540 	ARRAYS_CASE(arrays),
541 	ARRAYS_CASE(arrays___diff_arr_dim),
542 	ARRAYS_CASE(arrays___diff_arr_val_sz),
543 	ARRAYS_CASE(arrays___equiv_zero_sz_arr),
544 	ARRAYS_CASE(arrays___fixed_arr),
545 
546 	ARRAYS_ERR_CASE(arrays___err_too_small),
547 	ARRAYS_ERR_CASE(arrays___err_too_shallow),
548 	ARRAYS_ERR_CASE(arrays___err_non_array),
549 	ARRAYS_ERR_CASE(arrays___err_wrong_val_type),
550 	ARRAYS_ERR_CASE(arrays___err_bad_zero_sz_arr),
551 
552 	/* enum/ptr/int handling scenarios */
553 	PRIMITIVES_CASE(primitives),
554 	PRIMITIVES_CASE(primitives___diff_enum_def),
555 	PRIMITIVES_CASE(primitives___diff_func_proto),
556 	PRIMITIVES_CASE(primitives___diff_ptr_type),
557 
558 	PRIMITIVES_ERR_CASE(primitives___err_non_enum),
559 	PRIMITIVES_ERR_CASE(primitives___err_non_int),
560 	PRIMITIVES_ERR_CASE(primitives___err_non_ptr),
561 
562 	/* const/volatile/restrict and typedefs scenarios */
563 	MODS_CASE(mods),
564 	MODS_CASE(mods___mod_swap),
565 	MODS_CASE(mods___typedefs),
566 
567 	/* handling "ptr is an array" semantics */
568 	PTR_AS_ARR_CASE(ptr_as_arr),
569 	PTR_AS_ARR_CASE(ptr_as_arr___diff_sz),
570 
571 	/* int signedness/sizing/bitfield handling */
572 	INTS_CASE(ints),
573 	INTS_CASE(ints___bool),
574 	INTS_CASE(ints___reverse_sign),
575 
576 	/* validate edge cases of capturing relocations */
577 	{
578 		.case_name = "misc",
579 		.bpf_obj_file = "test_core_reloc_misc.o",
580 		.btf_src_file = "btf__core_reloc_misc.o",
581 		.input = (const char *)&(struct core_reloc_misc_extensible[]){
582 			{ .a = 1 },
583 			{ .a = 2 }, /* not read */
584 			{ .a = 3 },
585 		},
586 		.input_len = 4 * sizeof(int),
587 		.output = STRUCT_TO_CHAR_PTR(core_reloc_misc_output) {
588 			.a = 1,
589 			.b = 1,
590 			.c = 0, /* BUG in clang, should be 3 */
591 		},
592 		.output_len = sizeof(struct core_reloc_misc_output),
593 	},
594 
595 	/* validate field existence checks */
596 	{
597 		FIELD_EXISTS_CASE_COMMON(existence),
598 		.input = STRUCT_TO_CHAR_PTR(core_reloc_existence) {
599 			.a = 1,
600 			.b = 2,
601 			.c = 3,
602 			.arr = { 4 },
603 			.s = { .x = 5 },
604 		},
605 		.input_len = sizeof(struct core_reloc_existence),
606 		.output = STRUCT_TO_CHAR_PTR(core_reloc_existence_output) {
607 			.a_exists = 1,
608 			.b_exists = 1,
609 			.c_exists = 1,
610 			.arr_exists = 1,
611 			.s_exists = 1,
612 			.a_value = 1,
613 			.b_value = 2,
614 			.c_value = 3,
615 			.arr_value = 4,
616 			.s_value = 5,
617 		},
618 		.output_len = sizeof(struct core_reloc_existence_output),
619 	},
620 	{
621 		FIELD_EXISTS_CASE_COMMON(existence___minimal),
622 		.input = STRUCT_TO_CHAR_PTR(core_reloc_existence___minimal) {
623 			.a = 42,
624 		},
625 		.input_len = sizeof(struct core_reloc_existence___minimal),
626 		.output = STRUCT_TO_CHAR_PTR(core_reloc_existence_output) {
627 			.a_exists = 1,
628 			.b_exists = 0,
629 			.c_exists = 0,
630 			.arr_exists = 0,
631 			.s_exists = 0,
632 			.a_value = 42,
633 			.b_value = 0xff000002u,
634 			.c_value = 0xff000003u,
635 			.arr_value = 0xff000004u,
636 			.s_value = 0xff000005u,
637 		},
638 		.output_len = sizeof(struct core_reloc_existence_output),
639 	},
640 	{
641 		FIELD_EXISTS_CASE_COMMON(existence___wrong_field_defs),
642 		.input = STRUCT_TO_CHAR_PTR(core_reloc_existence___wrong_field_defs) {
643 		},
644 		.input_len = sizeof(struct core_reloc_existence___wrong_field_defs),
645 		.output = STRUCT_TO_CHAR_PTR(core_reloc_existence_output) {
646 			.a_exists = 0,
647 			.b_exists = 0,
648 			.c_exists = 0,
649 			.arr_exists = 0,
650 			.s_exists = 0,
651 			.a_value = 0xff000001u,
652 			.b_value = 0xff000002u,
653 			.c_value = 0xff000003u,
654 			.arr_value = 0xff000004u,
655 			.s_value = 0xff000005u,
656 		},
657 		.output_len = sizeof(struct core_reloc_existence_output),
658 	},
659 
660 	/* bitfield relocation checks */
661 	BITFIELDS_CASE(bitfields, {
662 		.ub1 = 1,
663 		.ub2 = 2,
664 		.ub7 = 96,
665 		.sb4 = -7,
666 		.sb20 = -0x76543,
667 		.u32 = 0x80000000,
668 		.s32 = -0x76543210,
669 	}),
670 	BITFIELDS_CASE(bitfields___bit_sz_change, {
671 		.ub1 = 6,
672 		.ub2 = 0xABCDE,
673 		.ub7 = 1,
674 		.sb4 = -1,
675 		.sb20 = -0x17654321,
676 		.u32 = 0xBEEF,
677 		.s32 = -0x3FEDCBA987654321LL,
678 	}),
679 	BITFIELDS_CASE(bitfields___bitfield_vs_int, {
680 		.ub1 = 0xFEDCBA9876543210LL,
681 		.ub2 = 0xA6,
682 		.ub7 = -0x7EDCBA987654321LL,
683 		.sb4 = -0x6123456789ABCDELL,
684 		.sb20 = 0xD00DLL,
685 		.u32 = -0x76543,
686 		.s32 = 0x0ADEADBEEFBADB0BLL,
687 	}),
688 	BITFIELDS_CASE(bitfields___just_big_enough, {
689 		.ub1 = 0xFLL,
690 		.ub2 = 0x0812345678FEDCBALL,
691 	}),
692 	BITFIELDS_ERR_CASE(bitfields___err_too_big_bitfield),
693 
694 	/* size relocation checks */
695 	SIZE_CASE(size),
696 	SIZE_CASE(size___diff_sz),
697 	SIZE_ERR_CASE(size___err_ambiguous),
698 
699 	/* validate type existence and size relocations */
700 	TYPE_BASED_CASE(type_based, {
701 		.struct_exists = 1,
702 		.union_exists = 1,
703 		.enum_exists = 1,
704 		.typedef_named_struct_exists = 1,
705 		.typedef_anon_struct_exists = 1,
706 		.typedef_struct_ptr_exists = 1,
707 		.typedef_int_exists = 1,
708 		.typedef_enum_exists = 1,
709 		.typedef_void_ptr_exists = 1,
710 		.typedef_func_proto_exists = 1,
711 		.typedef_arr_exists = 1,
712 		.struct_sz = sizeof(struct a_struct),
713 		.union_sz = sizeof(union a_union),
714 		.enum_sz = sizeof(enum an_enum),
715 		.typedef_named_struct_sz = sizeof(named_struct_typedef),
716 		.typedef_anon_struct_sz = sizeof(anon_struct_typedef),
717 		.typedef_struct_ptr_sz = sizeof(struct_ptr_typedef),
718 		.typedef_int_sz = sizeof(int_typedef),
719 		.typedef_enum_sz = sizeof(enum_typedef),
720 		.typedef_void_ptr_sz = sizeof(void_ptr_typedef),
721 		.typedef_func_proto_sz = sizeof(func_proto_typedef),
722 		.typedef_arr_sz = sizeof(arr_typedef),
723 	}),
724 	TYPE_BASED_CASE(type_based___all_missing, {
725 		/* all zeros */
726 	}),
727 	TYPE_BASED_CASE(type_based___diff_sz, {
728 		.struct_exists = 1,
729 		.union_exists = 1,
730 		.enum_exists = 1,
731 		.typedef_named_struct_exists = 1,
732 		.typedef_anon_struct_exists = 1,
733 		.typedef_struct_ptr_exists = 1,
734 		.typedef_int_exists = 1,
735 		.typedef_enum_exists = 1,
736 		.typedef_void_ptr_exists = 1,
737 		.typedef_func_proto_exists = 1,
738 		.typedef_arr_exists = 1,
739 		.struct_sz = sizeof(struct a_struct___diff_sz),
740 		.union_sz = sizeof(union a_union___diff_sz),
741 		.enum_sz = sizeof(enum an_enum___diff_sz),
742 		.typedef_named_struct_sz = sizeof(named_struct_typedef___diff_sz),
743 		.typedef_anon_struct_sz = sizeof(anon_struct_typedef___diff_sz),
744 		.typedef_struct_ptr_sz = sizeof(struct_ptr_typedef___diff_sz),
745 		.typedef_int_sz = sizeof(int_typedef___diff_sz),
746 		.typedef_enum_sz = sizeof(enum_typedef___diff_sz),
747 		.typedef_void_ptr_sz = sizeof(void_ptr_typedef___diff_sz),
748 		.typedef_func_proto_sz = sizeof(func_proto_typedef___diff_sz),
749 		.typedef_arr_sz = sizeof(arr_typedef___diff_sz),
750 	}),
751 	TYPE_BASED_CASE(type_based___incompat, {
752 		.enum_exists = 1,
753 		.enum_sz = sizeof(enum an_enum),
754 	}),
755 	TYPE_BASED_CASE(type_based___fn_wrong_args, {
756 		.struct_exists = 1,
757 		.struct_sz = sizeof(struct a_struct),
758 	}),
759 
760 	/* BTF_TYPE_ID_LOCAL/BTF_TYPE_ID_TARGET tests */
761 	TYPE_ID_CASE(type_id, setup_type_id_case_success),
762 	TYPE_ID_CASE(type_id___missing_targets, setup_type_id_case_failure),
763 
764 	/* Enumerator value existence and value relocations */
765 	ENUMVAL_CASE(enumval, {
766 		.named_val1_exists = true,
767 		.named_val2_exists = true,
768 		.named_val3_exists = true,
769 		.anon_val1_exists = true,
770 		.anon_val2_exists = true,
771 		.anon_val3_exists = true,
772 		.named_val1 = 1,
773 		.named_val2 = 2,
774 		.anon_val1 = 0x10,
775 		.anon_val2 = 0x20,
776 	}),
777 	ENUMVAL_CASE(enumval___diff, {
778 		.named_val1_exists = true,
779 		.named_val2_exists = true,
780 		.named_val3_exists = true,
781 		.anon_val1_exists = true,
782 		.anon_val2_exists = true,
783 		.anon_val3_exists = true,
784 		.named_val1 = 101,
785 		.named_val2 = 202,
786 		.anon_val1 = 0x11,
787 		.anon_val2 = 0x22,
788 	}),
789 	ENUMVAL_CASE(enumval___val3_missing, {
790 		.named_val1_exists = true,
791 		.named_val2_exists = true,
792 		.named_val3_exists = false,
793 		.anon_val1_exists = true,
794 		.anon_val2_exists = true,
795 		.anon_val3_exists = false,
796 		.named_val1 = 111,
797 		.named_val2 = 222,
798 		.anon_val1 = 0x111,
799 		.anon_val2 = 0x222,
800 	}),
801 	ENUMVAL_ERR_CASE(enumval___err_missing),
802 };
803 
804 struct data {
805 	char in[256];
806 	char out[256];
807 	bool skip;
808 	uint64_t my_pid_tgid;
809 };
810 
roundup_page(size_t sz)811 static size_t roundup_page(size_t sz)
812 {
813 	long page_size = sysconf(_SC_PAGE_SIZE);
814 	return (sz + page_size - 1) / page_size * page_size;
815 }
816 
test_core_reloc(void)817 void test_core_reloc(void)
818 {
819 	const size_t mmap_sz = roundup_page(sizeof(struct data));
820 	struct bpf_object_load_attr load_attr = {};
821 	struct core_reloc_test_case *test_case;
822 	const char *tp_name, *probe_name;
823 	int err, i, equal;
824 	struct bpf_link *link = NULL;
825 	struct bpf_map *data_map;
826 	struct bpf_program *prog;
827 	struct bpf_object *obj;
828 	uint64_t my_pid_tgid;
829 	struct data *data;
830 	void *mmap_data = NULL;
831 
832 	my_pid_tgid = getpid() | ((uint64_t)syscall(SYS_gettid) << 32);
833 
834 	for (i = 0; i < ARRAY_SIZE(test_cases); i++) {
835 		test_case = &test_cases[i];
836 		if (!test__start_subtest(test_case->case_name))
837 			continue;
838 
839 		if (test_case->needs_testmod && !env.has_testmod) {
840 			test__skip();
841 			continue;
842 		}
843 
844 		if (test_case->setup) {
845 			err = test_case->setup(test_case);
846 			if (CHECK(err, "test_setup", "test #%d setup failed: %d\n", i, err))
847 				continue;
848 		}
849 
850 		obj = bpf_object__open_file(test_case->bpf_obj_file, NULL);
851 		if (CHECK(IS_ERR(obj), "obj_open", "failed to open '%s': %ld\n",
852 			  test_case->bpf_obj_file, PTR_ERR(obj)))
853 			continue;
854 
855 		probe_name = "raw_tracepoint/sys_enter";
856 		tp_name = "sys_enter";
857 		if (test_case->prog_sec_name) {
858 			probe_name = test_case->prog_sec_name;
859 			tp_name = test_case->raw_tp_name; /* NULL for tp_btf */
860 		}
861 
862 		prog = bpf_object__find_program_by_title(obj, probe_name);
863 		if (CHECK(!prog, "find_probe",
864 			  "prog '%s' not found\n", probe_name))
865 			goto cleanup;
866 
867 
868 		if (test_case->btf_src_file) {
869 			err = access(test_case->btf_src_file, R_OK);
870 			if (!ASSERT_OK(err, "btf_src_file"))
871 				goto cleanup;
872 		}
873 
874 		load_attr.obj = obj;
875 		load_attr.log_level = 0;
876 		load_attr.target_btf_path = test_case->btf_src_file;
877 		err = bpf_object__load_xattr(&load_attr);
878 		if (err) {
879 			if (!test_case->fails)
880 				ASSERT_OK(err, "obj_load");
881 			goto cleanup;
882 		}
883 
884 		data_map = bpf_object__find_map_by_name(obj, "test_cor.bss");
885 		if (CHECK(!data_map, "find_data_map", "data map not found\n"))
886 			goto cleanup;
887 
888 		mmap_data = mmap(NULL, mmap_sz, PROT_READ | PROT_WRITE,
889 				 MAP_SHARED, bpf_map__fd(data_map), 0);
890 		if (CHECK(mmap_data == MAP_FAILED, "mmap",
891 			  ".bss mmap failed: %d", errno)) {
892 			mmap_data = NULL;
893 			goto cleanup;
894 		}
895 		data = mmap_data;
896 
897 		memset(mmap_data, 0, sizeof(*data));
898 		memcpy(data->in, test_case->input, test_case->input_len);
899 		data->my_pid_tgid = my_pid_tgid;
900 
901 		link = bpf_program__attach_raw_tracepoint(prog, tp_name);
902 		if (CHECK(IS_ERR(link), "attach_raw_tp", "err %ld\n",
903 			  PTR_ERR(link)))
904 			goto cleanup;
905 
906 		/* trigger test run */
907 		if (test_case->trigger) {
908 			if (!ASSERT_OK(test_case->trigger(test_case), "test_trigger"))
909 				goto cleanup;
910 		} else {
911 			usleep(1);
912 		}
913 
914 		if (data->skip) {
915 			test__skip();
916 			goto cleanup;
917 		}
918 
919 		if (!ASSERT_FALSE(test_case->fails, "obj_load_should_fail"))
920 			goto cleanup;
921 
922 		equal = memcmp(data->out, test_case->output,
923 			       test_case->output_len) == 0;
924 		if (CHECK(!equal, "check_result",
925 			  "input/output data don't match\n")) {
926 			int j;
927 
928 			for (j = 0; j < test_case->input_len; j++) {
929 				printf("input byte #%d: 0x%02hhx\n",
930 				       j, test_case->input[j]);
931 			}
932 			for (j = 0; j < test_case->output_len; j++) {
933 				printf("output byte #%d: EXP 0x%02hhx GOT 0x%02hhx\n",
934 				       j, test_case->output[j], data->out[j]);
935 			}
936 			goto cleanup;
937 		}
938 
939 cleanup:
940 		if (mmap_data) {
941 			CHECK_FAIL(munmap(mmap_data, mmap_sz));
942 			mmap_data = NULL;
943 		}
944 		if (!IS_ERR_OR_NULL(link)) {
945 			bpf_link__destroy(link);
946 			link = NULL;
947 		}
948 		bpf_object__close(obj);
949 	}
950 }
951