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