selftests/bpf: a demo for check_cond_jmp_op() non-null inference bug

A comparison between PTR_TO_MEM | MEM_RDONLY | PTR_UNTRUSTED and
PTR_TO_MAP_VALUE_OR_NULL should not infer that map pointer is not null.
A bug in check_cond_jmp_op() made such inference possible.

Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Link: https://lore.kernel.org/r/20260826-bug-029-bad-non-null-inference-v2-2-136789ace9e9@localhost
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
Eduard Zingerman 2026-08-26 11:18:45 -07:00 committed by Alexei Starovoitov
parent d3ef6c097b
commit ce6dcd0aed

View File

@ -3,7 +3,9 @@
#include <linux/bpf.h>
#include <bpf/bpf_helpers.h>
#include <stdbool.h>
#include "bpf_misc.h"
#include "bpf_kfuncs.h"
struct {
__uint(type, BPF_MAP_TYPE_XSKMAP);
@ -12,6 +14,13 @@ struct {
__type(value, int);
} map_xskmap SEC(".maps");
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__uint(max_entries, 1);
__type(key, int);
__type(value, int);
} map_hash SEC(".maps");
/* This is equivalent to the following program:
*
* r6 = skb->sk;
@ -264,4 +273,47 @@ __naked void jne_reg_reg_null_check(void)
: __clobber_all);
}
/*
* A comparison between PTR_TO_MEM | MEM_RDONLY | PTR_UNTRUSTED and
* PTR_TO_MAP_VALUE_OR_NULL should not infer that map pointer is not null.
* A bug in check_cond_jmp_op() made such inference possible.
*/
SEC("raw_tp")
__failure
__msg("error: invalid dereference of R0 (a nullable map value pointer)")
__msg(">>> 11 | (61) r0 = *(u32 *)(r0 +0)")
__naked void untrusted_mem_does_not_infer_map_value_non_null(void)
{
asm volatile (" \
/* r6 = bpf_rdonly_cast(0, 0); */ \
r1 = 0; \
r2 = 0; \
call %[bpf_rdonly_cast]; \
r6 = r0; \
/* 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]; \
/* \
* buggy verifier assumed that r6 can't be null \
* and marked r0 non-null as well. \
*/ \
if r6 != r0 goto 1f; \
r0 = *(u32 *)(r0 + 0); \
1: r0 = 0; \
exit; \
" :
: __imm(bpf_rdonly_cast),
__imm(bpf_map_lookup_elem),
__imm_addr(map_hash)
: __clobber_all);
}
void kfunc_root(void)
{
bpf_rdonly_cast(0, 0);
}
char _license[] SEC("license") = "GPL";