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