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

selftests/bpf: add test for LDX/STX/ST relocations over array field

Add a simple repro for the issue of miscalculating LDX/STX/ST CO-RE
relocation size adjustment when the CO-RE relocation target type is an
ARRAY.

We need to make sure that compiler generates LDX/STX/ST instruction with
CO-RE relocation against entire ARRAY type, not ARRAY's element. With
the code pattern in selftest, we get this:

59: 61 71 00 00 00 00 00 00 w1 = *(u32 *)(r7 + 0x0)
00000000000001d8: CO-RE <byte_off> [5] struct core_reloc_arrays::a (0:0)

Where offset of `int a[5]` is embedded (through CO-RE relocation) into memory
load instruction itself.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/r/20250207014809.1573841-2-andrii@kernel.org
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

authored by

Andrii Nakryiko and committed by
Alexei Starovoitov
4eb93fea 06096d19

+22 -2
+4 -2
tools/testing/selftests/bpf/prog_tests/core_reloc.c
··· 85 85 #define NESTING_ERR_CASE(name) { \ 86 86 NESTING_CASE_COMMON(name), \ 87 87 .fails = true, \ 88 - .run_btfgen_fails = true, \ 88 + .run_btfgen_fails = true, \ 89 89 } 90 90 91 91 #define ARRAYS_DATA(struct_name) STRUCT_TO_CHAR_PTR(struct_name) { \ 92 - .a = { [2] = 1 }, \ 92 + .a = { [2] = 1, [3] = 11 }, \ 93 93 .b = { [1] = { [2] = { [3] = 2 } } }, \ 94 94 .c = { [1] = { .c = 3 } }, \ 95 95 .d = { [0] = { [0] = { .d = 4 } } }, \ ··· 108 108 .input_len = sizeof(struct core_reloc_##name), \ 109 109 .output = STRUCT_TO_CHAR_PTR(core_reloc_arrays_output) { \ 110 110 .a2 = 1, \ 111 + .a3 = 12, \ 111 112 .b123 = 2, \ 112 113 .c1c = 3, \ 113 114 .d00d = 4, \ ··· 603 602 ARRAYS_ERR_CASE(arrays___err_non_array), 604 603 ARRAYS_ERR_CASE(arrays___err_wrong_val_type), 605 604 ARRAYS_ERR_CASE(arrays___err_bad_zero_sz_arr), 605 + ARRAYS_ERR_CASE(arrays___err_bad_signed_arr_elem_sz), 606 606 607 607 /* enum/ptr/int handling scenarios */ 608 608 PRIMITIVES_CASE(primitives),
+3
tools/testing/selftests/bpf/progs/btf__core_reloc_arrays___err_bad_signed_arr_elem_sz.c
··· 1 + #include "core_reloc_types.h" 2 + 3 + void f(struct core_reloc_arrays___err_bad_signed_arr_elem_sz x) {}
+10
tools/testing/selftests/bpf/progs/core_reloc_types.h
··· 347 347 */ 348 348 struct core_reloc_arrays_output { 349 349 int a2; 350 + int a3; 350 351 char b123; 351 352 int c1c; 352 353 int d00d; ··· 454 453 char b[2][3][4]; 455 454 struct core_reloc_arrays_substruct c[3]; 456 455 struct core_reloc_arrays_substruct d[1][2]; 456 + }; 457 + 458 + struct core_reloc_arrays___err_bad_signed_arr_elem_sz { 459 + /* int -> short (signed!): not supported case */ 460 + short a[5]; 461 + char b[2][3][4]; 462 + struct core_reloc_arrays_substruct c[3]; 463 + struct core_reloc_arrays_substruct d[1][2]; 464 + struct core_reloc_arrays_substruct f[][2]; 457 465 }; 458 466 459 467 /*
+5
tools/testing/selftests/bpf/progs/test_core_reloc_arrays.c
··· 15 15 16 16 struct core_reloc_arrays_output { 17 17 int a2; 18 + int a3; 18 19 char b123; 19 20 int c1c; 20 21 int d00d; ··· 42 41 { 43 42 struct core_reloc_arrays *in = (void *)&data.in; 44 43 struct core_reloc_arrays_output *out = (void *)&data.out; 44 + int *a; 45 45 46 46 if (CORE_READ(&out->a2, &in->a[2])) 47 47 return 1; ··· 54 52 return 1; 55 53 if (CORE_READ(&out->f01c, &in->f[0][1].c)) 56 54 return 1; 55 + 56 + a = __builtin_preserve_access_index(({ in->a; })); 57 + out->a3 = a[0] + a[1] + a[2] + a[3]; 57 58 58 59 return 0; 59 60 }