The verifier translates accesses to some UAPI context and socket types into accesses to kernel structures. These accesses require an unmodified base and an immediate field offset. Leaving preserve_access_index (PAI) off does not stop the compiler from merging loads at different field offsets into one load through an adjusted pointer. The verifier rejects the resulting program. preserve_static_offset (PSO), available since Clang 18, preserves static field offsets in load and store instruction immediates. Apply it to these 13 types in vmlinux.h through a __bpf_static_offset macro. Eduard introduced PSO in Clang and proposed annotating BPF context types in 2023 [1]. His v3 RFC [2] left pt_regs annotations in architecture headers unresolved. However, since commit de6c7d99f898 ("bpf: Relax fixed offset check for PTR_TO_CTX"), program types without convert_ctx_access() accept fixed offsets from modified context pointers. pt_regs can now keep PAI, while PSO on bpf_perf_event_data covers its regs member. PSO creates no CO-RE relocations, so BPF_NO_PRESERVE_ACCESS_INDEX does not disable it. Clang 18 through 23 crash on __builtin_preserve_field_info over a PSO record, including bpf_core_field_*() and the CO-RE bitfield helpers. -D__bpf_static_offset= can disable PSO for affected programs. LLVM main has the fix [3]. [1]: https://lore.kernel.org/bpf/20231208000531.19179-1-eddyz87@gmail.com/ [2]: https://lore.kernel.org/bpf/20231220133411.22978-1-eddyz87@gmail.com/ [3]: https://github.com/llvm/llvm-project/pull/234280 Signed-off-by: Ihor Solodrai --- tools/bpf/bpftool/btf.c | 16 ++++++++++++++-- .../bpf/bpftool_btf_dump_sorted.expected | 8 ++++++++ .../bpf/bpftool_btf_dump_unsorted.expected | 8 ++++++++ 3 files changed, 30 insertions(+), 2 deletions(-) diff --git a/tools/bpf/bpftool/btf.c b/tools/bpf/bpftool/btf.c index d913723a691a..1329745c5854 100644 --- a/tools/bpf/bpftool/btf.c +++ b/tools/bpf/bpftool/btf.c @@ -1206,12 +1206,17 @@ static int btf_c_annotate_records(struct btf *btf) for (i = 1; i < cnt; i++) { const struct btf_type *t = btf__type_by_id(btf, i); + const char *attr; if (!btf_is_composite(t)) continue; - if (non_relocatable[i]) + if (!non_relocatable[i]) + attr = "__bpf_relocatable"; + else if (btf_c_needs_static_offset(btf, t)) + attr = "__bpf_static_offset"; + else continue; - err = btf__add_decl_attr(btf, "__bpf_relocatable", i, -1); + err = btf__add_decl_attr(btf, attr, i, -1); if (err < 0) goto out; } @@ -1264,6 +1269,13 @@ static int dump_btf_c(struct btf *btf, printf("#define __bpf_relocatable\n"); printf("#endif\n"); printf("#endif\n\n"); + printf("#ifndef __bpf_static_offset\n"); + printf("#if __has_attribute(preserve_static_offset)\n"); + printf("#define __bpf_static_offset __attribute__((preserve_static_offset))\n"); + printf("#else\n"); + printf("#define __bpf_static_offset\n"); + printf("#endif\n"); + printf("#endif\n\n"); printf("#ifndef __ksym\n"); printf("#define __ksym __attribute__((section(\".ksyms\")))\n"); printf("#endif\n\n"); diff --git a/tools/testing/selftests/bpf/bpftool_btf_dump_sorted.expected b/tools/testing/selftests/bpf/bpftool_btf_dump_sorted.expected index f2389e3dceed..b56b676b96a5 100644 --- a/tools/testing/selftests/bpf/bpftool_btf_dump_sorted.expected +++ b/tools/testing/selftests/bpf/bpftool_btf_dump_sorted.expected @@ -9,6 +9,14 @@ #endif #endif +#ifndef __bpf_static_offset +#if __has_attribute(preserve_static_offset) +#define __bpf_static_offset __attribute__((preserve_static_offset)) +#else +#define __bpf_static_offset +#endif +#endif + #ifndef __ksym #define __ksym __attribute__((section(".ksyms"))) #endif diff --git a/tools/testing/selftests/bpf/bpftool_btf_dump_unsorted.expected b/tools/testing/selftests/bpf/bpftool_btf_dump_unsorted.expected index 549045677a45..543db89078af 100644 --- a/tools/testing/selftests/bpf/bpftool_btf_dump_unsorted.expected +++ b/tools/testing/selftests/bpf/bpftool_btf_dump_unsorted.expected @@ -9,6 +9,14 @@ #endif #endif +#ifndef __bpf_static_offset +#if __has_attribute(preserve_static_offset) +#define __bpf_static_offset __attribute__((preserve_static_offset)) +#else +#define __bpf_static_offset +#endif +#endif + #ifndef __ksym #define __ksym __attribute__((section(".ksyms"))) #endif -- 2.56.0