Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftest/bpf: Add relocatable bitfield reading tests

Add a bunch of selftests verifying correctness of relocatable bitfield reading
support in libbpf. Both bpf_probe_read()-based and direct read-based bitfield
macros are tested. core_reloc.c "test_harness" is extended to support raw
tracepoint and new typed raw tracepoints as test BPF program types.

Signed-off-by: Andrii Nakryiko <andriin@fb.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Link: https://lore.kernel.org/bpf/20191101222810.1246166-5-andriin@fb.com

authored by

Andrii Nakryiko and committed by
Daniel Borkmann
8b1cb1c9 94f060e9

+294 -2
+82 -2
tools/testing/selftests/bpf/prog_tests/core_reloc.c
··· 189 189 .fails = true, \ 190 190 } 191 191 192 + #define BITFIELDS_CASE_COMMON(objfile, test_name_prefix, name) \ 193 + .case_name = test_name_prefix#name, \ 194 + .bpf_obj_file = objfile, \ 195 + .btf_src_file = "btf__core_reloc_" #name ".o" 196 + 197 + #define BITFIELDS_CASE(name, ...) { \ 198 + BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_probed.o", \ 199 + "direct:", name), \ 200 + .input = STRUCT_TO_CHAR_PTR(core_reloc_##name) __VA_ARGS__, \ 201 + .input_len = sizeof(struct core_reloc_##name), \ 202 + .output = STRUCT_TO_CHAR_PTR(core_reloc_bitfields_output) \ 203 + __VA_ARGS__, \ 204 + .output_len = sizeof(struct core_reloc_bitfields_output), \ 205 + }, { \ 206 + BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_direct.o", \ 207 + "probed:", name), \ 208 + .input = STRUCT_TO_CHAR_PTR(core_reloc_##name) __VA_ARGS__, \ 209 + .input_len = sizeof(struct core_reloc_##name), \ 210 + .output = STRUCT_TO_CHAR_PTR(core_reloc_bitfields_output) \ 211 + __VA_ARGS__, \ 212 + .output_len = sizeof(struct core_reloc_bitfields_output), \ 213 + .direct_raw_tp = true, \ 214 + } 215 + 216 + 217 + #define BITFIELDS_ERR_CASE(name) { \ 218 + BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_probed.o", \ 219 + "probed:", name), \ 220 + .fails = true, \ 221 + }, { \ 222 + BITFIELDS_CASE_COMMON("test_core_reloc_bitfields_direct.o", \ 223 + "direct:", name), \ 224 + .direct_raw_tp = true, \ 225 + .fails = true, \ 226 + } 227 + 192 228 struct core_reloc_test_case { 193 229 const char *case_name; 194 230 const char *bpf_obj_file; ··· 235 199 int output_len; 236 200 bool fails; 237 201 bool relaxed_core_relocs; 202 + bool direct_raw_tp; 238 203 }; 239 204 240 205 static struct core_reloc_test_case test_cases[] = { ··· 389 352 EXISTENCE_ERR_CASE(existence__err_arr_kind), 390 353 EXISTENCE_ERR_CASE(existence__err_arr_value_type), 391 354 EXISTENCE_ERR_CASE(existence__err_struct_type), 355 + 356 + /* bitfield relocation checks */ 357 + BITFIELDS_CASE(bitfields, { 358 + .ub1 = 1, 359 + .ub2 = 2, 360 + .ub7 = 96, 361 + .sb4 = -7, 362 + .sb20 = -0x76543, 363 + .u32 = 0x80000000, 364 + .s32 = -0x76543210, 365 + }), 366 + BITFIELDS_CASE(bitfields___bit_sz_change, { 367 + .ub1 = 6, 368 + .ub2 = 0xABCDE, 369 + .ub7 = 1, 370 + .sb4 = -1, 371 + .sb20 = -0x17654321, 372 + .u32 = 0xBEEF, 373 + .s32 = -0x3FEDCBA987654321, 374 + }), 375 + BITFIELDS_CASE(bitfields___bitfield_vs_int, { 376 + .ub1 = 0xFEDCBA9876543210, 377 + .ub2 = 0xA6, 378 + .ub7 = -0x7EDCBA987654321, 379 + .sb4 = -0x6123456789ABCDE, 380 + .sb20 = 0xD00D, 381 + .u32 = -0x76543, 382 + .s32 = 0x0ADEADBEEFBADB0B, 383 + }), 384 + BITFIELDS_CASE(bitfields___just_big_enough, { 385 + .ub1 = 0xF, 386 + .ub2 = 0x0812345678FEDCBA, 387 + }), 388 + BITFIELDS_ERR_CASE(bitfields___err_too_big_bitfield), 392 389 }; 393 390 394 391 struct data { ··· 432 361 433 362 void test_core_reloc(void) 434 363 { 435 - const char *probe_name = "raw_tracepoint/sys_enter"; 436 364 struct bpf_object_load_attr load_attr = {}; 437 365 struct core_reloc_test_case *test_case; 366 + const char *tp_name, *probe_name; 438 367 int err, duration = 0, i, equal; 439 368 struct bpf_link *link = NULL; 440 369 struct bpf_map *data_map; ··· 458 387 test_case->bpf_obj_file, PTR_ERR(obj))) 459 388 continue; 460 389 390 + /* for typed raw tracepoints, NULL should be specified */ 391 + if (test_case->direct_raw_tp) { 392 + probe_name = "tp_btf/sys_enter"; 393 + tp_name = NULL; 394 + } else { 395 + probe_name = "raw_tracepoint/sys_enter"; 396 + tp_name = "sys_enter"; 397 + } 398 + 461 399 prog = bpf_object__find_program_by_title(obj, probe_name); 462 400 if (CHECK(!prog, "find_probe", 463 401 "prog '%s' not found\n", probe_name)) ··· 487 407 goto cleanup; 488 408 } 489 409 490 - link = bpf_program__attach_raw_tracepoint(prog, "sys_enter"); 410 + link = bpf_program__attach_raw_tracepoint(prog, tp_name); 491 411 if (CHECK(IS_ERR(link), "attach_raw_tp", "err %ld\n", 492 412 PTR_ERR(link))) 493 413 goto cleanup;
+3
tools/testing/selftests/bpf/progs/btf__core_reloc_bitfields.c
··· 1 + #include "core_reloc_types.h" 2 + 3 + void f(struct core_reloc_bitfields x) {}
+3
tools/testing/selftests/bpf/progs/btf__core_reloc_bitfields___bit_sz_change.c
··· 1 + #include "core_reloc_types.h" 2 + 3 + void f(struct core_reloc_bitfields___bit_sz_change x) {}
+3
tools/testing/selftests/bpf/progs/btf__core_reloc_bitfields___bitfield_vs_int.c
··· 1 + #include "core_reloc_types.h" 2 + 3 + void f(struct core_reloc_bitfields___bitfield_vs_int x) {}
+3
tools/testing/selftests/bpf/progs/btf__core_reloc_bitfields___err_too_big_bitfield.c
··· 1 + #include "core_reloc_types.h" 2 + 3 + void f(struct core_reloc_bitfields___err_too_big_bitfield x) {}
+3
tools/testing/selftests/bpf/progs/btf__core_reloc_bitfields___just_big_enough.c
··· 1 + #include "core_reloc_types.h" 2 + 3 + void f(struct core_reloc_bitfields___just_big_enough x) {}
+72
tools/testing/selftests/bpf/progs/core_reloc_types.h
··· 662 662 struct core_reloc_existence___err_wrong_struct_type { 663 663 int s; 664 664 }; 665 + 666 + /* 667 + * BITFIELDS 668 + */ 669 + /* bitfield read results, all as plain integers */ 670 + struct core_reloc_bitfields_output { 671 + int64_t ub1; 672 + int64_t ub2; 673 + int64_t ub7; 674 + int64_t sb4; 675 + int64_t sb20; 676 + int64_t u32; 677 + int64_t s32; 678 + }; 679 + 680 + struct core_reloc_bitfields { 681 + /* unsigned bitfields */ 682 + uint8_t ub1: 1; 683 + uint8_t ub2: 2; 684 + uint32_t ub7: 7; 685 + /* signed bitfields */ 686 + int8_t sb4: 4; 687 + int32_t sb20: 20; 688 + /* non-bitfields */ 689 + uint32_t u32; 690 + int32_t s32; 691 + }; 692 + 693 + /* different bit sizes (both up and down) */ 694 + struct core_reloc_bitfields___bit_sz_change { 695 + /* unsigned bitfields */ 696 + uint16_t ub1: 3; /* 1 -> 3 */ 697 + uint32_t ub2: 20; /* 2 -> 20 */ 698 + uint8_t ub7: 1; /* 7 -> 1 */ 699 + /* signed bitfields */ 700 + int8_t sb4: 1; /* 4 -> 1 */ 701 + int32_t sb20: 30; /* 20 -> 30 */ 702 + /* non-bitfields */ 703 + uint16_t u32; /* 32 -> 16 */ 704 + int64_t s32; /* 32 -> 64 */ 705 + }; 706 + 707 + /* turn bitfield into non-bitfield and vice versa */ 708 + struct core_reloc_bitfields___bitfield_vs_int { 709 + uint64_t ub1; /* 3 -> 64 non-bitfield */ 710 + uint8_t ub2; /* 20 -> 8 non-bitfield */ 711 + int64_t ub7; /* 7 -> 64 non-bitfield signed */ 712 + int64_t sb4; /* 4 -> 64 non-bitfield signed */ 713 + uint64_t sb20; /* 20 -> 16 non-bitfield unsigned */ 714 + int32_t u32: 20; /* 32 non-bitfield -> 20 bitfield */ 715 + uint64_t s32: 60; /* 32 non-bitfield -> 60 bitfield */ 716 + }; 717 + 718 + struct core_reloc_bitfields___just_big_enough { 719 + uint64_t ub1: 4; 720 + uint64_t ub2: 60; /* packed tightly */ 721 + uint32_t ub7; 722 + uint32_t sb4; 723 + uint32_t sb20; 724 + uint32_t u32; 725 + uint32_t s32; 726 + } __attribute__((packed)) ; 727 + 728 + struct core_reloc_bitfields___err_too_big_bitfield { 729 + uint64_t ub1: 4; 730 + uint64_t ub2: 61; /* packed tightly */ 731 + uint32_t ub7; 732 + uint32_t sb4; 733 + uint32_t sb20; 734 + uint32_t u32; 735 + uint32_t s32; 736 + } __attribute__((packed)) ;
+63
tools/testing/selftests/bpf/progs/test_core_reloc_bitfields_direct.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (c) 2019 Facebook 3 + 4 + #include <linux/bpf.h> 5 + #include <stdint.h> 6 + #include "bpf_helpers.h" 7 + #include "bpf_core_read.h" 8 + 9 + char _license[] SEC("license") = "GPL"; 10 + 11 + static volatile struct data { 12 + char in[256]; 13 + char out[256]; 14 + } data; 15 + 16 + struct core_reloc_bitfields { 17 + /* unsigned bitfields */ 18 + uint8_t ub1: 1; 19 + uint8_t ub2: 2; 20 + uint32_t ub7: 7; 21 + /* signed bitfields */ 22 + int8_t sb4: 4; 23 + int32_t sb20: 20; 24 + /* non-bitfields */ 25 + uint32_t u32; 26 + int32_t s32; 27 + }; 28 + 29 + /* bitfield read results, all as plain integers */ 30 + struct core_reloc_bitfields_output { 31 + int64_t ub1; 32 + int64_t ub2; 33 + int64_t ub7; 34 + int64_t sb4; 35 + int64_t sb20; 36 + int64_t u32; 37 + int64_t s32; 38 + }; 39 + 40 + struct pt_regs; 41 + 42 + struct trace_sys_enter { 43 + struct pt_regs *regs; 44 + long id; 45 + }; 46 + 47 + SEC("tp_btf/sys_enter") 48 + int test_core_bitfields_direct(void *ctx) 49 + { 50 + struct core_reloc_bitfields *in = (void *)&data.in; 51 + struct core_reloc_bitfields_output *out = (void *)&data.out; 52 + 53 + out->ub1 = BPF_CORE_READ_BITFIELD(in, ub1); 54 + out->ub2 = BPF_CORE_READ_BITFIELD(in, ub2); 55 + out->ub7 = BPF_CORE_READ_BITFIELD(in, ub7); 56 + out->sb4 = BPF_CORE_READ_BITFIELD(in, sb4); 57 + out->sb20 = BPF_CORE_READ_BITFIELD(in, sb20); 58 + out->u32 = BPF_CORE_READ_BITFIELD(in, u32); 59 + out->s32 = BPF_CORE_READ_BITFIELD(in, s32); 60 + 61 + return 0; 62 + } 63 +
+62
tools/testing/selftests/bpf/progs/test_core_reloc_bitfields_probed.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (c) 2019 Facebook 3 + 4 + #include <linux/bpf.h> 5 + #include <stdint.h> 6 + #include "bpf_helpers.h" 7 + #include "bpf_core_read.h" 8 + 9 + char _license[] SEC("license") = "GPL"; 10 + 11 + static volatile struct data { 12 + char in[256]; 13 + char out[256]; 14 + } data; 15 + 16 + struct core_reloc_bitfields { 17 + /* unsigned bitfields */ 18 + uint8_t ub1: 1; 19 + uint8_t ub2: 2; 20 + uint32_t ub7: 7; 21 + /* signed bitfields */ 22 + int8_t sb4: 4; 23 + int32_t sb20: 20; 24 + /* non-bitfields */ 25 + uint32_t u32; 26 + int32_t s32; 27 + }; 28 + 29 + /* bitfield read results, all as plain integers */ 30 + struct core_reloc_bitfields_output { 31 + int64_t ub1; 32 + int64_t ub2; 33 + int64_t ub7; 34 + int64_t sb4; 35 + int64_t sb20; 36 + int64_t u32; 37 + int64_t s32; 38 + }; 39 + 40 + #define TRANSFER_BITFIELD(in, out, field) \ 41 + if (BPF_CORE_READ_BITFIELD_PROBED(in, field, &res)) \ 42 + return 1; \ 43 + out->field = res 44 + 45 + SEC("raw_tracepoint/sys_enter") 46 + int test_core_bitfields(void *ctx) 47 + { 48 + struct core_reloc_bitfields *in = (void *)&data.in; 49 + struct core_reloc_bitfields_output *out = (void *)&data.out; 50 + uint64_t res; 51 + 52 + TRANSFER_BITFIELD(in, out, ub1); 53 + TRANSFER_BITFIELD(in, out, ub2); 54 + TRANSFER_BITFIELD(in, out, ub7); 55 + TRANSFER_BITFIELD(in, out, sb4); 56 + TRANSFER_BITFIELD(in, out, sb20); 57 + TRANSFER_BITFIELD(in, out, u32); 58 + TRANSFER_BITFIELD(in, out, s32); 59 + 60 + return 0; 61 + } 62 +