Re: [PATCH bpf-next v2 1/4] selftests/bpf: map_kptr: expect BPF_ST reject msg on cpuv4 toolchains
Yonghong Song <[email protected]>
| Newsgroups | org.kernel.vger.bpf |
|---|---|
| Message-ID | <[email protected]> |
On 8/7/26 1:44 PM, Vineet Gupta wrote:
> 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 <[email protected]>
Acked-by: Yonghong Song <[email protected]>
> ---
> 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;