From e28b4922679ed56062ac0dcd77f393cbafa90070 Mon Sep 17 00:00:00 2001 From: Vineet Gupta Date: Fri, 7 Aug 2026 13:44:31 -0700 Subject: [PATCH] selftests/bpf: map_kptr: Expect BPF_ST reject msg on cpuv4 toolchains reject_scalar_store_to_kptr stores a scalar constant to a kptr field: *(volatile u64 *)&v->unref_ptr = 0xBADC0DE; Compilers generate one of two encodings for that: 1. Materialize the constant into a register and emit BPF_STX: r1 = 0xbadc0de *(u64 *)(r0 + 0x8) = r1 2. Or fold it into a single BPF_ST (store immediate): *(u64 *)(r0 + 0x8) = 0xbadc0de These go through different rejection paths and output different messages. - BPF_STX goes through map_kptr_match_type(), which prints "invalid kptr access, R...". - BPF_ST only gets the immediate check printing "BPF_ST imm must be 0 when storing to kptr" The test only expects the BPF_STX message, so it fails on a toolchain that folds the constant - bpf-gcc, and clang -mcpu=v4: 7: (7a) *(u64 *)(r0 +8) = 195936478 BPF_ST imm must be 0 when storing to kptr at off=8 ... EXPECTED SUBSTR: 'invalid kptr access, R' Pick the expected message with __BPF_FEATURE_ST, which clang and bpf-gcc both define exactly when BPF_ST codegen is available - cpuv4 for clang, and by default for bpf-gcc, whose default cpu is v4. bpf-gcc, before: #229/20 map_kptr/reject_scalar_store_to_kptr:FAIL bpf-gcc, after : #229/20 map_kptr/reject_scalar_store_to_kptr:OK Two caveats worth noting: - On a BPF_ST toolchain the test now only exercises the imm != 0 check and never reaches map_kptr_match_type(), so the scalar-vs-PTR_TO_BTF_ID rejection the test is named for is only covered by the non-ST builds. The imm path itself is already covered compiler-independently by verifier/map_kptr.c ("map_kptr: BPF_ST imm != 0"). - __BPF_FEATURE_ST says the compiler *can* emit BPF_ST, not that it will. The encoding also depends on the optimization level: clang -mcpu=v4 -O0 still emits BPF_STX, which would send the #ifdef down the wrong branch and fail the test. Selftests always build BPF objects at -O2 so this does not bite today, but it is a latent failure mode if that changes. Signed-off-by: Vineet Gupta Signed-off-by: Daniel Borkmann Acked-by: Yonghong Song Link: https://lore.kernel.org/bpf/20260807204434.1036279-2-vineet.gupta@linux.dev --- tools/testing/selftests/bpf/progs/map_kptr_fail.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/testing/selftests/bpf/progs/map_kptr_fail.c b/tools/testing/selftests/bpf/progs/map_kptr_fail.c index f11848dfa78f..5e25ca806060 100644 --- a/tools/testing/selftests/bpf/progs/map_kptr_fail.c +++ b/tools/testing/selftests/bpf/progs/map_kptr_fail.c @@ -386,7 +386,16 @@ int kptr_xchg_possibly_null(struct __sk_buff *ctx) } SEC("?tc") +/* + * A compiler with BPF_ST folds the constant into a store-immediate, which the + * verifier rejects on a different path (and with a different message) than the + * BPF_STX form. + */ +#ifdef __BPF_FEATURE_ST +__failure __msg("BPF_ST imm must be 0 when storing to kptr at off=8") +#else __failure __msg("invalid kptr access, R") +#endif int reject_scalar_store_to_kptr(struct __sk_buff *ctx) { struct map_value *v;