[PATCH bpf-next v2 1/4] selftests/bpf: map_kptr: expect BPF_ST reject msg on cpuv4 toolchains
Vineet Gupta <[email protected]>
| Newsgroups | org.kernel.vger.bpf |
|---|---|
| Message-ID | <[email protected]> |
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]>
---
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;
--
2.53.0-Meta