selftests/bpf: No non-NULL inference from unbounded offset pointers

Check that a comparison against a pointer whose offset is not bounded
from above does not make the verifier infer that a nullable pointer is
not NULL, and that a bounded offset still does. W/o the previous patch
the first test is accepted.

Reported-by: Nicholas Carlini <npc@anthropic.com>
Suggested-by: Nicholas Carlini <npc@anthropic.com>
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/bpf/20260904083325.2083493-2-eddyz87@gmail.com
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
This commit is contained in:
Eduard Zingerman 2026-09-04 01:33:19 -07:00 committed by Kumar Kartikeya Dwivedi
parent 67b529f521
commit 6752b90ccf
No known key found for this signature in database
GPG Key ID: 472D377B63542F83

View File

@ -311,6 +311,86 @@ __naked void untrusted_mem_does_not_infer_map_value_non_null(void)
: __clobber_all);
}
/*
* A pointer with an offset that is not bounded from above may be null at
* runtime, hence it is not a witness for the pointer it is compared with.
*/
SEC("socket")
__failure
__msg("error: invalid dereference of R7 (a nullable map value pointer)")
__naked void unbounded_offset_does_not_infer_map_value_non_null(void)
{
asm volatile (" \
/* r6 = bpf_map_lookup_elem(map_hash, &0); */ \
*(u64 *)(r10 - 8) = 0; \
r1 = %[map_hash] ll; \
r2 = r10; \
r2 += -8; \
call %[bpf_map_lookup_elem]; \
if r0 == 0 goto 1f; \
r6 = r0; \
/* r7 = bpf_map_lookup_elem(map_hash, &1); */ \
*(u64 *)(r10 - 8) = 1; \
r1 = %[map_hash] ll; \
r2 = r10; \
r2 += -8; \
call %[bpf_map_lookup_elem]; \
r7 = r0; \
/* pointer - pointer is an unknown scalar */ \
r8 = r7; \
r8 -= r6; \
/* r8 is in [0, S64_MAX] */ \
r8 <<= 1; \
r8 >>= 1; \
/* r6 may wrap to zero at runtime */ \
r6 += r8; \
if r7 != r6 goto 1f; \
r0 = *(u8 *)(r7 + 0); \
1: r0 = 0; \
exit; \
" :
: __imm(bpf_map_lookup_elem),
__imm_addr(map_hash)
: __clobber_all);
}
/* Same, but the offset is bounded, so the inference is still done. */
SEC("socket")
__success
__naked void bounded_offset_infers_map_value_non_null(void)
{
asm volatile (" \
/* r6 = bpf_map_lookup_elem(map_hash, &0); */ \
*(u64 *)(r10 - 8) = 0; \
r1 = %[map_hash] ll; \
r2 = r10; \
r2 += -8; \
call %[bpf_map_lookup_elem]; \
if r0 == 0 goto 1f; \
r6 = r0; \
/* r7 = bpf_map_lookup_elem(map_hash, &1); */ \
*(u64 *)(r10 - 8) = 1; \
r1 = %[map_hash] ll; \
r2 = r10; \
r2 += -8; \
call %[bpf_map_lookup_elem]; \
r7 = r0; \
/* pointer - pointer is an unknown scalar */ \
r8 = r7; \
r8 -= r6; \
/* r8 is in [0, 3] */ \
r8 &= 3; \
r6 += r8; \
if r7 != r6 goto 1f; \
r0 = *(u8 *)(r7 + 0); \
1: r0 = 0; \
exit; \
" :
: __imm(bpf_map_lookup_elem),
__imm_addr(map_hash)
: __clobber_all);
}
void kfunc_root(void)
{
bpf_rdonly_cast(0, 0);