All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH bpf v4 0/2] bpf: Fix unsound scalar forking for BPF_OR
@ 2026-03-14  2:15 Daniel Wade
  2026-03-14  2:15 ` [PATCH bpf v4 1/2] bpf: Fix unsound scalar forking in maybe_fork_scalars() " Daniel Wade
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Daniel Wade @ 2026-03-14  2:15 UTC (permalink / raw)
  To: bpf; +Cc: daniel, eddyz87, ameryhung, ast, danjwade95

maybe_fork_scalars() unconditionally sets the pushed path dst register
to 0 for both BPF_AND and BPF_OR.  For AND this is correct (0 & K == 0),
but for OR it is wrong (0 | K == K, not 0).  This causes the verifier to
track an incorrect value on the pushed path, leading to a verifier/runtime
divergence that allows out-of-bounds map value access.

v4: Use block comment style for multi-line comments in selftests (Amery Hung)
    Add Reviewed-by/Acked-by tags
v3: Use single-line comment style in selftests (Alexei Starovoitov)
v2: Use push_stack(env, env->insn_idx, ...) to re-execute the insn
    on the pushed path (Eduard Zingerman)

Daniel Wade (2):
  bpf: Fix unsound scalar forking in maybe_fork_scalars() for BPF_OR
  selftests/bpf: Add tests for maybe_fork_scalars() OR vs AND handling

 kernel/bpf/verifier.c                         |  2 +-
 .../selftests/bpf/progs/verifier_bounds.c     | 94 +++++++++++++++++++
 2 files changed, 95 insertions(+), 1 deletion(-)

-- 
2.43.0


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

* [PATCH bpf v4 1/2] bpf: Fix unsound scalar forking in maybe_fork_scalars() for BPF_OR
  2026-03-14  2:15 [PATCH bpf v4 0/2] bpf: Fix unsound scalar forking for BPF_OR Daniel Wade
@ 2026-03-14  2:15 ` Daniel Wade
  2026-03-14  2:15 ` [PATCH bpf v4 2/2] selftests/bpf: Add tests for maybe_fork_scalars() OR vs AND handling Daniel Wade
  2026-03-21 20:20 ` [PATCH bpf v4 0/2] bpf: Fix unsound scalar forking for BPF_OR patchwork-bot+netdevbpf
  2 siblings, 0 replies; 4+ messages in thread
From: Daniel Wade @ 2026-03-14  2:15 UTC (permalink / raw)
  To: bpf; +Cc: daniel, eddyz87, ameryhung, ast, danjwade95

maybe_fork_scalars() is called for both BPF_AND and BPF_OR when the
source operand is a constant.  When dst has signed range [-1, 0], it
forks the verifier state: the pushed path gets dst = 0, the current
path gets dst = -1.

For BPF_AND this is correct: 0 & K == 0.
For BPF_OR this is wrong:    0 | K == K, not 0.

The pushed path therefore tracks dst as 0 when the runtime value is K,
producing an exploitable verifier/runtime divergence that allows
out-of-bounds map access.

Fix this by passing env->insn_idx (instead of env->insn_idx + 1) to
push_stack(), so the pushed path re-executes the ALU instruction with
dst = 0 and naturally computes the correct result for any opcode.

Fixes: bffacdb80b93 ("bpf: Recognize special arithmetic shift in the verifier")
Signed-off-by: Daniel Wade <danjwade95@gmail.com>
Reviewed-by: Amery Hung <ameryhung@gmail.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
---
 kernel/bpf/verifier.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index a9e2380327..68fa308520 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -14206,7 +14206,7 @@ static int maybe_fork_scalars(struct bpf_verifier_env *env, struct bpf_insn *ins
 	else
 		return 0;
 
-	branch = push_stack(env, env->insn_idx + 1, env->insn_idx, false);
+	branch = push_stack(env, env->insn_idx, env->insn_idx, false);
 	if (IS_ERR(branch))
 		return PTR_ERR(branch);
 
-- 
2.43.0


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

* [PATCH bpf v4 2/2] selftests/bpf: Add tests for maybe_fork_scalars() OR vs AND handling
  2026-03-14  2:15 [PATCH bpf v4 0/2] bpf: Fix unsound scalar forking for BPF_OR Daniel Wade
  2026-03-14  2:15 ` [PATCH bpf v4 1/2] bpf: Fix unsound scalar forking in maybe_fork_scalars() " Daniel Wade
@ 2026-03-14  2:15 ` Daniel Wade
  2026-03-21 20:20 ` [PATCH bpf v4 0/2] bpf: Fix unsound scalar forking for BPF_OR patchwork-bot+netdevbpf
  2 siblings, 0 replies; 4+ messages in thread
From: Daniel Wade @ 2026-03-14  2:15 UTC (permalink / raw)
  To: bpf; +Cc: daniel, eddyz87, ameryhung, ast, danjwade95

Add three test cases to verifier_bounds.c to verify that
maybe_fork_scalars() correctly tracks register values for BPF_OR
operations with constant source operands:

1. or_scalar_fork_rejects_oob: After ARSH 63 + OR 8, the pushed
   path should have dst = 8. With value_size = 8, accessing
   map_value + 8 is out of bounds and must be rejected.

2. and_scalar_fork_still_works: Regression test ensuring AND
   forking continues to work. ARSH 63 + AND 4 produces pushed
   dst = 0 and current dst = 4, both within value_size = 8.

3. or_scalar_fork_allows_inbounds: After ARSH 63 + OR 4, the
   pushed path has dst = 4, which is within value_size = 8
   and should be accepted.

These tests exercise the fix in the previous patch, which makes the
pushed path re-execute the ALU instruction so it computes the correct
result for BPF_OR.

Signed-off-by: Daniel Wade <danjwade95@gmail.com>
Reviewed-by: Amery Hung <ameryhung@gmail.com>
Acked-by: Eduard Zingerman <eddyz87@gmail.com>
---
 .../selftests/bpf/progs/verifier_bounds.c     | 94 +++++++++++++++++++
 1 file changed, 94 insertions(+)

diff --git a/tools/testing/selftests/bpf/progs/verifier_bounds.c b/tools/testing/selftests/bpf/progs/verifier_bounds.c
index a0bb7fb40e..d8fe6f98e7 100644
--- a/tools/testing/selftests/bpf/progs/verifier_bounds.c
+++ b/tools/testing/selftests/bpf/progs/verifier_bounds.c
@@ -1200,4 +1200,98 @@ l0_%=:	r0 = 0;						\
 	: __clobber_all);
 }
 
+SEC("socket")
+__description("maybe_fork_scalars: OR with constant rejects OOB")
+__failure __msg("invalid access to map value")
+__naked void or_scalar_fork_rejects_oob(void)
+{
+	asm volatile ("					\
+	r1 = 0;						\
+	*(u64*)(r10 - 8) = r1;				\
+	r2 = r10;					\
+	r2 += -8;					\
+	r1 = %[map_hash_8b] ll;				\
+	call %[bpf_map_lookup_elem];			\
+	if r0 == 0 goto l0_%=;				\
+	r9 = r0;					\
+	r6 = *(u64*)(r9 + 0);				\
+	r6 s>>= 63;					\
+	r6 |= 8;					\
+	/* r6 is -1 (current) or 8 (pushed) */		\
+	if r6 s< 0 goto l0_%=;				\
+	/* pushed path: r6 = 8, OOB for value_size=8 */	\
+	r9 += r6;					\
+	r0 = *(u8*)(r9 + 0);				\
+l0_%=:	r0 = 0;						\
+	exit;						\
+"	:
+	: __imm(bpf_map_lookup_elem),
+	  __imm_addr(map_hash_8b)
+	: __clobber_all);
+}
+
+SEC("socket")
+__description("maybe_fork_scalars: AND with constant still works")
+__success __retval(0)
+__naked void and_scalar_fork_still_works(void)
+{
+	asm volatile ("					\
+	r1 = 0;						\
+	*(u64*)(r10 - 8) = r1;				\
+	r2 = r10;					\
+	r2 += -8;					\
+	r1 = %[map_hash_8b] ll;				\
+	call %[bpf_map_lookup_elem];			\
+	if r0 == 0 goto l0_%=;				\
+	r9 = r0;					\
+	r6 = *(u64*)(r9 + 0);				\
+	r6 s>>= 63;					\
+	r6 &= 4;					\
+	/*						\
+	 * r6 is 0 (pushed, 0&4==0) or 4 (current)	\
+	 * both within value_size=8			\
+	 */						\
+	if r6 s< 0 goto l0_%=;				\
+	r9 += r6;					\
+	r0 = *(u8*)(r9 + 0);				\
+l0_%=:	r0 = 0;						\
+	exit;						\
+"	:
+	: __imm(bpf_map_lookup_elem),
+	  __imm_addr(map_hash_8b)
+	: __clobber_all);
+}
+
+SEC("socket")
+__description("maybe_fork_scalars: OR with constant allows in-bounds")
+__success __retval(0)
+__naked void or_scalar_fork_allows_inbounds(void)
+{
+	asm volatile ("					\
+	r1 = 0;						\
+	*(u64*)(r10 - 8) = r1;				\
+	r2 = r10;					\
+	r2 += -8;					\
+	r1 = %[map_hash_8b] ll;				\
+	call %[bpf_map_lookup_elem];			\
+	if r0 == 0 goto l0_%=;				\
+	r9 = r0;					\
+	r6 = *(u64*)(r9 + 0);				\
+	r6 s>>= 63;					\
+	r6 |= 4;					\
+	/*						\
+	 * r6 is -1 (current) or 4 (pushed)		\
+	 * pushed path: r6 = 4, within value_size=8	\
+	 */						\
+	if r6 s< 0 goto l0_%=;				\
+	r9 += r6;					\
+	r0 = *(u8*)(r9 + 0);				\
+l0_%=:	r0 = 0;						\
+	exit;						\
+"	:
+	: __imm(bpf_map_lookup_elem),
+	  __imm_addr(map_hash_8b)
+	: __clobber_all);
+}
+
 char _license[] SEC("license") = "GPL";
-- 
2.43.0


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

* Re: [PATCH bpf v4 0/2] bpf: Fix unsound scalar forking for BPF_OR
  2026-03-14  2:15 [PATCH bpf v4 0/2] bpf: Fix unsound scalar forking for BPF_OR Daniel Wade
  2026-03-14  2:15 ` [PATCH bpf v4 1/2] bpf: Fix unsound scalar forking in maybe_fork_scalars() " Daniel Wade
  2026-03-14  2:15 ` [PATCH bpf v4 2/2] selftests/bpf: Add tests for maybe_fork_scalars() OR vs AND handling Daniel Wade
@ 2026-03-21 20:20 ` patchwork-bot+netdevbpf
  2 siblings, 0 replies; 4+ messages in thread
From: patchwork-bot+netdevbpf @ 2026-03-21 20:20 UTC (permalink / raw)
  To: Daniel Wade; +Cc: bpf, daniel, eddyz87, ameryhung, ast

Hello:

This series was applied to bpf/bpf.git (master)
by Alexei Starovoitov <ast@kernel.org>:

On Sat, 14 Mar 2026 13:15:19 +1100 you wrote:
> maybe_fork_scalars() unconditionally sets the pushed path dst register
> to 0 for both BPF_AND and BPF_OR.  For AND this is correct (0 & K == 0),
> but for OR it is wrong (0 | K == K, not 0).  This causes the verifier to
> track an incorrect value on the pushed path, leading to a verifier/runtime
> divergence that allows out-of-bounds map value access.
> 
> v4: Use block comment style for multi-line comments in selftests (Amery Hung)
>     Add Reviewed-by/Acked-by tags
> v3: Use single-line comment style in selftests (Alexei Starovoitov)
> v2: Use push_stack(env, env->insn_idx, ...) to re-execute the insn
>     on the pushed path (Eduard Zingerman)
> 
> [...]

Here is the summary with links:
  - [bpf,v4,1/2] bpf: Fix unsound scalar forking in maybe_fork_scalars() for BPF_OR
    https://git.kernel.org/bpf/bpf/c/c845894ebd6f
  - [bpf,v4,2/2] selftests/bpf: Add tests for maybe_fork_scalars() OR vs AND handling
    https://git.kernel.org/bpf/bpf/c/0ad1734cc559

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



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

end of thread, other threads:[~2026-03-21 20:20 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-14  2:15 [PATCH bpf v4 0/2] bpf: Fix unsound scalar forking for BPF_OR Daniel Wade
2026-03-14  2:15 ` [PATCH bpf v4 1/2] bpf: Fix unsound scalar forking in maybe_fork_scalars() " Daniel Wade
2026-03-14  2:15 ` [PATCH bpf v4 2/2] selftests/bpf: Add tests for maybe_fork_scalars() OR vs AND handling Daniel Wade
2026-03-21 20:20 ` [PATCH bpf v4 0/2] bpf: Fix unsound scalar forking for BPF_OR patchwork-bot+netdevbpf

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.