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.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.o", \ 47 .btf_src_file = "btf__core_reloc_" #name ".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.o", \ 72 .btf_src_file = "btf__core_reloc_" #name ".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.o", \ 100 .btf_src_file = "btf__core_reloc_" #name ".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.o", \ 134 .btf_src_file = "btf__core_reloc_" #name ".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.o", \ 154 .btf_src_file = "btf__core_reloc_" #name ".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.o", \ 178 .btf_src_file = "btf__core_reloc_" #name ".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.o", \ 207 .btf_src_file = "btf__core_reloc_" #name ".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.o", \ 227 .btf_src_file = "btf__core_reloc_" #name ".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 ".o" 235 236 #define BITFIELDS_CASE(name, ...) { \ 237 BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_probed.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.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.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.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.o", \ 276 .btf_src_file = "btf__core_reloc_" #name ".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.o", \ 316 .btf_src_file = "btf__core_reloc_" #name ".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.o", \ 335 .btf_src_file = "btf__core_reloc_" #name ".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.o", \ 354 .btf_src_file = "btf__core_reloc_" #name ".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.o", \ 373 .btf_src_file = "btf__core_reloc_" #name ".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 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 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 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 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 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.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.o", 633 .btf_src_file = "btf__core_reloc_misc.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 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 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 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 1147 void test_core_reloc(void) 1148 { 1149 run_core_reloc_tests(false); 1150 } 1151 1152 void test_core_reloc_btfgen(void) 1153 { 1154 run_core_reloc_tests(true); 1155 } 1156