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