BPF List
 help / color / mirror / Atom feed
* [PATCH bpf 1/8] bpf: don't infer non-NULL from a pointer with an unbounded offset
@ 2026-09-04  8:33 Eduard Zingerman
  2026-09-04  8:33 ` [PATCH bpf 2/8] selftests/bpf: no non-NULL inference from unbounded offset pointers Eduard Zingerman
                   ` (7 more replies)
  0 siblings, 8 replies; 11+ messages in thread
From: Eduard Zingerman @ 2026-09-04  8:33 UTC (permalink / raw)
  To: bpf, ast, andrii
  Cc: daniel, martin.lau, kernel-team, yonghong.song, eddyz87, memxor,
	npc

reg_not_null() decides that a register holds a non-NULL value by
looking at its type alone. For pointer types that allow arithmetic the
type only guarantees a non-NULL base, in case of an unbound offset
the runtime offset value might still add up to NULL.
Consider the followng program:

  r6 = bpf_map_lookup_elem(map, &0);  /* present */
  if (r6 == 0) return 0;
  r7 = bpf_map_lookup_elem(map, &1);  /* absent, NULL at runtime */
  r8 = r7;
  r8 -= r6;     /* pointer - pointer: unknown scalar, -r6 */
  r8 <<= 1;
  r8 >>= 1;     /* any non-negative offset is accepted by */
                /* check_reg_sane_offset_ptr() */
  r6 += r8;     /* verifier: map value;    runtime: zero  */
  if (r7 != r6) return 0;
  *(u8 *)(r7 + 0);  /* r7 is inferred non-NULL, both are zero */

At runtime both registers are zero, the comparison is true and the
load faults with NULL pointer dereference.

Require the offset to be within +-BPF_MAX_VAR_OFF in reg_not_null().

Fixes: cac616db39c2 ("bpf: Verifier track null pointer branch_taken with JNE and JEQ")
Reported-by: Nicholas Carlini <npc@anthropic.com>
Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
---
 kernel/bpf/verifier.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index e64035683795..e53619e2210e 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -352,6 +352,13 @@ static bool reg_not_null(struct bpf_verifier_env *env, const struct bpf_reg_stat
 	if (type_may_be_null(type))
 		return false;
 
+	/*
+	 * The types below guarantee a non-NULL base, an unbounded offset can
+	 * still wrap base + offset to zero.
+	 */
+	if (reg_smin(reg) <= -BPF_MAX_VAR_OFF || reg_smax(reg) >= BPF_MAX_VAR_OFF)
+		return false;
+
 	type = base_type(type);
 	return type == PTR_TO_SOCKET ||
 		type == PTR_TO_TCP_SOCK ||
-- 
2.55.0


^ permalink raw reply related	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2026-09-04 11:11 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-04  8:33 [PATCH bpf 1/8] bpf: don't infer non-NULL from a pointer with an unbounded offset Eduard Zingerman
2026-09-04  8:33 ` [PATCH bpf 2/8] selftests/bpf: no non-NULL inference from unbounded offset pointers Eduard Zingerman
2026-09-04  8:33 ` [PATCH bpf 3/8] bpf: don't resurrect a scalar id dropped by collect_linked_regs() Eduard Zingerman
2026-09-04  8:33 ` [PATCH bpf 4/8] selftests/bpf: check the linked regs cap for the compared register Eduard Zingerman
2026-09-04  8:33 ` [PATCH bpf 5/8] bpf: don't predict JMP32 pointer vs zero comparisons Eduard Zingerman
2026-09-04  8:33 ` [PATCH bpf 6/8] selftests/bpf: check that JMP32 pointer vs zero jumps are not predicted Eduard Zingerman
2026-09-04  8:33 ` [PATCH bpf 7/8] bpf: mark the zero register precise for a register-form NULL check Eduard Zingerman
2026-09-04  8:57   ` sashiko-bot
2026-09-04 11:11     ` Kumar Kartikeya Dwivedi
2026-09-04  8:33 ` [PATCH bpf 8/8] selftests/bpf: no non-NULL inference from an imprecise zero register Eduard Zingerman
2026-09-04 11:10 ` [PATCH bpf 1/8] bpf: don't infer non-NULL from a pointer with an unbounded offset patchwork-bot+netdevbpf

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox