selftests/bpf: Check that JMP32 pointer vs zero jumps are not predicted

Add jmp32_ptr_vs_zero_jne: the fall-through of the 32-bit compare, which
the verifier used to skip, contains an out of bounds map value access,
hence w/o the previous patch the program is accepted. See previous patch
for detailed description.

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-6-eddyz87@gmail.com
Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
This commit is contained in:
Eduard Zingerman 2026-09-04 01:33:23 -07:00 committed by Kumar Kartikeya Dwivedi
parent e51179a4e0
commit 836b2fe544
No known key found for this signature in database
GPG Key ID: 472D377B63542F83

View File

@ -391,6 +391,33 @@ __naked void bounded_offset_infers_map_value_non_null(void)
: __clobber_all);
}
/*
* The low 32 bits of a map value pointer may be zero, hence a 32-bit
* compare with zero cannot be predicted from the pointer being non-NULL
* and both successors of such a jump have to be verified.
*/
SEC("socket")
__failure __msg("invalid access to map value, value_size=4 off=32 size=4")
__naked void jmp32_ptr_vs_zero_jne(void)
{
asm volatile (" \
/* r0 = bpf_map_lookup_elem(map_hash, &key); */ \
*(u64 *)(r10 - 8) = 0; \
r1 = %[map_hash] ll; \
r2 = r10; \
r2 += -8; \
call %[bpf_map_lookup_elem]; \
if r0 == 0 goto 1f; \
if w0 != 0 goto 1f; \
r0 = *(u32 *)(r0 + 32); \
1: r0 = 0; \
exit; \
" :
: __imm(bpf_map_lookup_elem),
__imm_addr(map_hash)
: __clobber_all);
}
void kfunc_root(void)
{
bpf_rdonly_cast(0, 0);